52

I need to go from milliseconds to a tuple of (hour, minutes, seconds, milliseconds) representing the same amount of time. E.g.:

10799999ms = 2h 59m 59s 999ms

The following pseudo-code is the only thing I could come up with:

# The division operator below returns the result as a rounded down integer
function to_tuple(x):
    h = x / (60*60*1000)
    x = x - h*(60*60*1000)
    m = x / (60*1000)
    x = x - m*(60*1000)
    s = x / 1000
    x = x - s*1000
    return (h,m,s,x)

I'm sure it must be possible to do it smarter/more elegant/faster/more compact.

2
  • you could use the modulo operator ( % in C and friends ) to slightly simplify the calculations of x ( eg x = x % (60*60*1000) )
    – fvu
    Commented Jun 3, 2012 at 21:38
  • Make sure you don't have such functionality already in standard library of language you use. Commented Jun 3, 2012 at 21:47

12 Answers 12

153

Here is how I would do it in Java:

int seconds = (int) (milliseconds / 1000) % 60 ;
int minutes = (int) ((milliseconds / (1000*60)) % 60);
int hours   = (int) ((milliseconds / (1000*60*60)) % 24);
4
  • 3
    it's worth to use TimeUnit in java to make code more readable. Commented Jun 3, 2012 at 21:44
  • 10
    long millis = 12884983; System.out.println(((millis / (1000 * 60)) % 60)); System.out.println(java.util.concurrent.TimeUnit.MILLISECONDS.toMinutes(millis)); output: 34 | 214
    – JBoy
    Commented Oct 31, 2014 at 9:45
  • That hours calculation is for time of day courtesy of the % 24, if you remove the % 24 you'll get just a number of hours. You'll see the difference if the total hours is 24 or more, which it isn't in the OPs sample input.
    – Ed Morton
    Commented May 19, 2023 at 14:58
  • 1
    @Alex W : so you're performing 6 divisions when at most 3 are needed ? Commented May 20, 2023 at 3:02
7

Good question. Yes, one can do this more efficiently. Your CPU can extract both the quotient and the remainder of the ratio of two integers in a single operation. In <stdlib.h>, the function that exposes this CPU operation is called div(). In your psuedocode, you'd use it something like this:

function to_tuple(x):
    qr = div(x, 1000)
    ms = qr.rem
    qr = div(qr.quot, 60)
    s  = qr.rem
    qr = div(qr.quot, 60)
    m  = qr.rem
    h  = qr.quot

A less efficient answer would use the / and % operators separately. However, if you need both quotient and remainder, anyway, then you might as well call the more efficient div().

0
5

Maybe can be shorter an more elegant. But I did it.

public String getHumanTimeFormatFromMilliseconds(String millisecondS){
    String message = "";
    long milliseconds = Long.valueOf(millisecondS);
    if (milliseconds >= 1000){
        int seconds = (int) (milliseconds / 1000) % 60;
        int minutes = (int) ((milliseconds / (1000 * 60)) % 60);
        int hours = (int) ((milliseconds / (1000 * 60 * 60)) % 24);
        int days = (int) (milliseconds / (1000 * 60 * 60 * 24));
        if((days == 0) && (hours != 0)){
            message = String.format("%d hours %d minutes %d seconds ago", hours, minutes, seconds);
        }else if((hours == 0) && (minutes != 0)){
            message = String.format("%d minutes %d seconds ago", minutes, seconds);
        }else if((days == 0) && (hours == 0) && (minutes == 0)){
            message = String.format("%d seconds ago", seconds);
        }else{
            message = String.format("%d days %d hours %d minutes %d seconds ago", days, hours, minutes, seconds);
        }
    } else{
        message = "Less than a second ago.";
    }
    return message;
}
4

not really eleganter, but a bit shorter would be

function to_tuple(x):
   y = 60*60*1000
   h = x/y
   m = (x-(h*y))/(y/60)
   s = (x-(h*y)-(m*(y/60)))/1000
   mi = x-(h*y)-(m*(y/60))-(s*1000)

   return (h,m,s,mi)
1
milliseconds = 12884983  // or x milliseconds
hr = 0
min = 0
sec = 0 
day = 0
while (milliseconds >= 1000) {
  milliseconds = (milliseconds - 1000)
  sec = sec + 1
  if (sec >= 60) min = min + 1
  if (sec == 60) sec = 0
  if (min >= 60) hr = hr + 1
  if (min == 60) min = 0
  if (hr >= 24) {
    hr = (hr - 24)
    day = day + 1
  }
}

I hope that my shorter method will help you

0
milliseconds = x
total = 0
while (milliseconds >= 1000) {
  milliseconds = (milliseconds - 1000)
  total = total + 1
}
hr = 0
min = 0
while (total >= 60) {
  total = total - 60
  min = min + 1
  if (min >= 60) hr = hr + 1
  if (min == 60) min = 0
}
sec = total

This is on groovy, but I thing that this is not problem for you. Method work perfect.

