143

I am trying to convert a long value (number of milliseconds elapsed from 1/1/1970 i.e. Epoch) to time of format h:m:s:ms.

The long value I use as timestamp, I get from the field timestamp of a logging event from log4j.

So far I've tried the following and it fails:

logEvent.timeStamp/ (1000*60*60)
TimeUnit.MILLISECONDS.toMinutes(logEvent.timeStamp)

but I get incorrect value:

1289375173771 for logEvent.timeStamp
358159  for logEvent.timeStamp/ (1000*60*60) 
21489586 for TimeUnit.MILLISECONDS.toMinutes(logEvent.timeStamp)

How do I go about this?

nabster
  • 1,561
  • 2
  • 20
  • 32
Cratylus
  • 52,998
  • 69
  • 209
  • 339

10 Answers10

206

Try this:

Date date = new Date(logEvent.timeSTamp);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateFormatted = formatter.format(date);

See SimpleDateFormat for a description of other format strings that the class accepts.

See runnable example using input of 1200 ms.

Derek Mahar
  • 27,608
  • 43
  • 124
  • 174
manolowar
  • 6,772
  • 5
  • 23
  • 18
  • 9
    Comment: HH will print the hour at that date (0-23), not the total amount of hours elapsed since 1970. Just sayin'. – JohnyTex Aug 19 '14 at 11:41
  • 4
    And don't forget. Old SimpleDateFormat can't be used multithreaded. – keiki Apr 01 '16 at 10:30
  • to import `SimpleDateFormat`, use the import as follows: `import java.text.*;` – Naveen Kumar R B Jan 04 '17 at 11:06
  • 3
    FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). See:https://stackoverflow.com/a/4142428/642706 – Basil Bourque May 07 '18 at 20:06
  • 1
    whats the type of logevent?Can you please put in the Question? – Raulp Feb 20 '19 at 08:32
150
long millis = durationInMillis % 1000;
long second = (durationInMillis / 1000) % 60;
long minute = (durationInMillis / (1000 * 60)) % 60;
long hour = (durationInMillis / (1000 * 60 * 60)) % 24;

String time = String.format("%02d:%02d:%02d.%d", hour, minute, second, millis);
Derek Mahar
  • 27,608
  • 43
  • 124
  • 174
Brajendra Pandey
  • 2,280
  • 1
  • 16
  • 22
  • 15
    I like your solution better than the accepted answer as it is a bit more explicit and does not suffer problems with locale. Though you miss the final part: millis = millis % 1000, which would rightly put milliseconds at the end of the formatted string. – Ondrej Burkert Jan 17 '14 at 15:08
  • 1
    Multiplications and division are associative. (millis / (1000 * 60)) is the same as (millis / 1000 * 60) – Wesley De Keirsmaeker Mar 11 '14 at 09:50
  • 8
    @WesleyDeKeirsmaeker, in general, readability is more important than conciseness. – Alphaaa Apr 14 '14 at 15:48
  • 2
    why remainder with 24 for hours ? – baboo Sep 11 '14 at 10:42
  • 3
    Division is not associative: 50000 / (1000 * 60) = 0.8333333333 while 50000 / 1000 * 60= 3000. – farnett Feb 16 '15 at 22:05
  • 3
    'millis = millis % 1000' is missing :D\n and if you need days, here you go: 'long days = (millis /(1000*60*60*24));' – Adreamus Sep 25 '15 at 00:18
  • What about leap seconds? – Timmmm Jun 03 '16 at 08:57
  • 1
    @WesleyDeKeirsmaeker you are wrong; in Java, (millis / 1000 * 60) is the same as ((millis / 1000) * 60), NOT (millis / (1000 * 60)) – Lambart Jul 12 '16 at 18:46
  • if 'hours' is the biggest partition you will use, and you won't use 'days' - in this case remove "% 24" from the line "long hour = (millis / (1000 * 60 * 60)) % 24;" – Kirill Karmazin Mar 19 '17 at 19:52
  • @Alphaaa Hopefully you have realized since that comment that readability is only preferred when it does not sacrifice conciseness. I would hate to think you have been publishing inaccurate code for the sake of source readability all this time. – Abandoned Cart May 15 '17 at 17:44
  • 1
    @LoungeKatt I don't understand why you define more readable code as "inaccurate". I remember this passage from Norvig's "Artificial Intelligence: A Modern Approach" where he was illustrating that in boolean logic NOT+AND or NOT+OR are sufficient... but we write expressions using NOT+AND+OR "because readability is often more important than conciseness" (don't remember the exact words). – Alphaaa May 17 '17 at 08:05
  • @Alphaaa TL;DR I do not define more readable code as inaccurate. I define elaborate explanations for simple tasks as prone to error. – Abandoned Cart May 17 '17 at 19:41
  • i love this answer! – 최봉재 Nov 16 '17 at 05:35
  • For second you can simply use long second = (durationInMillis / 1000), we do not need %60 at the end, same goes for minutes we do not need %60 – Sahbaz Dec 27 '18 at 03:41
  • @Sahbaz I don't think you understand the purpose of the code, the `% 60` is to represent the remainder of seconds, if the code was your way, you could have the following: `1 hours and 78 minutes`, with this code, the hours and minutes wraps back to zero so you have `2 hours 18 minutes`. – Zintom Jan 17 '21 at 14:51
41

I'll show you three ways to (a) get the minute field from a long value, and (b) print it using the Date format you want. One uses java.util.Calendar, another uses Joda-Time, and the last uses the java.time framework built into Java 8 and later.

The java.time framework supplants the old bundled date-time classes, and is inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.

The java.time framework is the way to go when using Java 8 and later. Otherwise, such as Android, use Joda-Time. The java.util.Date/.Calendar classes are notoriously troublesome and should be avoided.

java.util.Date & .Calendar

final long timestamp = new Date().getTime();

// with java.util.Date/Calendar api
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timestamp);
// here's how to get the minutes
final int minutes = cal.get(Calendar.MINUTE);
// and here's how to get the String representation
final String timeString =
    new SimpleDateFormat("HH:mm:ss:SSS").format(cal.getTime());
