How to convert milliseconds to "hh:mm:ss" format?
Asked Answered
C

19

228

I'm confused. After stumbling upon this thread, I tried to figure out how to format a countdown timer that had the format hh:mm:ss.

Here's my attempt -

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

So, when I try a value like 3600000ms, I get 01:59:00, which is wrong since it should be 01:00:00. Obviously there's something wrong with my logic, but at the moment, I cannot see what it is!

Can anyone help?

Edit -

Fixed it. Here's the right way to format milliseconds to hh:mm:ss format -

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

The problem was this TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)). It should have been this TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)) instead.

Canikin answered 27/1, 2012 at 0:1 Comment(1)
3,600,000 milliseconds is 3,600 seconds, or 60 minutes, or 1 hour. It shouldn't be 00:59:59, it should be 01:00:00.Catalan
A
420

You were really close:

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

You were converting hours to millisseconds using minutes instead of hours.

BTW, I like your use of the TimeUnit API :)

Here's some test code:

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

Output:

01:00:00

I realised that my code above can be greatly simplified by using a modulus division instead of subtraction:

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

Still using the TimeUnit API for all magic values, and gives exactly the same output.

Amass answered 27/1, 2012 at 0:11 Comment(11)
It is not a good idea to reinvent the wheel! Triton Man's answer is better solution.Madame
@محمدباقر But the other answer uses an external library, whereas my code uses the core JDK only. It depends on what your needs are - for example you may not be able to use an external library. The other answer is good though.Amass
How 'bout when it exceeds 365 days? Can you do the equivalent years? Thanks.Heurlin
@Heurlin what do you mean? Can you give sample input and output please?Amass
@محمدباقر I needed to add Days and extra text to the string. in this answer, easily i inserted my text between the %02d and finished, what about doing this with the answer you suggested is better than this ?Octagonal
Given time in milliseconds, say the time is not upto an hour, it returns for example "00:15:23". Is there any way to make it remove zeros if empty? For example to return "15:23" instead of "00:15:23".Winograd
@Ozuf add .replaceAll("^00:", "") or .replaceAll("^00:(00:)?", "") to remove minutes as well as hours if both are zero.Amass
Thanks but what happens if the time is "00:15:00" or "10:00:23"?Winograd
@Ozuf you get "15:00" and "10:00:23" respectively; only leading zeros are removed, due to the match being anchored to start of input by ^.Amass
Thanks a million :D. Please can you update the answer so that others can easily see it?Winograd
int hrs = (int) TimeUnit.MILLISECONDS.toHours(miliSeconds) % 24; int min = (int) TimeUnit.MILLISECONDS.toMinutes(miliSeconds) % 60; int sec = (int) TimeUnit.MILLISECONDS.toSeconds(miliSeconds) % 60; return String.format("%02d:%02d:%02d", hrs, min, sec);Huppert
M
98

The generic method for this is fairly simple:

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);
}
Martyrdom answered 27/1, 2012 at 0:7 Comment(4)
@Javaman59, did you mean String.format("% 02 d:%02d:%02d", h,m,s)?Heurlin
@KarenAnne. That depends on whether you want, for example, "03:59:59" or "3:59:59".Meaghan
The time's in milliseconds, you need to multiply seconds with 1000Halfcaste
author asked about milliseconds, not seconds!Kisung
B
71

If you are using apache commons:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");
Bertina answered 1/5, 2013 at 18:55 Comment(3)
Shortcut : DurationFormatUtils.formatDurationHMS(timeInMS);Jacie
@Jorgesys Why are they obsolete?Mothy
they aren't obsolete.Bertina
P
31

I used this:

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

See description of class Formatter.

See runnable example using input of 2400 ms.

Planar answered 20/10, 2015 at 21:35 Comment(3)
It seems not working, I simply test it by pass 100, 1000, 1200 and it responding as 05:30:00 , 05:30:01, 05:30:01.An
@CoDe, it works for your time zone. You must be in a different time zone than UTC. String.format() is time zone dependent. The ideal correct answer, however, should be time zone independent.Ade
@CoDe, it is showing times that correspond to your time zone which must be different than UTC. String.format() is time zone dependent. The ideal correct answer, however, should be time zone independent.Ade
G
30
// 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 );

You can also use new DateTime API

     var formatted = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
            .withZone(ZoneId.of("UTC"))
            .format(Instant.ofEpochMilli(millis));
Gentoo answered 20/6, 2014 at 12:15 Comment(3)
This would produce incorrect results for amounts of time more than a day. It would wrap the number of hours from 23 back to 0, which probably isn't desirable here.Jeroldjeroma
No buddy... I think it would still work the same. try with today dateGentoo
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa"); in case someone wants in 12 hours format with am/pmMorisco
E
16
DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);
Epstein answered 27/1, 2012 at 0:12 Comment(2)
Same answer as #9027817 with same problem for duration above 1 dayPest
It's also dependent on time zone which means the result will differ when run in different time zones.Ade
B
14

