Je fais un chronomètre où j'utilise SimpleDateFormat de Java pour convertir le nombre de millisecondes au format Nice "hh: mm: ss: SSS". Le problème est que le champ des heures contient toujours un nombre aléatoire. Voici le code que j'utilise:
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
String strDate = sdf.format(millis);
return strDate;
}
Si je retire la partie hh, alors cela fonctionne bien. Sinon, dans la partie hh, quelque chose d’aléatoire tel que "07" sera affiché, même si l’argument passé (nombre de millisecondes) est zéro.
Cependant, je ne connais pas grand chose de la classe SimpleDateFormat. Merci pour toute aide.
Voici comment je l'ai fait, en utilisant uniquement le JDK standard (cela fonctionnera dès Java 1.1 en remettant StringBuilder
à StringBuffer
):
static public String formatMillis(long val) {
StringBuilder buf=new StringBuilder(20);
String sgn="";
if(val<0) { sgn="-"; val=Math.abs(val); }
append(buf,sgn,0,(val/3600000)); val%=3600000;
append(buf,":",2,(val/ 60000)); val%= 60000;
append(buf,":",2,(val/ 1000)); val%= 1000;
append(buf,".",3,(val ));
return buf.toString();
}
/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
tgt.append(pfx);
if(dgt>1) {
int pad=(dgt-1);
for(long xa=val; xa>9 && pad>0; xa/=10) { pad--; }
for(int xa=0; xa<pad; xa++ ) { tgt.append('0'); }
}
tgt.append(val);
}
TimeUnit
.Ce que vous voulez utiliser, c'est Java.util.concurrent.TimeUnit pour travailler avec intervalles.
SimpleDateFormat
fait exactement ce que cela ressemble, il formate les instances de Java.util.Date
ou, dans votre cas, il convertit la valeur long
dans le contexte d'un Java.util.Date
et il ne sait pas quoi faire avec intervalles. apparemment travaillent avec.
Vous pouvez facilement le faire sans avoir à recourir à des bibliothèques externes telles que JodaTime.
import Java.util.concurrent.TimeUnit;
public class Main
{
private static String formatInterval(final long l)
{
final long hr = TimeUnit.MILLISECONDS.toHours(l);
final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
}
public static void main(final String[] args)
{
System.out.println(formatInterval(Long.parseLong(args[0])));
}
}
La sortie sera formatée comme ceci
13:00:00.000
Une méthode plus courte consiste à utiliser la classe DurationFormatUtils dans Apache Commons Lang :
public static String formatTime(long millis) {
return DurationFormatUtils.formatDuration(millis, "HH:mm:ss.S");
}
Pourquoi pas ça?
public static String GetFormattedInterval(final long ms) {
long millis = ms % 1000;
long x = ms / 1000;
long seconds = x % 60;
x /= 60;
long minutes = x % 60;
x /= 60;
long hours = x % 24;
return String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
}
C’est la première partie de mon travail sur Joda que j’ai réalisé et qui semblait plus fastidieux que le support JDK. Une implémentation de Joda pour le format demandé (faisant quelques hypothèses sur des champs nuls) est:
public void printDuration(long milliSecs)
{
PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroIfSupported()
.appendHours()
.appendSeparator(":")
.minimumPrintedDigits(2)
.appendMinutes()
.appendSeparator(":")
.appendSecondsWithMillis()
.toFormatter();
System.out.println(formatter.print(new Period(milliSecs)));
}
En examinant les autres réponses, je suis venu avec cette fonction ...
public static String formatInterval(final long interval, boolean millisecs )
{
final long hr = TimeUnit.MILLISECONDS.toHours(interval);
final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
if( millisecs ) {
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
} else {
return String.format("%02d:%02d:%02d", hr, min, sec );
}
}
Voici ce qui se passe. Lorsque vous passez en millisecondes, ce nombre est relatif au 1er janvier 1970. Lorsque vous passez 0, il prend cette date et la convertit dans votre fuseau horaire local. Si vous êtes en heure centrale, il est 19h. Si vous exécutez cela, alors tout est logique.
new SimpleDateFormat().format(0) => 12/31/69 7:00 PM
Edit, je pense que ce que vous voulez faire, c'est avoir du temps écoulé. Pour cela, je recommande d'utiliser JodaTime qui le fait déjà plutôt bien. Vous faites quelque chose comme
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours()
.appendSuffix(" hour", " hours")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" minute", " minutes")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" second", " seconds")
.toFormatter();
String formattedText = formatter.print(new Period(elapsedMilliSeconds));
Le format s'effectue en fonction de votre fuseau horaire local. Par conséquent, si vous passez 0, il suppose 0 GMT et le convertit dans votre fuseau horaire local.
Celui-ci fonctionne réellement, mais il semble que je peaufine l'intention de la méthode :-).
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
String strDate = sdf.format(millis - 3600000);
return strDate;
}
Pour ceux d’entre vous qui vraiment savent comment cela fonctionne, vous trouverez probablement des réserves.
Voici une autre façon de le faire. Entièrement autonome et entièrement compatible avec les versions antérieures. Nombre illimité de jours.
private static String slf(double n) {
return String.valueOf(Double.valueOf(Math.floor(n)).longValue());
}
public static String timeSpan(long timeInMs) {
double t = Double.valueOf(timeInMs);
if(t < 1000d)
return slf(t) + "ms";
if(t < 60000d)
return slf(t / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 3600000d)
return slf(t / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 86400000d)
return slf(t / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
return slf(t / 86400000d) + "d " +
slf((t % 86400000d) / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
}
Formatage simple pour un temps écoulé inférieur à 24h. Au-delà de 24h, le code n’affichera que les heures du lendemain et ne sera pas ajouté au jour écoulé.
public static String formatElapsedTime(long milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
}
Fonctionnalités manquantes dans l'exemple de code:
public static String formatElapsedTimeOver24h(long milliseconds) {
// Compiler will take care of constant arithmetics
if (24 * 60 * 60 * 1000 > milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
} else {
SimpleDateFormat sdf = new SimpleDateFormat(":mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// Keep long data type
// Compiler will take care of constant arithmetics
long hours = milliseconds / (60L * 60L * 1000L);
return hours + sdf.format(milliseconds);
}
}
Si vous utilisez une version Calendar
de Java simple pour des intervalles allant jusqu'à un jour (24 heures), consultez ma réponse à la question: Comment formater des intervalles de temps en Java?