Как преобразовать миллисекунды в формат чч:мм:сс?

Я запутался. Наткнувшись на этот поток, Я попытался выяснить, как отформатировать таймер обратного отсчета, который имел формат hh:mm:ss.

Вот моя попытка -

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

Итак, когда я пробую значение, подобное 3600000ms, я получаю 01:59:00, что неверно, поскольку должно быть 01:00:00. Очевидно, что-то не так с моей логикой, но в данный момент я не могу понять, что это такое!

Кто-нибудь может помочь?

Изменить –

Починил это. Вот правильный способ отформатировать миллисекунды в формате hh:mm:ss -

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

Проблема была в этом TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)). Вместо этого должен был быть этот TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)).


person mre    schedule 27.01.2012    source источник
comment
3 600 000 миллисекунд — это 3 600 секунд, или 60 минут, или 1 час. Не должно быть 00:59:59, должно быть 01:00:00.   -  person Borealid    schedule 27.01.2012


Ответы (18)


Вы были действительно близки:

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

Вы конвертировали часы в миллисекунды, используя минуты вместо часов.

Кстати, мне нравится, как вы используете TimeUnit API :)

Вот некоторый тестовый код:

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

Выход:

01:00:00

Я понял, что мой код выше можно значительно упростить, используя модульное деление вместо вычитания:

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

Все еще использую TimeUnit API для всех магических значений и дает точно такой же результат.

person Bohemian♦    schedule 27.01.2012
comment
Аминь, нравится, как вы используете TimeUnit API :) - person Dheeraj Bhaskar; 12.01.2013
comment
Изобретать велосипед - не лучшая идея! Ответ Triton Man - лучшее решение. - person محمدباقر; 10.07.2013
comment
@محمدباقر Но в другом ответе используется внешняя библиотека, тогда как в моем коде используется только основной JDK. Это зависит от ваших потребностей - например, вы не сможете использовать внешнюю библиотеку. Хотя другой ответ хорош. - person Bohemian♦; 10.07.2013
comment
Как насчет того, когда он превышает 365 дней? Можете ли вы сделать эквивалентные годы? Спасибо. - person KarenAnne; 15.10.2013
comment
@KarenAnne, что ты имеешь в виду? Можете ли вы дать образец ввода и вывода, пожалуйста? - person Bohemian♦; 15.10.2013
comment
@محمدباقر Мне нужно было добавить в строку дни и дополнительный текст. в этом ответе я легко вставил свой текст между% 02d и закончил, как насчет того, чтобы сделать это с ответом, который вы предложили, лучше, чем этот? - person MBH; 05.06.2016
comment
Учитывая время в миллисекундах, скажем, время не до часа, оно возвращает, например, 00:15:23. Есть ли способ заставить его удалить нули, если он пуст? Например, чтобы вернуть 15:23 вместо 00:15:23. - person X09; 10.04.2017
comment
@Ozuf добавьте .replaceAll("^00:", "") или .replaceAll("^00:(00:)?", ""), чтобы удалить минуты и часы, если оба равны нулю. - person Bohemian♦; 10.04.2017
comment
Спасибо, но что произойдет, если время будет 00:15:00 или 10:00:23? - person X09; 10.04.2017
comment
@Ozuf вы получаете "15:00" и "10:00:23" соответственно; удаляются только ведущие нули из-за того, что совпадение привязано к началу ввода с помощью ^. - person Bohemian♦; 10.04.2017
comment
Спасибо миллион :D. Пожалуйста, не могли бы вы обновить ответ, чтобы другие могли легко его увидеть? - person X09; 10.04.2017
comment
int hrs = (int) TimeUnit.MILLISECONDS.toHours(miliSeconds) % 24; int min = (int) TimeUnit.MILLISECONDS.toMinutes(miliSeconds) % 60; int sec = (int) TimeUnit.MILLISECONDS.toSeconds(miliSeconds) % 60; вернуть String.format(%02d:%02d:%02d, часы, мин, сек); - person Swapnil; 06.11.2018
comment
Сэкономил много моего времени. Спасибо. - person uncommon_breed; 04.03.2019

