Wie konvertiere ich Millisekunden in das Format „hh: mm: ss“?

183

Ich bin verwirrt. Nachdem ich über diesen Thread gestolpert war , versuchte ich herauszufinden, wie man einen Countdown-Timer formatiert, der das Format hatte hh:mm:ss.

Hier ist mein Versuch -

//hh:mm:ss
String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) - 
    TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));   

Wenn ich also einen Wert wie versuche 3600000ms, bekomme ich 01:59:00, was falsch ist, da es sein sollte 01:00:00. Natürlich stimmt etwas mit meiner Logik nicht, aber im Moment kann ich nicht sehen, was es ist!

Kann jemand helfen?

Bearbeiten -

Behoben. Hier ist der richtige Weg, um Millisekunden zu hh:mm:ssformatieren -

//hh:mm:ss
String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) - 
    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))));

Das Problem war das TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)). Es hätte TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))stattdessen so sein sollen.

mre
quelle
1
3.600.000 Millisekunden sind 3.600 Sekunden oder 60 Minuten oder 1 Stunde. Es sollte nicht sein 00:59:59, es sollte sein 01:00:00.
Borealid

Antworten:

354

Sie waren wirklich nah:

String.format("%02d:%02d:%02d", 
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) -  
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), // The change is in this line
TimeUnit.MILLISECONDS.toSeconds(millis) - 
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));   

Sie haben Stunden in Millissekunden umgerechnet, indem Sie Minuten anstelle von Stunden verwendet haben .

Übrigens, ich mag Ihre Verwendung der TimeUnitAPI :)

Hier ist ein Testcode:

public static void main(String[] args) throws ParseException {
    long millis = 3600000;
    String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
    System.out.println(hms);
}

Ausgabe:

01:00:00

Ich habe festgestellt, dass mein Code oben durch die Verwendung einer Moduldivision anstelle einer Subtraktion erheblich vereinfacht werden kann:

String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) % TimeUnit.HOURS.toMinutes(1),
    TimeUnit.MILLISECONDS.toSeconds(millis) % TimeUnit.MINUTES.toSeconds(1));

Verwendet weiterhin die TimeUnitAPI für alle magischen Werte und liefert genau die gleiche Ausgabe.

Böhmisch
quelle
2
Amen, wie Sie TimeUnit API verwenden :)
Dheeraj Bhaskar
2
Es ist keine gute Idee, das Rad neu zu erfinden! Die Antwort von Triton Man ist eine bessere Lösung.
Freitag,
5
@ محمدباقر Aber die andere Antwort verwendet eine externe Bibliothek, während mein Code nur das Kern-JDK verwendet. Dies hängt von Ihren Anforderungen ab. Beispielsweise können Sie möglicherweise keine externe Bibliothek verwenden. Die andere Antwort ist jedoch gut.
Bohemian
2
@Ozuf füge Minuten .replaceAll("^00:", "")oder .replaceAll("^00:(00:)?", "")Stunden hinzu oder entferne sie, wenn beide Null sind.
Bohemian
2
@Ozuf Sie erhalten "15:00"und "10:00:23"verbunden sind; Es werden nur führende Nullen entfernt, da die Übereinstimmung am Beginn der Eingabe durch verankert ist ^.
Bohemian
77

Die generische Methode hierfür ist ziemlich einfach:

public static String convertSecondsToHMmSs(long seconds) {
    long s = seconds % 60;
    long m = (seconds / 60) % 60;
    long h = (seconds / (60 * 60)) % 24;
    return String.format("%d:%02d:%02d", h,m,s);
}
Arets Paeglis
quelle
1
@ Javaman59, meintest du String.format("% 02 d:%02d:%02d", h,m,s) ?
KarenAnne
2
@ KarenAnne. Das hängt davon ab, ob Sie beispielsweise "03:59:59" oder "3:59:59" möchten.
Stephen Hosking
2
Die Zeit ist in Millisekunden, Sie müssen Sekunden mit 1000 multiplizieren
Apurva
5
Autor fragte nach Millisekunden, nicht nach Sekunden!
user924
59

