How to convert milliseconds to "hh:mm:ss" format?

JavaTime FormatCountdowntimer

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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

Solution 3 - Java

If you are using apache commons:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");

Solution 4 - Java

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.

Solution 5 - Java

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

Solution 6 - Java

DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);

Solution 7 - Java

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

Solution 8 - Java

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

Solution 9 - Java

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.

Solution 10 - Java

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

Solution 11 - Java

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

Solution 12 - Java

        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

Solution 13 - Java

 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
}

Solution 14 - Java

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

Solution 15 - Java

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

Solution 16 - Java

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

Solution 17 - Java

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

Solution 18 - Java

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

Solution 19 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmreView Question on Stackoverflow
Solution 1 - JavaBohemianView Answer on Stackoverflow
Solution 2 - JavaArets PaeglisView Answer on Stackoverflow
Solution 3 - JavaRocky PulleyView Answer on Stackoverflow
Solution 4 - JavaZuluMView Answer on Stackoverflow
Solution 5 - JavaVinay LodhaView Answer on Stackoverflow
Solution 6 - JavaGabriel BelingueresView Answer on Stackoverflow
Solution 7 - JavaDevixView Answer on Stackoverflow
Solution 8 - JavaMariusAView Answer on Stackoverflow
Solution 9 - JavaOle V.V.View Answer on Stackoverflow
Solution 10 - JavaJorgesysView Answer on Stackoverflow
Solution 11 - JavaAalinView Answer on Stackoverflow
Solution 12 - JavaOmid NajiView Answer on Stackoverflow
Solution 13 - JavactuView Answer on Stackoverflow
Solution 14 - JavaMenzio Luca FabrizioView Answer on Stackoverflow
Solution 15 - JavaleonovView Answer on Stackoverflow
Solution 16 - JavaKishan SolankiView Answer on Stackoverflow
Solution 17 - JavaanonymousView Answer on Stackoverflow
Solution 18 - JavaLonyView Answer on Stackoverflow
Solution 19 - JavaUdaraWanasingheView Answer on Stackoverflow