it-swarm.com.de

Wie formatiere ich ein verstrichenes Zeitintervall im Format hh: mm: ss.SSS in Java?

Ich mache eine Stoppuhr, bei der ich Java SimpleDateFormat verwende, um die Anzahl der Millisekunden in ein Nice-Format "hh: mm: ss: SSS" zu konvertieren. Das Problem ist, dass das Stundenfeld immer eine Zufallszahl enthält. Hier ist der Code, den ich verwende: 

public static String formatTime(long millis) {
    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");

    String strDate = sdf.format(millis);
    return strDate;
}

Wenn ich den hh-Teil abnehme, funktioniert es gut. Andernfalls wird im hh-Teil etwas zufällig wie "07" angezeigt, auch wenn das übergebene Argument (Anzahl Millisekunden) Null ist. 

Ich weiß nicht viel über die SimpleDateFormat-Klasse. Danke für jede Hilfe.

32
JDS

So habe ich es gemacht, indem ich nur das Standard-JDK verwendet habe (dies wird bis zu Java 1.1 funktionieren, indem StringBuilder zurück in StringBuffer geändert wird):

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

Die Unterstützung für das, was Sie tun möchten, ist in den neuesten JDKs mit einer wenig bekannten Klasse namens TimeUnit integriert.

Was Sie verwenden möchten, ist Java.util.concurrent.TimeUnit , um mit Intervallen zu arbeiten. 

SimpleDateFormat macht genau das, was es klingt, formatiert Instanzen von Java.util.Date oder konvertiert in Ihrem Fall den long-Wert in den Kontext eines Java.util.Date und weiß nicht, was Sie mit Intervalle tun sollen anscheinend arbeiten mit. 

Sie können dies ganz einfach tun, ohne auf externe Bibliotheken wie JodaTime zurückgreifen zu müssen.

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])));
    }
}

Die Ausgabe wird in etwa wie folgt formatiert

13:00:00.000
67
user177800

Eine kürzere Möglichkeit, dies zu tun, ist die Verwendung von DurationFormatUtils class in Apache Commons Lang :

public static String formatTime(long millis) {
    return DurationFormatUtils.formatDuration(millis, "HH:mm:ss.S");
}
26
Paul Sexton

Warum nicht das?

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.

Dies ist der erste Teil von Joda, den ich gemacht habe, wo es langweiliger schien als die Unterstützung durch JDK. Eine Joda-Implementierung für das angeforderte Format (mit einigen Annahmen über Nullfelder) ist:

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

Bei der Überprüfung der anderen Antworten kam ich mit dieser Funktion ...

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

Hier ist was los ist. Wenn Sie Millisekunden übergeben, ist diese Zahl relativ zum 1. Januar 1970. Wenn Sie 0 übergeben, wird dieses Datum in die lokale Zeitzone umgewandelt. Wenn Sie sich in der Zentralzeit befinden, dann ist das 7 Uhr. Wenn Sie dies ausführen, ist alles sinnvoll.

new SimpleDateFormat().format(0) => 12/31/69 7:00 PM

Edit, ich glaube, Sie wollen abgelaufene Zeit bekommen. Dafür empfehle ich die Verwendung von JodaTime , was dies bereits ziemlich gut macht. Sie machen so etwas 

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

Das Format richtet sich nach Ihrer lokalen Zeitzone. Wenn Sie also 0 übergeben, wird 0 GMT angenommen und in Ihre lokale Zeitzone konvertiert.

1
Kal

Dieses funktioniert zwar, aber ich scheine die Absicht der Methode zu verändern :-).

public static String formatTime(long millis) {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

    String strDate = sdf.format(millis - 3600000);
    return strDate;
}

Für diejenigen von Ihnen, die wirklich wissen, wie dies funktioniert, werden Sie wahrscheinlich einige Vorbehalte finden.

0
Ingemar

Hier ist eine andere Möglichkeit, dies zu tun. Vollständig in sich geschlossen und vollständig abwärtskompatibel. Unbegrenzte Anzahl von Tagen.

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: Bis zu 24 Stunden

Einfache Formatierung für weniger als 24 Stunden. Über 24 Stunden zeigt der Code nur die Stunden innerhalb des nächsten Tages an und addiert den verstrichenen Tag nicht zu den Stunden.

public static String formatElapsedTime(long milliseconds) {

    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

    return sdf.format(milliseconds);
}

Fehlende Funktionen im Beispielcode:

  • Beseitigen Sie die Zeitzone mit "UTC" 
  • Verwenden Sie das 24h-Format "HH"

Variante: über 24 Stunden

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

Verwenden Sie ein einfaches Java Calendar für Intervalle bis zu einem Tag (24 Stunden). Siehe meine Antwort auf die Frage: Wie formatiere ich Zeitintervalle in Java?

0
Jiri Patera

tl; dr

LocalTime                     // Represents a time-of-day, without date and without time zone.
.ofNanoOfDay(                 // Convert a count of nanoseconds into a time-of-day in a generic 24-hour day, ignoring real-world anomalies such as Daylight Saving Time (DST). 
    Duration                  // Class that represents a span-of-time not attached to the timeline.
    .of( milliseconds )       // Parse your count of milliseconds as a span-of-time.
    .toNanos()                // Extract total number of nanoseconds in this span-of-time.
)                             // Returns a `LocalDate` object.
.toString()                   // Generate text in standard ISO 8601 format for a time-of-day (*not* recommended by me). 

Java.time.Duration

Die richtige Klasse für eine Zeitspanne, die nicht mit der Zeitachse verknüpft ist, ist Duration . Verwenden Sie für eine Skala von Jahren, Monaten und Tagen Period .

Duration d = Duration.of( milliseconds ) ;

ISO 8601 Format

Ich schlage vor, Sie vermeiden, eine Zeitspanne im Uhrzeitformat HH: MM: SS zu melden. Ich habe gesehen, dass die inhärente Mehrdeutigkeit zu Fehlinterpretationen und Verwirrung in echten Geschäftsanwendungen führt.

Es gibt einen Standard für die Meldung solcher Werte: definiert in ISO 8601 : PnYnMnDTnHnMnS. Das P markiert den Anfang, während das T einen Teil von Jahr, Monat, Tag von einem Teil von Stunde, Minute und Sekunde trennt.

Die Java.time-Klassen verwenden beim Parsen/Generieren von Zeichenfolgen standardmäßig die ISO 8601-Standardformate. Dies schließt die Klasse Duration ein.

Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toString() ;

Siehe dies Code wird live auf IdeOne.com ausgeführt .

PT1H23M45.678S

Diese ISO 8601-Zeichenfolgen können sowohl analysiert als auch generiert werden.

Duration d = Duration.parse( "PT1H23M45.678S" ) ;

Uhrzeitformat

Wenn Sie jedoch darauf bestehen, das Uhrzeitformat für Ihre Dauer zu verwenden, können Sie einen solchen Stich zusammenstellen, indem Sie die Methoden to…Part Für das Objekt Duration aufrufen.

Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + TimeUnit.NANOSECONDS.toMillis( d.toNanosPart() ) ;

1: 23: 45.678

Oder wir könnten die Klasse LocalTime missbrauchen, um Ihre Zeichenfolge zu erstellen.

Duration d = Duration.ofMillis( 5_025_678L ) ;
long nanoOfDay = d.toNanos() ;
LocalTime localTimeBogus = LocalTime.ofNanoOfDay( nanoOfDay ) ;
String output = localTimeBogus.toString() ;

Auch hier können Sie dies sehen Code wird live auf IdeOne.com ausgeführt .

01: 23: 45.678

0
Basil Bourque