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

184

Я запутался. Наткнувшись на эту ветку, я попытался выяснить, как отформатировать таймер обратного отсчета, который имел формат 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)).

MRE
источник
1
3600000 миллисекунд - это 3600 секунд, или 60 минут, или 1 час. Так не должно быть 00:59:59, так и должно быть 01:00:00.
Бореалид

Ответы:

355

Вы были очень близки

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

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

Кстати, мне нравится ваше использование TimeUnitAPI :)

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

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

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

Богемский
источник
2
Аминь, как способ использовать TimeUnit API :)
Dheeraj Bhaskar
2
Не стоит изобретать велосипед! Ответ Тритона Мана - лучшее решение.
محمدباقر
5
@ محمدباقر Но другой ответ использует внешнюю библиотеку, тогда как мой код использует только основной JDK. Это зависит от ваших потребностей - например, вы не сможете использовать внешнюю библиотеку. Другой ответ хорош, хотя.
Богемный
2
@Ozuf добавить .replaceAll("^00:", "")или .replaceAll("^00:(00:)?", "")удалить минуты, а также часы, если оба равны нулю.
Богемный
2
@Ozuf вы получаете "15:00"и "10:00:23"соответственно; только ведущие нули удаляются, в результате сравнения будет якорем , чтобы начать с вводом ^.
Богемный
77

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

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);
}
Арец Паеглис
источник
1
@ Javaman59, ты имел в виду String.format("% 02 d:%02d:%02d", h,m,s) ?
КаренАнн
2
@KarenAnne. Это зависит от того, хотите ли вы, например, «03:59:59» или «3:59:59».
Стивен Хоскинг
2
Время в миллисекундах, вам нужно умножить секунды на 1000
Апурва
5
Автор спрашивал о миллисекундах, а не секундах!
user924
59

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

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");
Тритон Мэн
источник
4
Ярлык:DurationFormatUtils.formatDurationHMS(timeInMS);
Ароняйна
@Jorgesys Почему они устарели?
Пиовезан
они не устарели.
Тритон Мэн
26

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

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

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

См. Работающий пример с использованием ввода 2400 мс.

ZULUM
источник
Кажется, он не работает, я просто проверяю его, проходя 100, 1000, 1200, и он отвечает как 05:30:00 , 05:30:01 , 05:30:01 .
Код
2
@CoDe, это работает для вашего часового пояса. Вы должны быть в другом часовом поясе, чем UTC. String.format()это временная зона зависит . Однако идеальный правильный ответ должен быть независимым от часового пояса .
Дерек Махар
@CoDe, он показывает время, которое соответствует вашему часовому поясу, который должен отличаться от UTC. String.format()это временная зона зависит . Однако идеальный правильный ответ должен быть независимым от часового пояса .
Дерек Махар
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 );

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

Виная Лодха
источник
3
Это дало бы неправильные результаты за промежуток времени более суток. Это обернуло бы количество часов с 23 до 0, что, вероятно, здесь нежелательно.
Кенстер
Нет, приятель ... Я думаю, что все равно будет работать так же. попробуйте с сегодняшней датой
Vinay Lodha
1
SimpleDateFormat sdf = new SimpleDateFormat ("чч: мм аа"); если кто-то хочет в 12-часовом формате с am / pm
Ajji
14
DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);
Габриэль Белингерес
источник
1
Тот же ответ, что и stackoverflow.com/questions/9027317/… с той же проблемой на срок более 1 дня
OneWorld
Это также зависит от часового пояса, что означает, что результат будет отличаться при запуске в разных часовых поясах.
Дерек Махар
10

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

Потребовалось много форматирования для больших данных, нужна лучшая производительность, поэтому вот (неожиданные) результаты:

для (int i = 0; i <1000000; i ++) {FUNCTION_CALL}

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

  • комбинация форматирования : 196 миллис
  • formatDuration: 272 миллис
  • apacheFormat: 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(); 
     }
MariusA
источник
Насколько надежны такие показатели? Я никогда не понимал этот процесс.
MRE
В моей ситуации, когда несколько тысяч объектов создаются последовательно, этот тест, на мой взгляд, очень полезен. Хорошо, не устанавливая только некоторые строки, но создавая объекты, которые имеют одно поле отформатированной строки.
MariusA
@marius вы пошли на неприятности, чтобы использовать, а StringBuilderзатем сделать ошибку, используя «0» + номер типа «разрушает» его. ГК @mre JVM чрезвычайно хорош в распределении и сборе большого количества недолговечных объектов, здесь нет проблем. Я пошел String.formatбез логики «ведущий-ноль».
побег-ООО
7

это сработало для меня, с 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
источник
Работал отлично для меня. Это должен быть лучший ответ, поскольку он обрабатывает ноль часов
vNext
6

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

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

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

Aalin
источник
Мне нравится ваш ответ больше всего! Просто простая математика. Кстати, в моем случае я добавил миллисекунды до конца, millisLeft%1000/10чтобы мы получили форматhour:minutes:seconds:milliseconds
Lê Quang Duy
@ LêQuangDuy Мне нужны миллисекунды в 3 цифры, например, 01: 24: 51,123, но вы, наконец, рубите 3, что делать?
Наану
@naanu просто использовать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
источник
Ответ зависит от часового пояса, что означает, что результат будет отличаться при запуске в разных часовых поясах.
Дерек Махар
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);

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

1: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 используйте Android-версию ThreeTen Backport. Это называется ThreeTenABP. И убедитесь, что вы импортируете классы даты и времени из org.threeten.bpподпакетов.

связи

Оле В.В.
источник
5

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

23: 59: 58: 999 - 86398999

и тогда

С 86398999 по 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;
    }
}
Мензио Лука Фабрицио
источник
Я проголосовал за это решение. Просто поставьте точку между секундами и миллисекундами. И я не знаю, почему обработка времени и даты оооочень сложна в Java. Наиболее используемые функции должны быть уже доступны и частью класса.
Барух Атта
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)));

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

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

00: 10: 15,605

Омид Наджи
источник
5

Ответ, помеченный как правильный, содержит небольшую ошибку,

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);
Jorgesys
источник
4

Я попытался, как показано в первом ответе. Это работает, но минус привел меня в замешательство. Мой ответ от 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])
}
Леоновым
источник
3

Для Котлина

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миллисекунды

Кишан Соланки
источник
1

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

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

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

анонимный
источник