Wenn Sie Apache Commons verwenden:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");
Triton Man
quelle
4
DurationFormatUtils.formatDurationHMS(timeInMS);
Abkürzung
@Jorgesys Warum sind sie veraltet?
Piovezan
Sie sind nicht veraltet.
Triton Man
26

Ich habe das benutzt:

String.format("%1$tH:%1$tM:%1$tS.%1$tL", millis);

Siehe Beschreibung der Klasse Formatierer .

Siehe ausführbares Beispiel mit einer Eingabe von 2400 ms.

ZuluM
quelle
Es scheint nicht zu funktionieren, ich teste es einfach mit Pass 100, 1000, 1200 und es antwortet als 05:30:00 , 05:30:01 , 05:30:01 .
CoDe
2
@CoDe, es funktioniert für Ihre Zeitzone. Sie müssen sich in einer anderen Zeitzone als UTC befinden. String.format()ist zeitzonenabhängig . Die ideale richtige Antwort sollte jedoch Zeitzone unabhängig .
Derek Mahar
@CoDe zeigt Zeiten an, die Ihrer Zeitzone entsprechen und sich von UTC unterscheiden müssen. String.format()ist zeitzonenabhängig . Die ideale richtige Antwort sollte jedoch Zeitzone unabhängig .
Derek Mahar
24
// New date object from millis
Date date = new Date(millis);
// formattter 
SimpleDateFormat formatter= new SimpleDateFormat("HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// Pass date object
String formatted = formatter.format(date );

Siehe ausführbares Beispiel mit einer Eingabe von 1200 ms.

Vinay Lodha
quelle
3
Dies würde zu falschen Ergebnissen für Zeiträume von mehr als einem Tag führen. Es würde die Anzahl der Stunden von 23 auf 0 zurückführen, was hier wahrscheinlich nicht wünschenswert ist.
Kenster
Kein Kumpel ... Ich denke, es würde immer noch genauso funktionieren. versuchen Sie es mit dem heutigen Datum
Vinay Lodha
1
SimpleDateFormat sdf = new SimpleDateFormat ("hh: mm aa"); für den Fall, dass jemand im 12-Stunden-Format mit am / pm will
Ajji
14
DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);
Gabriel Belingueres
quelle
1
Gleiche Antwort wie stackoverflow.com/questions/9027317/… mit demselben Problem für eine Dauer von mehr als 1 Tag
OneWorld
Dies hängt auch von der Zeitzone ab, was bedeutet, dass das Ergebnis unterschiedlich ist, wenn es in verschiedenen Zeitzonen ausgeführt wird.
Derek Mahar
10

Testergebnisse für die 4 Implementierungen

Da für große Datenmengen viel formatiert werden musste, war die beste Leistung erforderlich. Hier sind die (überraschenden) Ergebnisse:

für (int i = 0; i <1000000; i ++) {FUNCTION_CALL}

Dauer:

  • KombinationFormater: 196 Millis
  • FormatDauer: 272 Millis
  • apacheFormat: 754 Millis
  • formatTimeUnit: 2216 Millis

    public static String apacheFormat(long millis) throws ParseException {
        return DurationFormatUtils.formatDuration(millis, "HH:mm:ss");
    }
    
    public static String formatTimeUnit(long millis) throws ParseException {
    String formatted = String.format(
            "%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis)
                    - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis)
                    - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        return formatted;
    }
    
    public static String formatDuration(final long millis) {
        long seconds = (millis / 1000) % 60;
        long minutes = (millis / (1000 * 60)) % 60;
        long hours = millis / (1000 * 60 * 60);
    
        StringBuilder b = new StringBuilder();
        b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) : 
        String.valueOf(hours));
        b.append(":");
        b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) :     
        String.valueOf(minutes));
        b.append(":");
        b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) : 
        String.valueOf(seconds));
        return b.toString();
    }
    
    public static String combinationFormatter(final long millis) {
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis)
                - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis)
                - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis));
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
    
        StringBuilder b = new StringBuilder();
        b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) : 
        String.valueOf(hours));
        b.append(":");
        b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) : 
        String.valueOf(minutes));
            b.append(":");
        b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) : 
        String.valueOf(seconds));
        return b.toString(); 
     }
