Jak przekonwertować milisekundy na format „hh: mm: ss”?

184

Jestem zmieszany. Po napotkaniu tego wątku próbowałem wymyślić, jak sformatować licznik czasu, który miał ten format hh:mm:ss.

Oto moja próba -

//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)));   

Kiedy więc wypróbowuję wartość typu „ 3600000msdostaję” 01:59:00, co jest błędne, ponieważ powinno być 01:00:00. Oczywiście coś jest nie tak z moją logiką, ale w tej chwili nie widzę, co to jest!

Czy ktoś może pomóc?

Edytować -

Naprawione. Oto właściwy sposób na sformatowanie milisekund do hh:mm:sssformatowania -

//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))));

Problem polegał na tym TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)). Powinno tak być TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)).

mre
źródło
1
3 600 000 milisekund to 3600 sekund, 60 minut lub 1 godzina. Nie powinno być 00:59:59, powinno być 01:00:00.
Borealid

Odpowiedzi:

355

Byłaś naprawdę blisko:

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

Konwertujesz godziny na milisekundy, używając minut zamiast godzin .

BTW, podoba mi się korzystanie z TimeUnitAPI :)

Oto kod testowy:

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

Wynik:

01:00:00

Zrozumiałem, że mój powyższy kod można znacznie uprościć, używając podziału modułu zamiast odejmowania:

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

Nadal używam TimeUnitAPI dla wszystkich magicznych wartości i daje dokładnie takie same wyniki.

Czeski
źródło
2
Amen, jak sposób korzystania z TimeUnit API :)
Dheeraj Bhaskar
2
Wymyślenie koła na nowo nie jest dobrym pomysłem! Odpowiedź Tritona Człowieka jest lepszym rozwiązaniem.
محمدباقر
5
@ محمدباقر Ale druga odpowiedź korzysta z zewnętrznej biblioteki, podczas gdy mój kod używa tylko podstawowego JDK. To zależy od twoich potrzeb - na przykład możesz nie być w stanie korzystać z zewnętrznej biblioteki. Druga odpowiedź jest jednak dobra.
Czeski
2
@Ozuf dodaj .replaceAll("^00:", "")lub, .replaceAll("^00:(00:)?", "")aby usunąć minuty i godziny, jeśli oba są równe zero.
Czeski
2
@Ozuf otrzymujesz "15:00"i "10:00:23"odpowiednio; usuwane są tylko zera wiodące , ponieważ dopasowanie jest zakotwiczone na początku wprowadzania przez ^.
Czeski
77

Ogólna metoda tego jest dość prosta:

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
źródło
1
@ Javaman59, miałeś na myśli String.format("% 02 d:%02d:%02d", h,m,s) ?
KarenAnne,
2
@KarenAnne. Zależy to od tego, czy chcesz na przykład „03:59:59” czy „3:59:59”.
Stephen Hosking,
2
Czas jest w milisekundach, musisz pomnożyć sekundy przez 1000
Apurva
5
autor pytał o milisekundy, a nie sekundy!
user924
59

Jeśli używasz apache commons:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");
Triton Man
źródło
4
Skrót:DurationFormatUtils.formatDurationHMS(timeInMS);
Aroniaina
@Jorgesys Dlaczego są przestarzałe?
Piovezan
nie są przestarzałe.
Triton Man
26

Użyłem tego:

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

Zobacz opis klasy Formatter .

Zobacz wykonalny przykład z wykorzystaniem danych wejściowych 2400 ms.

ZuluM
źródło
Wygląda na to, że nie działa, po prostu testuję go przez zaliczenie 100, 1000, 1200 i odpowiada jako 05:30:00 , 05:30:01 , 05:30:01 .
CoDe
2
@CoDe, działa dla twojej strefy czasowej. Musisz być w innej strefie czasowej niż UTC. zależy odString.format() strefy czasowej . Jednak idealna poprawna odpowiedź powinna być niezależna od strefy czasowej .
Derek Mahar
@CoDe, pokazuje czasy, które odpowiadają twojej strefie czasowej, która musi być inna niż UTC. zależy odString.format() strefy czasowej . Jednak idealna poprawna odpowiedź powinna być niezależna od strefy czasowej .
Derek Mahar
25
// 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 );

Zobacz wykonalny przykład z wykorzystaniem danych wejściowych 1200 ms.

Vinay Lodha
źródło
3
Spowodowałoby to uzyskanie nieprawidłowych wyników dla ilości czasu dłuższych niż jeden dzień. Zwiększyłoby to liczbę godzin z 23 z powrotem do 0, co prawdopodobnie nie jest tutaj pożądane.
Kenster,
Żaden kolego ... Myślę, że nadal działałoby tak samo. spróbuj z dzisiejszą datą
Vinay Lodha
1
SimpleDateFormat sdf = nowy SimpleDateFormat („gg: mm aa”); na wypadek, gdyby ktoś chciał w formacie 12-godzinnym z am / pm
Ajji
14
DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);
Gabriel Belingueres
źródło
1
Ta sama odpowiedź, co stackoverflow.com/questions/9027317/... z tym samym problemem przez okres powyżej 1 dnia
OneWorld
Zależy to również od strefy czasowej, co oznacza, że ​​wynik będzie się różnił, gdy zostanie uruchomiony w różnych strefach czasowych.
Derek Mahar
10