0
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class MyTest {

    public static void main(String[] args) {
        long seconds = 360000;

        long days = TimeUnit.SECONDS.toDays(seconds);
        long hours = TimeUnit.SECONDS.toHours(seconds - TimeUnit.DAYS.toSeconds(days));

        System.out.println("days: " + days);
        System.out.println("hours: " + hours);
    }
}
0

Arduino (c++) version based on Valentinos answer

unsigned long timeNow = 0;
unsigned long mSecInHour = 3600000;
unsigned long TimeNow =0;
int millisecs =0;  
int seconds = 0;
byte minutes = 0;
byte hours = 0;

void setup() {
Serial.begin(9600);
Serial.println (""); // because arduino monitor gets confused with line 1
Serial.println ("hours:minutes:seconds.milliseconds:");
}

void loop() {
TimeNow = millis(); 
hours = TimeNow/mSecInHour;
minutes = (TimeNow-(hours*mSecInHour))/(mSecInHour/60);
seconds = (TimeNow-(hours*mSecInHour)-(minutes*(mSecInHour/60)))/1000;
millisecs = TimeNow-(hours*mSecInHour)-(minutes*(mSecInHour/60))-       (seconds*1000);

Serial.print(hours);  
Serial.print(":");
Serial.print(minutes);
Serial.print(":"); 
Serial.print(seconds); 
Serial.print("."); 
Serial.println(millisecs); 
}
0

Just an other java example:

long dayLength = 1000 * 60 * 60 * 24;
long dayMs = System.currentTimeMillis() % dayLength;
double percentOfDay = (double) dayMs / dayLength;
int hour = (int) (percentOfDay * 24);
int minute = (int) (percentOfDay * 24 * 60) % 60;
int second = (int) (percentOfDay * 24 * 60 * 60) % 60;

an advantage is that you can simulate shorter days, if you adjust dayLength

0

Kotlin example with leading zero's for hours/minutes/seconds smaller then 10. So you end up with the same duration in lenght, if you want to use the value as a String in a UI for instance.

This gives 01:57:01 instead of 1:57:1 which might be confusing for hh:mn:ss annotation.

val timeInMilliSec = 45600030

val hours = timeInMilliSec.div(3600).rem(24)
val minutes = timeInMilliSec.div(60).rem(60)
val seconds = timeInMilliSec.rem(60)

val hoursFormatted = if (hours < 10) "0$hours" else "$hours"
val minutesFormatted = if (minutes < 10) "0$minutes" else "$minutes"
val secondsFormatted = if (seconds < 10) "0$seconds" else "$seconds"

"$hoursFormatted:$minutesFormatted:$secondsFormatted"

                        
0

just use a loop-less unified formula without hard-coded constants or the modulo % operator, which then you can quickly verify via bc :


echo '10799999
      45600030
      12884983' | gawk -p- -be '

function ____(__, _, ___) {  

    ms =  __ - (___ = ((_+= _^= _<_) + _^++_)^_) * \
   ((s = (__ = int(__/___)) - (_+= _*_*(_ += _)) * (\       
     m = (__ = int(__ /_) ) - _ * (\
     h =       int(__/_) )) - _ * h * _) + _ * (h * _ + m))
} { 
     ____($0)

     printf("\t%2dh:%.2dm:%.2d.%.3ds\n", h, m, s, ms) 
}'

     2h:59m:59.999s
    12h:40m:00.030s
     3h:34m:44.983s

echo 'obase=60; 10799.999 ; 45600.030; 12884.983' | bc

 1   02 59 59.59 56
 2   12 40 00.01 48
 3   03 34 44.58 58

minor caveats

— durations of 1 day and beyond will all be accumulated at the h(our)s variable instead of being % 24 hrs

— doesn't handle leap seconds, since the formula is only for time units conversion


the fully hard-coded version would resemble :

function ms_to_hms(_) {

     ms = (_)      - 1000 * \
   ( (s = (_ = int(_/1000) ) - 60 * (\
      m = (_ = int(_/  60) ) - 60 * (\
      h =      int(_/  60))) - 60 * 60 * h ) + 60 * (60 * h + m))
}
0

This solution is for convert milliseconds to remaining hours, minutes, seconds and milliseconds.

const convertMilliSecondToReadableHours = (milliSecond) => {
    const hours = Math.floor(milliSecond / (1000 * 60 * 60));
    let remainingMilliSecond = milliSecond - (hours * 1000 * 60 * 60);
    const minutes = Math.floor(remainingMilliSecond / (1000 * 60));
    remainingMilliSecond = remainingMilliSecond - (minutes * 1000 * 60);
    const seconds = Math.floor(remainingMilliSecond / 1000);
    remainingMilliSecond = remainingMilliSecond - (seconds * 1000);
    const readableHours = `${hours} hours ${minutes} minutes ${seconds} seconds ${remainingMilliSecond} milliseconds`
    // console.log('readableHours :: ', readableHours);
    return readableHours;
};

const readableHoursFormat = convertMilliSecondToReadableHours(64163598)

console.log('milliseconds :: ', 64163598)
console.log('readableHoursFormat :: ', readableHoursFormat)

Not the answer you're looking for? Browse other questions tagged or ask your own question.