MariusA
quelle
Wie zuverlässig sind solche Metriken? Ich habe den Prozess nie wirklich verstanden.
Mehr
In meiner Situation, in der einige tausend Objekte nacheinander erstellt werden, ist dieser Test meiner Meinung nach ziemlich nützlich. Okay, nicht nur einige Zeichenfolgen festlegen, sondern Objekte erstellen, deren Feld eine formatierte Zeichenfolge ist.
MariusA
@Marius du hast dir die Mühe gemacht, es zu benutzen, StringBuilderdann hast du den Fehler gemacht, "0" + eine Art "Ruine" zu verwenden. @mre JVMs GC ist extrem gut darin, viele kurzlebige Objekte zuzuweisen und zu sammeln, keine Sorge. Ich ging String.formatohne führende Null-Logik vor.
Flucht-llc
6

Nach Bohemians Antwort müssen wir TimeUnit nicht verwenden, um einen bekannten Wert zu finden. Viel optimaler Code wäre

String hms = String.format("%02d:%02d:%02d", millisLeft/(3600*1000),
                    millisLeft/(60*1000) % 60,
                    millisLeft/1000 % 60);

Ich hoffe es hilft

Aalin
quelle
Wie deine Antwort am meisten! Nur einfache Mathematik. Übrigens habe ich in meinem Fall die Millisekunden am Ende hinzugefügt, millisLeft%1000/10damit wir das Format erhaltenhour:minutes:seconds:milliseconds
Lê Quang Duy
@ LêQuangDuy Ich brauche Millisekunden in 3 Ziffern wie 01: 24: 51,123, aber du schneidest endlich 3, was zu tun ist?
Naanu
@naanu nur verwendenmillisLeft%1000
Lê Quang Duy
6
 public String millsToDateFormat(long mills) {

    Date date = new Date(mills);
    DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
    String dateFormatted = formatter.format(date);
    return dateFormatted; //note that it will give you the time in GMT+0
}
ctu
quelle
Die Antwort hängt von der Zeitzone ab, was bedeutet, dass das Ergebnis unterschiedlich ist, wenn es in verschiedenen Zeitzonen ausgeführt wird.
Derek Mahar
6

Das hat bei mir mit Kotlin funktioniert

fun formatToDigitalClock(miliSeconds: Long): String {
        val hours = TimeUnit.MILLISECONDS.toHours(miliSeconds).toInt() % 24
        val minutes = TimeUnit.MILLISECONDS.toMinutes(miliSeconds).toInt() % 60
        val seconds = TimeUnit.MILLISECONDS.toSeconds(miliSeconds).toInt() % 60
        return when {
            hours > 0 -> String.format("%d:%02d:%02d", hours, minutes, seconds)
            minutes > 0 -> String.format("%02d:%02d", minutes, seconds)
            seconds > 0 -> String.format("00:%02d", seconds)
            else -> {
                "00:00"
            }
        }
    }
Devix
quelle
Hat perfekt für mich funktioniert. Dies sollte die beste Antwort sein, da es null Stunden behandelt
vNext
6

Java 9

    Duration timeLeft = Duration.ofMillis(3600000);
    String hhmmss = String.format("%02d:%02d:%02d", 
            timeLeft.toHours(), timeLeft.toMinutesPart(), timeLeft.toSecondsPart());
    System.out.println(hhmmss);

Dies druckt:

01:00:00

Sie machen es richtig, dass Bibliotheksmethoden die Konvertierungen für Sie durchführen. java.time, die moderne Java-API für Datum und Uhrzeit, oder genauer gesagt, ihre DurationKlasse macht es eleganter und weniger fehleranfällig als TimeUnit.

Die toMinutesPartund toSecondsPartMethoden, die ich verwendet habe, wurden in Java 9 eingeführt.

Java 6, 7 und 8

    long hours = timeLeft.toHours();
    timeLeft = timeLeft.minusHours(hours);
    long minutes = timeLeft.toMinutes();
    timeLeft = timeLeft.minusMinutes(minutes);
    long seconds = timeLeft.toSeconds();
    String hhmmss = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    System.out.println(hhmmss);

Die Ausgabe ist die gleiche wie oben.

Frage: Wie kann das in Java 6 und 7 funktionieren?

  • In Java 8 und höher und auf neueren Android-Geräten (ab API-Level 26, wurde mir gesagt) java.time integriert.
  • In Java 6 und 7 erhalten Sie den ThreeTen Backport, den Backport der modernen Klassen (ThreeTen für JSR 310; siehe die Links unten).
  • Verwenden Sie auf (älteren) Android die Android-Edition von ThreeTen Backport. Es heißt ThreeTenABP. Und stellen Sie sicher, dass Sie die Datums- und org.threeten.bpZeitklassen mit Unterpaketen importieren.

Links

Ole VV
quelle
5

Der folgende Code führt die Konvertierung in beide Richtungen durch

23: 59: 58: 999 bis 86398999

und dann

86398999 bis 23: 59: 58: 999


import java.util.concurrent.TimeUnit;

public class TimeUtility {

    public static void main(String[] args) {

        long currentDateTime = System.currentTimeMillis();

        String strTest = "23:59:58:999";
        System.out.println(strTest);

        long l = strToMilli(strTest);
        System.out.println(l);
        l += 1;
        String str = milliToString(l);
        System.out.println(str);
    }

    /**
     * convert a time string into the equivalent long milliseconds
     *
     * @param strTime string fomratted as HH:MM:SS:MSMS i.e. "23:59:59:999"
     * @return long integer like 86399999
     */
    public static long strToMilli(String strTime) {
        long retVal = 0;
        String hour = strTime.substring(0, 2);
        String min = strTime.substring(3, 5);
        String sec = strTime.substring(6, 8);
        String milli = strTime.substring(9, 12);
        int h = Integer.parseInt(hour);
        int m = Integer.parseInt(min);
        int s = Integer.parseInt(sec);
        int ms = Integer.parseInt(milli);

        String strDebug = String.format("%02d:%02d:%02d:%03d", h, m, s, ms);
        //System.out.println(strDebug);
        long lH = h * 60 * 60 * 1000;
        long lM = m * 60 * 1000;
        long lS = s * 1000;

        retVal = lH + lM + lS + ms;
        return retVal;
    }