Wyniki testu dla 4 wdrożeń

Konieczność wykonania dużego formatowania ogromnych danych wymagała najlepszej wydajności, więc oto (zaskakujące) wyniki:

dla (int i = 0; i <1000000; i ++) {FUNCTION_CALL}

Czas trwania:

  • Kombinacja Format : 196 Format milisów
  • format Czas trwania: 272 milis
  • apacheFormat: 754 milis
  • formatTimeUnit: 2216 milisów

    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(); 
     }
Marius A.
źródło
jak wiarygodne są takie wskaźniki? Nigdy tak naprawdę nie zrozumiałem tego procesu.
pan
W mojej sytuacji, w której kilka tysięcy obiektów powstaje kolejno, ten test wydaje mi się bardzo przydatny. Dobra, nie ustawiając tylko niektórych ciągów, ale tworząc obiekty, które mają jedno pole, sformatowany ciąg.
MariusA
@marius, którego użyłeś, StringBuildera potem popełniłeś błąd, używając „0” + rodzaj „ruiny”. @mre GC JVM jest wyjątkowo dobry w przydzielaniu i zbieraniu wielu krótkotrwałych obiektów, nie martw się. Poszedłem String.formatbez logiki wiodącej zero.
escape-llc
6

Idąc za odpowiedzią Czecha, nie musimy używać TimeUnit, aby znaleźć znaną wartość. Byłby o wiele bardziej optymalny kod

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

Mam nadzieję, że to pomoże

Aalin
źródło
Najbardziej podoba się twoja odpowiedź! Po prostu prosta matematyka. Btw w moim przypadku dodałem milisekundy do końca, millisLeft%1000/10więc otrzymujemy formathour:minutes:seconds:milliseconds
Lê Quang Duy
@ LêQuangDuy potrzebuję milisekund w 3 cyfrach, takich jak 01: 24: 51,123, ale w końcu kroisz 3 co robić?
naanu
@naanu wystarczy użyćmillisLeft%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
źródło
Odpowiedź zależy od strefy czasowej, co oznacza, że ​​wynik będzie różny, gdy zostanie uruchomiony w różnych strefach czasowych.
Derek Mahar
6

to zadziałało dla mnie z Kotlin

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
źródło
Działa idealnie dla mnie. To powinna być najlepsza odpowiedź, ponieważ obsługuje zero godzin
vNastępny
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);

To drukuje:

01:00:00

Robisz dobrze, pozwalając, aby metody biblioteczne przeprowadzały za ciebie konwersje. java.time, nowoczesny interfejs API daty i godziny Java, a ściślej jego Durationklasa robi to bardziej elegancko i mniej podatnie na błędy niżTimeUnit .

toMinutesPartitoSecondsPart metody użyłem zostały wprowadzone w Javie 9.

Java 6, 7 i 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);

Dane wyjściowe są takie same jak powyżej.

Pytanie: Jak to działa w Javie 6 i 7?

  • W Javie 8 i nowszych oraz na nowszych urządzeniach z Androidem (powiedziano mi, że od poziomu API 26) java.time jest wbudowany.
  • W Javie 6 i 7 pobierz ThreeTen Backport, backport współczesnych klas (ThreeTen dla JSR 310; patrz łącza u dołu).
  • Na (starszym) Androidzie użyj wersji ThreeTen Backport na Androida. To się nazywa ThreeTenABP. I pamiętaj, aby zaimportować klasy daty i godziny org.threeten.bpz podpakietów.

Spinki do mankietów

Ole VV
źródło
5

Poniższy kod wykonuje konwersję w obie strony

23: 59: 58: 999 do 86398999

i niż

86398999 do 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
źródło
Poparłem to rozwiązanie. Wystarczy wstawić kropkę między sekundą a mls. I nie wiem, dlaczego obsługa czasu i daty jest tak trudna w Javie. Najczęściej używane funkcje powinny być już dostępne i stanowić część klasy.
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

Przykład: 615605 Millisecend

00: 10: 15.605

Omid Naji
źródło
5

Odpowiedź oznaczona jako poprawna ma mały błąd,

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

na przykład jest to przykład wartości, którą otrzymuję:

417474:44:19

Oto rozwiązanie pozwalające uzyskać właściwy format:

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

uzyskanie w rezultacie poprawnego formatu:

18:44:19

inną opcją uzyskania formatu hh:mm:ssjest po prostu:

   Date myDate = new Date(timeinMillis);
   SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
   String myTime = formatter.format(myDate);
Jorgesys
źródło
4

Próbowałem, jak pokazano w pierwszej odpowiedzi. Działa, ale minus wprawił mnie w zamieszanie. Moja odpowiedź 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
źródło
3

Dla Kotlina

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)))

gdzie milSecsjest milisekundami

Kishan Solanki
źródło
1

Możesz spróbować czegoś takiego:

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

konwertować milisekundy na wartość czasu

anonimowy
źródło