this worked for me, with 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"
            }
        }
    }
Basket answered 31/10, 2018 at 19:4 Comment(1)
Worked perfectly for me. This should be the best answer since it handles zero hourPlanography
E
11

Test results for the 4 implementations

Having to do a lot of formatting for huge data, needed the best performance, so here are the (surprising) results:

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

Durations:

  • combinationFormatter: 196 millis
  • formatDuration: 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(); 
     }
    
Escobedo answered 11/2, 2014 at 12:17 Comment(3)
how reliable are metrics like these? I've never really understood the process.Canikin
In my situation where some thousands of objects are created in succession, this test I think is pretty useful. Okay not setting just some strings, but creating objects which have one field a formatted string.Escobedo
@marius you went to the trouble to use StringBuilder then make the mistake of using "0"+number kind of "ruins" it. @Canikin JVM's GC is extremely good at allocating and collecting lots of short-lived objects, no worries there. I went with String.format no leading-zero logic to deal with.Brok
D
11

Java 9

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

This prints:

01:00:00

You are doing right in letting library methods do the conversions involved for you. java.time, the modern Java date and time API, or more precisely, its Duration class does it more elegantly and in a less error-prone way than TimeUnit.

The toMinutesPart and toSecondsPart methods I used were introduced in Java 9.

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

The output is the same as above.

Question: How can that work in Java 6 and 7?

  • In Java 8 and later and on newer Android devices (from API level 26, I’m told) java.time comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Delmydeloach answered 20/5, 2018 at 20:13 Comment(0)
A
9

The answer marked as correct has a little mistake,

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

for example this is an example of the value that i get:

417474:44:19

This is the solution to get the right format is:

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

getting as a result a correct format:

18:44:19

other option to get the format hh:mm:ss is just :

   Date myDate = new Date(timeinMillis);
   SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
   String myTime = formatter.format(myDate);
Altricial answered 16/8, 2017 at 18:46 Comment(0)
G
8

Going by Bohemian's answer we need need not use TimeUnit to find a known value. Much more optimal code would be

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

Hope it helps

Gitt answered 3/5, 2016 at 9:29 Comment(3)
Like your answer the most! Just simple math. Btw in my case I added the milliseconds to the end millisLeft%1000/10 so we get the format hour:minutes:seconds:millisecondsPalembang
@LêQuangDuy i need milliseconds in 3 digits like 01:24:51,123 but your is chopping 3 at last what to do ?Dion
@naanu just use millisLeft%1000Palembang
T
8
 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
}
Thecla answered 8/9, 2016 at 14:19 Comment(1)
Answer is dependent on time zone which means the result will differ when run in different time zones.Ade
M
7
        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

Example: 615605 Millisecend

00:10:15.605

Mope answered 20/7, 2016 at 7:12 Comment(0)
R
5

The code below does the conversion in both way

23:59:58:999 to 86398999

and than

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;
    }
}
Ranitta answered 28/3, 2015 at 9:44 Comment(1)
I upvoted this solution. Just put a dot between sec and mls. And I don't know why times and date handling is sooooo difficult in Java. The most used functions should be already available and part of the class.Mattock
V
4

I tried as shown in the first answer. It works, but minus brought me into confusion. My answer by 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])
}
Verb answered 25/7, 2013 at 14:46 Comment(0)
R
4

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

where, milSecs is milliseconds

Rosemaria answered 21/5, 2018 at 6:2 Comment(0)
S
2

In kotlin

private fun stringForTime(timeMs: Int): String {
    val totalSeconds = timeMs / 1000
    val seconds = totalSeconds % 60
    val minutes = totalSeconds / 60 % 60
    val hours = totalSeconds / 3600
    return if (hours > 0) {
        "%d:%02d:%02d".format(hours, minutes, seconds)
    } else {
        "%02d:%02d".format(minutes, seconds)
    }
}

In Java

private String stringForTime(int timeMs) {
    int totalSeconds = timeMs / 1000;
    int seconds = totalSeconds % 60;
    int minutes = totalSeconds / 60 % 60;
    int hours = totalSeconds / 3600;
    return hours > 0 ? String.format(Locale.getDefault(),
            "%d:%02d:%02d",
            hours,
            minutes,
            seconds) :
            String.format(Locale.getDefault(),
                    "%02d:%02d",
                    minutes,
                    seconds);
}
Slavery answered 15/2, 2022 at 7:49 Comment(0)
F
1

Well, you could try something like this, :

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

to convert milliseconds to a time value

Floweret answered 27/1, 2012 at 0:12 Comment(0)
S
1

In Kotlin:

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)
}
Sugden answered 29/6, 2021 at 8:32 Comment(2)
This question asked in JAVA, you should answer it in Java please.Filler
This question is 9 years old, and Kotlin is "designed to interoperate fully with Java", so I think this question could be expanded to allow for new technologies in the same sphere. Comments like this drive people away from SO.Tillion

© 2022 - 2025 — McMap. All rights reserved.