Общий метод для этого довольно прост:

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);
}
person Arets Paeglis    schedule 27.01.2012
comment
@ Javaman59, вы имели в виду String.format("% 02 d:%02d:%02d", h,m,s)? - person KarenAnne; 15.10.2013
comment
@КаренЭнн. Это зависит от того, хотите ли вы, например, 03:59:59 или 3:59:59. - person Stephen Hosking; 19.10.2013
comment
Время в миллисекундах, вам нужно умножить секунды на 1000 - person Apurva; 01.03.2015
comment
автор спрашивал о миллисекундах, а не о секундах! - person user924; 24.10.2017

Если вы используете Apache Commons:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");
person Rocky Pulley    schedule 01.05.2013
comment
Ярлык: DurationFormatUtils.formatDurationHMS(timeInMS); - person Aroniaina; 12.09.2017
comment
@Jorgesys Почему они устарели? - person Piovezan; 16.01.2019
comment
они не устарели. - person Rocky Pulley; 14.02.2019

Я использовал это:

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

См. описание класса Formatter.

См. исполняемый пример с использованием ввода 2400 мс.

person ZuluM    schedule 20.10.2015
comment
Кажется, это не работает, я просто тестирую его с проходом 100, 1000, 1200, и он отвечает как 05:30:00 , 05:30:01, 05 :30:01. - person CoDe; 24.10.2017
comment
@CoDe, это работает для вашего часового пояса. Вы должны находиться в часовом поясе, отличном от UTC. String.format() зависит от часового пояса. Однако идеальный правильный ответ должен быть независим от часового пояса. - person Derek Mahar; 05.07.2018
comment
@CoDe, он показывает время, соответствующее вашему часовому поясу, которое должно отличаться от UTC. String.format() зависит от часового пояса. Однако идеальный правильный ответ должен быть независим от часового пояса. - person Derek Mahar; 06.07.2018

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

См. исполняемый пример с вводом 1200 мс.

person Vinay Lodha    schedule 20.06.2014
comment
Это приведет к неправильным результатам для количества времени, превышающего день. Это перенесет количество часов с 23 обратно на 0, что, вероятно, здесь нежелательно. - person Kenster; 20.06.2014
comment
Нет, приятель... Я думаю, все будет работать так же. попробуйте с сегодняшней датой - person Vinay Lodha; 23.06.2014
comment
SimpleDateFormat sdf = новый SimpleDateFormat (чч: мм аа); на случай, если кто-то захочет в 12-часовом формате с am/pm - person Ajji; 23.05.2018

Результаты тестирования для 4 реализаций

Необходимость форматировать большие объемы данных требовала наилучшей производительности, поэтому вот (удивительные) результаты:

for (int i = 0; i ‹ 1000000; i++) { FUNCTION_CALL }

Продолжительность:

  • comboFormatter: 196 миллисекунд
  • formatDuration: 272 миллисекунды
  • apacheФормат: 754 миллис
  • formatTimeUnit: 2216 миллисекунд

    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(); 
     }
    
person MariusA    schedule 11.02.2014
comment
насколько надежны такие показатели? Я никогда не понимал процесс. - person mre; 11.02.2014
comment
В моей ситуации, когда последовательно создаются несколько тысяч объектов, этот тест я считаю весьма полезным. Хорошо, не устанавливая только некоторые строки, а создавая объекты, которые имеют одно поле отформатированной строки. - person MariusA; 12.02.2014
comment
@marius, ты потрудился, чтобы использовать StringBuilder, а затем сделал ошибку, использовав 0+число, что все испортило. GC @mre JVM очень хорошо распределяет и собирает множество недолговечных объектов, не беспокойтесь об этом. Я пошел с String.format без логики начального нуля, с которой нужно было иметь дело. - person escape-llc; 14.01.2016

это сработало для меня с котлином

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"
            }
        }
    }
person Devix    schedule 31.10.2018
comment
Работал отлично для меня. Это должен быть лучший ответ, так как он обрабатывает нулевой час - person vNext; 03.11.2019

Ява 9

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

Это печатает:

01:00:00