    /**
     * convert time in milliseconds to the corresponding string, in case of day
     * rollover start from scratch 23:59:59:999 + 1 = 00:00:00:000
     *
     * @param millis the number of milliseconds corresponding to tim i.e.
     *               34137999 that can be obtained as follows;
     *               <p>
     *               long lH = h * 60 * 60 * 1000; //hour to milli
     *               <p>
     *               long lM = m * 60 * 1000; // minute to milli
     *               <p>
     *               long lS = s * 1000; //seconds to milli
     *               <p>
     *               millis = lH + lM + lS + ms;
     * @return a string formatted as HH:MM:SS:MSMS i.e. "23:59:59:999"
     */
    private static String milliToString(long millis) {

        long hrs = TimeUnit.MILLISECONDS.toHours(millis) % 24;
        long min = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
        long sec = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
        //millis = millis - (hrs * 60 * 60 * 1000); //alternative way
        //millis = millis - (min * 60 * 1000);
        //millis = millis - (sec * 1000);
        //long mls = millis ;
        long mls = millis % 1000;
        String toRet = String.format("%02d:%02d:%02d:%03d", hrs, min, sec, mls);
        //System.out.println(toRet);
        return toRet;
    }
}
Menzio Luca Fabrizio
quelle
Ich habe diese Lösung positiv bewertet. Setzen Sie einfach einen Punkt zwischen sec und mls. Und ich weiß nicht, warum die Handhabung von Zeiten und Datumsangaben in Java sooooo schwierig ist. Die am häufigsten verwendeten Funktionen sollten bereits verfügbar und Teil der Klasse sein.
Baruch Atta
5
        String string = String.format("%02d:%02d:%02d.%03d",
            TimeUnit.MILLISECONDS.toHours(millisecend), TimeUnit.MILLISECONDS.toMinutes(millisecend) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millisecend)),
            TimeUnit.MILLISECONDS.toSeconds(millisecend) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisecend)), millisecend - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisecend)));

Format: 00: 00: 00.000

Beispiel: 615605 Millisecend

00: 10: 15.605

Omid Naji
quelle
5

Die als richtig gekennzeichnete Antwort hat einen kleinen Fehler.

String myTime = String.format("%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) -
                    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), // The change is in this line
            TimeUnit.MILLISECONDS.toSeconds(millis) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

Zum Beispiel ist dies ein Beispiel für den Wert, den ich bekomme:

417474:44:19

Dies ist die Lösung, um das richtige Format zu erhalten:

String myTime =  String.format("%02d:%02d:%02d",
                //Hours
                TimeUnit.MILLISECONDS.toHours(millis) -
                        TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(millis)),
                //Minutes
                TimeUnit.MILLISECONDS.toMinutes(millis) -
                        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                //Seconds
                TimeUnit.MILLISECONDS.toSeconds(millis) -
                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

als Ergebnis ein korrektes Format erhalten:

18:44:19

Eine andere Option, um das Format zu erhalten, hh:mm:ssist nur:

   Date myDate = new Date(timeinMillis);
   SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
   String myTime = formatter.format(myDate);
Jorgesys
quelle
4

Ich habe es wie in der ersten Antwort gezeigt versucht. Es funktioniert, aber Minus brachte mich in Verwirrung. Meine Antwort von Groovy:

import static java.util.concurrent.TimeUnit.*

...

private static String formatElapsedTime(long millis) {

    int hrs = MILLISECONDS.toHours(millis) % 24
    int min = MILLISECONDS.toMinutes(millis) % 60
    int sec = MILLISECONDS.toSeconds(millis) % 60
    int mls = millis % 1000

    sprintf( '%02d:%02d:%02d (%03d)', [hrs, min, sec, mls])
}
leonov
quelle
3

Für Kotlin

val hours = String.format("%02d", TimeUnit.MILLISECONDS.toHours(milSecs))
val minutes = String.format("%02d",
                        TimeUnit.MILLISECONDS.toMinutes(milSecs) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milSecs)))
val seconds = String.format("%02d",
                        TimeUnit.MILLISECONDS.toSeconds(milSecs) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milSecs)))

wo milSecsist Millisekunden

Kishan Solanki
quelle
1

Nun, Sie könnten so etwas versuchen:

public String getElapsedTimeHoursMinutesSecondsString() {       
     long elapsedTime = getElapsedTime();  
     String format = String.format("%%0%dd", 2);  
     elapsedTime = elapsedTime / 1000;  
     String seconds = String.format(format, elapsedTime % 60);  
     String minutes = String.format(format, (elapsedTime % 3600) / 60);  
     String hours = String.format(format, elapsedTime / 3600);  
     String time =  hours + ":" + minutes + ":" + seconds;  
     return time;  
 }  

Millisekunden in einen Zeitwert umwandeln

anonym
quelle