System.out.println(minutes);
System.out.println(timeString);

Joda-Time

// with JodaTime 2.4
final DateTime dt = new DateTime(timestamp);
// here's how to get the minutes
final int minutes2 = dt.getMinuteOfHour();
// and here's how to get the String representation
final String timeString2 = dt.toString("HH:mm:ss:SSS");
System.out.println(minutes2);
System.out.println(timeString2);

Output:

24
09:24:10:254
24
09:24:10:254

java.time

long millisecondsSinceEpoch = 1289375173771L;
Instant instant = Instant.ofEpochMilli ( millisecondsSinceEpoch );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , ZoneOffset.UTC );

DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "HH:mm:ss:SSS" );
String output = formatter.format ( zdt );

System.out.println ( "millisecondsSinceEpoch: " + millisecondsSinceEpoch + " instant: " + instant + " output: " + output );

millisecondsSinceEpoch: 1289375173771 instant: 2010-11-10T07:46:13.771Z output: 07:46:13:771

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • 1
    Is there any performance reason or any other reason, I should preffer Joda over Calendar? – Cratylus Nov 10 '10 at 08:59
  • 1
    in simple cases like this, no. In general: Joda's api is designed better. e.g. java Dates are mutable Joda DateTimes are not. Joda is also more programmer friendly, you can access almost all functionality from the DateTime class without having to convert back and forth between Date and Calendar – Sean Patrick Floyd Nov 10 '10 at 09:06
  • does it have any dependencies I should be aware? – Cratylus Nov 10 '10 at 09:33
  • No dependencies, it's a standalone library – Sean Patrick Floyd Nov 10 '10 at 09:37
  • 2
    Good answer, but I suggest also specifying the time zone rather than rely implicitly on the JVM’s current default time zone. So the call to constructor of DateTime would have a second argument, a [`DateTimeZone`](http://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeZone.html) object. Like this: `new DateTime( timestamp, DateTimeZone.forID( "America/Montreal" ) )` – Basil Bourque Sep 09 '14 at 00:29
  • 2
    @Cratylus The java.time classes supplant *both* Joda-Time and the old legacy date-time classes bundled with Java. Joda-Time inspired the java.time classes, both projects led by the same man, Stephen Colbourne. – Basil Bourque Dec 02 '16 at 06:36
22

It is possible to use apache commons (commons-lang3) and its DurationFormatUtils class.

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>3.1</version>
</dependency>

For example:

String formattedDuration = DurationFormatUtils.formatDurationHMS(12313152);
// formattedDuration value is "3:25:13.152"
String otherFormattedDuration = DurationFormatUtils.formatDuration(12313152, DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN);
// otherFormattedDuration value is "P0000Y0M0DT3H25M13.152S"

Hope it can help ...

YoCha
  • 231
  • 2
  • 4
8
long second = TimeUnit.MILLISECONDS.toSeconds(millis);
long minute = TimeUnit.MILLISECONDS.toMinutes(millis);
long hour = TimeUnit.MILLISECONDS.toHours(millis);
millis -= TimeUnit.SECONDS.toMillis(second);
return String.format("%02d:%02d:%02d:%d", hour, minute, second, millis);
Lo Ka
  • 107
  • 1
  • 3
  • 2
    This doesn't seem correct. Does `TimeUnit.MILLISECONDS.toSeconds()`, for example, convert milliseconds to the same duration in seconds or the remaining seconds after subtracting hours and minutes? The solution requires the latter. – Derek Mahar Jul 05 '18 at 16:34
  • This method is incorrect, it returns **431220:25873204:1552392282:0** if I want to convert the date of **12 march 2019** at **13h04 42s** – 0ddlyoko Mar 12 '19 at 12:07
  • My answer below is similar to this, but fixes the error. – Joel Richard Koett Mar 01 '21 at 23:33
6
public static String timeDifference(long timeDifference1) {
long timeDifference = timeDifference1/1000;
int h = (int) (timeDifference / (3600));
int m = (int) ((timeDifference - (h * 3600)) / 60);
int s = (int) (timeDifference - (h * 3600) - m * 60);

return String.format("%02d:%02d:%02d", h,m,s);
Vivek Pal
  • 181
  • 1
  • 4
5

Try this:

    String sMillis = "10997195233";
    double dMillis = 0;

    int days = 0;
    int hours = 0;
    int minutes = 0;
    int seconds = 0;
    int millis = 0;

    String sTime;

    try {
        dMillis = Double.parseDouble(sMillis);
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }


    seconds = (int)(dMillis / 1000) % 60;
    millis = (int)(dMillis % 1000);

    if (seconds > 0) {
        minutes = (int)(dMillis / 1000 / 60) % 60;
        if (minutes > 0) {
            hours = (int)(dMillis / 1000 / 60 / 60) % 24;
            if (hours > 0) {
                days = (int)(dMillis / 1000 / 60 / 60 / 24);
                if (days > 0) {
                    sTime = days + " days " + hours + " hours " + minutes + " min " + seconds + " sec " + millis + " millisec";
                } else {
                    sTime = hours + " hours " + minutes + " min " + seconds + " sec " + millis + " millisec";
                }
            } else {
                sTime = minutes + " min " + seconds + " sec " + millis + " millisec";
            }
        } else {
            sTime = seconds + " sec " + millis + " millisec";
        }
    } else {
        sTime = dMillis + " millisec";
    }

    System.out.println("time: " + sTime);
LeoZao
  • 59
  • 1
  • 1
4

Doing

logEvent.timeStamp / (1000*60*60)

will give you hours, not minutes. Try:

logEvent.timeStamp / (1000*60)

and you will end up with the same answer as

TimeUnit.MILLISECONDS.toMinutes(logEvent.timeStamp)
Nico Huysamen
  • 10,217
  • 9
  • 62
  • 88
1
long hours = TimeUnit.MILLISECONDS.toHours(timeInMilliseconds);
long minutes = TimeUnit.MILLISECONDS.toMinutes(timeInMilliseconds - TimeUnit.HOURS.toMillis(hours));
long seconds = TimeUnit.MILLISECONDS.toSeconds(timeInMilliseconds - TimeUnit.HOURS.toMillis(hours) - TimeUnit.MINUTES.toMillis(minutes));
long milliseconds = timeInMilliseconds - TimeUnit.HOURS.toMillis(hours) - TimeUnit.MINUTES.toMillis(minutes) - TimeUnit.SECONDS.toMillis(seconds);

return String.format("%02d:%02d:%02d:%d", hours, minutes, seconds, milliseconds);
1

I wanted to only show the relevant part of the time. So, always show seconds, but only show minutes/hours/days if there are any.

Also, optionally show milliseconds.

And I was using GWT, so I couldn't use String.format.

So, if this is you too, here is the code.

public static String formatTimeFromMs(long timeInMs, boolean showMs) {
    boolean negative = timeInMs < 0;

    timeInMs = Math.abs(timeInMs);

    StringBuffer result = new StringBuffer();
    long seconds = (timeInMs / 1000) % 60;
    long minutes = (timeInMs / (1000 * 60)) % 60;
    long hours = (timeInMs / (1000 * 60 * 60)) % 24;
    long days = (timeInMs / (1000 * 60 * 60 * 24));

    if (days > 0) {
        result.append(days + "d ");
    }
    
    if (hours > 0) {
        if (hours < 10 && result.length() > 0) {
            result.append("0");
        }
        result.append(hours + ":");
    }
    else if (result.length() > 0) {
        result.append("00:");
    }

    if (minutes > 0) {
        if (minutes < 10 && result.length() > 0) {
            result.append("0");
        }
        result.append(minutes + ":");
    }
    else if (result.length() > 0) {
        result.append("00:");
    }

    if (seconds > 0) {
        if (seconds < 10 && result.length() > 0) {
            result.append("0");
        }
        result.append(seconds);
    }
    else if (result.length() > 0) {
        result.append("00");
    }
    else {
        result.append("0");
    }

    if (showMs) {
        long millis = timeInMs % 1000;
        
        if (millis < 10) {
            result.append(".00" + millis);
        }
        else if (millis < 100) {
            result.append(".0" + millis);
        }
        else {
            result.append("." + millis);
        }
    }

    if (negative) {
        result.insert(0, "-");
    }

    return result.toString();
}
Craigo
  • 3,384
  • 30
  • 22