Вы поступаете правильно, позволяя библиотечным методам выполнять соответствующие преобразования за вас. java.time, современный API даты и времени Java, или, точнее, его класс Duration делает это более элегантно и менее подверженным ошибкам способом, чем TimeUnit.

Методы toMinutesPart и toSecondsPart, которые я использовал, были представлены в Java 9.

Ява 6, 7 и 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);

Выход такой же, как указано выше.

Вопрос: Как это может работать в Java 6 и 7?

  • В Java 8 и более поздних версиях, а также на более новых устройствах Android (начиная с уровня API 26, как мне сказали) java.time встроено.
  • В Java 6 и 7 используйте ThreeTen Backport, бэкпорт современных классов (ThreeTen для JSR 310; см. ссылки внизу).
  • На (старом) Android используйте версию ThreeTen Backport для Android. Он называется ThreeTenABP. И убедитесь, что вы импортируете классы даты и времени из org.threeten.bp с подпакетами.

Ссылки

person Ole V.V.    schedule 20.05.2018

В ответе, отмеченном как правильный, есть небольшая ошибка,

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

например, это пример значения, которое я получаю:

417474:44:19

Это решение для получения правильного формата:

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

получив в результате правильный формат:

18:44:19

другой вариант получить формат hh:mm:ss просто:

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

Судя по ответу Богемии, нам не нужно использовать TimeUnit для поиска известного значения. Гораздо более оптимальным был бы код

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

Надеюсь, поможет

person Aalin    schedule 03.05.2016
comment
Ваш ответ понравился больше всего! Просто простая математика. Кстати, в моем случае я добавил миллисекунды в конец millisLeft%1000/10, поэтому мы получили формат hour:minutes:seconds:milliseconds - person Lê Quang Duy; 17.03.2017
comment
@ LêQuangDuy Мне нужны миллисекунды в 3 цифрах, например 01:24:51,123, но у вас, наконец, 3, что делать? - person Vikas Acharya; 19.06.2020
comment
@naanu просто используй millisLeft%1000 - person Lê Quang Duy; 20.06.2020

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

Формат: 00:00:00.000

Пример: 615605 Миллисекунды

00:10:15.605

person Omid Naji    schedule 20.07.2016

Код ниже выполняет преобразование в обоих направлениях

23:59:58:999 to 86398999

и тогда

86398999 to 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;
    }
}
person Menzio Luca Fabrizio    schedule 28.03.2015
comment
Я проголосовал за это решение. Просто поставьте точку между sec и mls. И я не знаю, почему обработка времени и даты так сложна в Java. Наиболее часто используемые функции должны быть уже доступны и являться частью класса. - person Baruch Atta; 05.03.2018

Я попробовал, как показано в первом ответе. Работает, но минус привел меня в замешательство. Мой ответ от 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])
}
person leonov    schedule 25.07.2013

Для Котлина

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

где milSecs - миллисекунды

person Kishan Solanki    schedule 21.05.2018

Ну, вы можете попробовать что-то вроде этого:

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

для преобразования миллисекунд в значение времени

person anonymous    schedule 27.01.2012

В Котлине:

fun FUNCTION_NAME(milliSeconds: Long): String {
    val s: Long = milliSeconds / 1000 % 60

    val m: Long = milliSeconds / (1000*60) % 60

    val h: Long = milliSeconds / (1000*60*60) % 24

    return String.format("%02d:%02d:%02d", h, m, s)
}
person Lony    schedule 29.06.2021
comment
Этот вопрос задан в JAVA, вы должны ответить на него в Java, пожалуйста. - person Kaveh; 29.06.2021

person    schedule
comment
Тот же ответ, что и stackoverflow.com/questions/9027317/ с той же проблемой продолжительностью более 1 дня - person OneWorld; 24.02.2016
comment
Это также зависит от часового пояса, что означает, что результат будет отличаться при запуске в разных часовых поясах. - person Derek Mahar; 06.07.2018

person    schedule
comment
Ответ зависит от часового пояса, что означает, что результат будет отличаться при запуске в разных часовых поясах. - person Derek Mahar; 06.07.2018