web-dev-qa-db-fra.com

Comment formater un intervalle de temps écoulé au format hh: mm: ss.SSS en Java?

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.

32
JDS

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);
    }
6
Lawrence Dol

La prise en charge de ce que vous voulez faire est intégrée aux derniers JDK avec une classe peu connue appelée 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
67
user177800

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");
}
26
Paul Sexton

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);
}
6
Jeff T.

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)));
}
5
Ed Staub

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 );
    }
}
3
mksteve

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));
2
Amir Raminfar

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.

1
Kal

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.

0
Ingemar

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";
}
0
youurayy

Variante: jusqu'à 24 heures

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:

  • Éliminer le fuseau horaire avec "UTC" 
  • Utilisez le format 24h "HH"

Variante: Plus de 24 heures

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);
    }
}
0
notes-jj

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?

0
Jiri Patera