How to get milliseconds from LocalDateTime in Java 8
Asked Answered
B

15

431

I am wondering if there is a way to get current milliseconds since 1-1-1970 (epoch) using the new LocalDate, LocalTime or LocalDateTime classes of Java 8.

The known way is below:

long currentMilliseconds = new Date().getTime();

or

long currentMilliseconds = System.currentTimeMillis();
Belted answered 29/5, 2014 at 22:57 Comment(6)
What's wrong with System.currentTimeMillis()?Dirndl
@DavidWallace He's trying to get the time of a Date, not the current time?Lophophore
"... a way to get current milliseconds ..."Dirndl
milliseconds counting from 1-1-1970. I was wandering if there is a method to get them using the new classes of Java 8 LocalDate, LocalTime and LocalDateTime, cause i didn't found one.Belted
My understanding of the purpose for those classes is that it is a "human-focused" understanding of time, and currentTimeMillis would be irrelevant in that context. Think Calendar + Wall-clock with really good precision, and no concerns about time zones and locality. So there's no way to get back to "UTC Time" from a LocalTimeNegative
Similar Question: How to covert LocalDateTime to a Long? with one good Answer.Cinquecento
M
453

I'm not entirely sure what you mean by "current milliseconds" but I'll assume it's the number of milliseconds since the "epoch," namely midnight, January 1, 1970 UTC.

If you want to find the number of milliseconds since the epoch right now, then use System.currentTimeMillis() as Anubian Noob has pointed out. If so, there's no reason to use any of the new java.time APIs to do this.

However, maybe you already have a LocalDateTime or similar object from somewhere and you want to convert it to milliseconds since the epoch. It's not possible to do that directly, since the LocalDateTime family of objects has no notion of what time zone they're in. Thus time zone information needs to be supplied to find the time relative to the epoch, which is in UTC.

Suppose you have a LocalDateTime like this:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

You need to apply the time zone information, giving a ZonedDateTime. I'm in the same time zone as Los Angeles, so I'd do something like this:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

Of course, this makes assumptions about the time zone. And there are edge cases that can occur, for example, if the local time happens to name a time near the Daylight Saving Time (Summer Time) transition. Let's set these aside, but you should be aware that these cases exist.

Anyway, if you can get a valid ZonedDateTime, you can convert this to the number of milliseconds since the epoch, like so:

long millis = zdt.toInstant().toEpochMilli();
Mariammarian answered 30/5, 2014 at 1:46 Comment(7)
Note that ZonedDateTime already has the getEpochSecond method (via ChronoZonedDateTime default). No need for the Instant.Erebus
Sure, if all you need is seconds, not milliseconds.Mariammarian
Ah well, I was imprecise: ZonedDateTime also has Instants getNano method, so wouldn't you be able to just replace inst with zdt in your example?Erebus
Argh. ChronoZonedDateTime has toEpochSecond not getEpochSecond. So yes I think this allows skipping the use of Instant. I'll test and update.Mariammarian
Avoid the maths on nanos by using zdt.get(ChronoField.MILLI_OF_SECOND). Avoid all the maths by using zdt.toInstant().toEpochMilli()Ferous
@Ferous zdt.getLong instead of just get (which returns int)Bathos
LocalDateTime.now().toInstant(OffsetDateTime.now().offset) there is also another solution without using ZonePeroxidize
C
147

What I do so I don't specify a time zone is,

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

gives

ldt 1424812121078 
ctm 1424812121281

As you can see the numbers are the same except for a small execution time.

Just in case you don't like System.currentTimeMillis, use Instant.now().toEpochMilli()

Chemnitz answered 24/2, 2015 at 21:12 Comment(5)
No, Epoch is relative to UTC but you get the current time from your local zone.Batholomew
@ChristofferHammarström the amount of milliseconds that have passed since the epoch is a fact independent of timezone. It's the same amount of milliseconds, no matter what time of day you call it. The two results are different because brian's machine took 203 milliseconds to execute the second command.Aureomycin
Is it ok to use UTC when the user maybe in a different timezoneWhitesmith
@Whitesmith you should probably never use this exact code, use the API as intended. Date-time should always be UTC when stored on a computer or transmitted to another user. It should usually be presented to the user as a local date time using their own time zone settings.Chemnitz
As @Aureomycin has already mentioned, the result has nothing to do with the timezone. The reason behind the difference is that it took 203 milliseconds to execute the second command. You can replace System.out.println("ctm " + System.currentTimeMillis()); with System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); i.e. execute the exact same statement twice and you will still see the difference equal to the no. of milliseconds elapsed since the last execution of the same statement.Tricyclic
S
26

Since Java 8 you can call java.time.Instant.toEpochMilli().

For example the call

final long currentTimeJava8 = Instant.now().toEpochMilli();

gives you the same results as

final long currentTimeJava1 = System.currentTimeMillis();
Simons answered 12/2, 2018 at 9:24 Comment(2)
"gives you the same results as" ... but takes more CPU power and stresses the garbage collector a lot more.Oidea
I'd like to see the above quantified (especially for normal usage - e.g. not for some performance critical real-time application...)Findley
G
23

To avoid ZoneId you can do:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

Getting 0 as value, that's right!

Grayson answered 13/5, 2015 at 16:0 Comment(5)
ZoneOffset.ofTotalSeconds(0) it is the same as ZoneOffset.UTCBabysitter
Yes, it was me upvoting @AntonNovopashin’s comment. Since you needed UTC, you’re fine (you might want to mention that in the answer). BTW ZoneOffset is a subclass of ZoneId, so I wouldn’t exactly say you have avoided it, but as long as you’re happy…Elnaelnar
My first comment was a bit harsh, but wasn’t meant as offensive. You took offense. I am sorry. I have deleted it. Allow me to ask the other way around: what might be our reason for wanting to avoid ZoneId?Elnaelnar
@OleV.V Is it ok to use UTC. Isn't only for people living in UTC timezone.Whitesmith
@Whitesmith I don’t think anyone lives in UTC time zone. Using UTC for times that are used across time zones is recommended as a good practice. See for example Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users. Or maybe I didn’t understand your question?Elnaelnar
F
15

You can use java.sql.Timestamp also to get milliseconds.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
Faze answered 29/6, 2018 at 9:8 Comment(5)
You are ignoring the crucial need for a time zone. I do not recommend doing it this way. Also the Timestamp class is long outdated and filled with design problems, so I’d rather avoid it, especially when we can use the classes from java.time like LocalDateTime.Elnaelnar
@OleV.V. Just curious about the design problems of Timestamp, Can you share some article on that? It helps me to avoid using Timestamp from my code as well. Thanks!Faze
Just short, it’s implemented as a subclass of Date but often cannot be handled as a Date. Most of the methods inherited from Date and one constructor are deprecated. Its toString method uses the JVM’s time zone, which confuses many since the same Timestamp is printed differently on different computers (example).Elnaelnar
This is perfect for unit testing. Just replace the now with LocalDate.of(year, month, day)Pearse
This should be the accepted answer to workaround the "always UTC" values.Affixation
L
14

To get the current time in milliseconds (since the epoch), use System.currentTimeMillis().

Lophophore answered 29/5, 2014 at 23:1 Comment(0)
P
13

You can try this:

long diff = LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
Presumably answered 15/12, 2020 at 10:42 Comment(3)
Please add some explanation too.Timaru
if you use LocalDateTime without local offset (always use UTC only) then it's better to just use Instant for REST, Websockets and other logic, and then you can pass that Instant to ZonedDateTime when you want to format date time for UI with local offset. In this case you don't use LocalDateTime at allPeroxidize
LocalDateTime.now().toInstant(OffsetDateTime.now().offset) is easierPeroxidize
L
7

Why didn't anyone mentioned the method LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

This seems way shorter that many suggested answers above...

Leo answered 17/3, 2020 at 23:33 Comment(5)
this is what I was looking for. That accepted answer was giving me the willies.Polynomial
Accept its only available in API 26 :{Polynomial
Because it gives only seconds. It's weird that there is no toEpochMilli method, taken into account the fact that you can specify even nanoseconds in LocalDateTime: there is a method LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).Nidanidaros
if you just knew the difference between seconds and milliseconds...Peroxidize
the question was about milliseconds and the guy says that it is weird that nobody mentioned seconds :DPeroxidize
L
6

In case of LocalDate, you can use the toEpochDay() method. It returns the number of days since 01/01/1970. That number then can be easily converted to milliseconds:

long dateInMillis = TimeUnit.DAYS.toMillis(myLocalDate.toEpochDay());

In case of LocalDateTime, you can use the toEpochSecond() method. It returns the number of seconds since 01/01/1970. That number then can be converted to milliseconds, too:

long dateTimeInMillis = TimeUnit.SECONDS.toMillis(myLocalDateTime.toEpochSecond());
Lozano answered 3/2, 2022 at 20:13 Comment(2)
The correct method is: toEpochDayModerator
Thanks for pointing this out, fixed the typo.Lozano
I
5

For LocalDateTime I do it this way:

LocalDateTime.of(2021,3,18,7,17,24,341000000)
    .toInstant(OffsetDateTime.now().getOffset())
    .toEpochMilli()
Ivied answered 18/3, 2021 at 9:21 Comment(0)
L
4

If you have a Java 8 Clock, then you can use clock.millis() (although it recommends you use clock.instant() to get a Java 8 Instant, as it's more accurate).

Why would you use a Java 8 clock? So in your DI framework you can create a Clock bean:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

and then in your tests you can easily Mock it:

@MockBean private Clock clock;

or you can have a different bean:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

which helps with tests that assert dates and times immeasurably.

Leolaleoline answered 18/7, 2018 at 9:4 Comment(0)
B
4

I think this is more simpler:

ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());
Assert.assertEquals(System.currentTimeMillis(), zdt.toInstant().toEpochMilli());

get the millis like System.currentTimeMillis() (from UTC).

Balf answered 13/8, 2021 at 10:21 Comment(0)
I
3

Date and time as String to Long (millis):

String dateTimeString = "2020-12-12T14:34:18.000Z";

DateTimeFormatter formatter = DateTimeFormatter
                .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);

LocalDateTime localDateTime = LocalDateTime
        .parse(dateTimeString, formatter);

Long dateTimeMillis = localDateTime
        .atZone(ZoneId.systemDefault())
        .toInstant()
        .toEpochMilli();
Insurance answered 21/2, 2021 at 18:34 Comment(0)
M
2
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}
Millenarian answered 25/8, 2019 at 16:4 Comment(0)
B
0

Simplest conversion:

Instant.from(localDateTime).toEpochMilli()

SORRY this does not work and gies the following error:

"Unsupported field: InstantSeconds",
"  java.base/java.time.LocalDate.get0(LocalDate.java:708)",
"  java.base/java.time.LocalDate.getLong(LocalDate.java:687)",
"  java.base/java.time.LocalDateTime.getLong(LocalDateTime.java:720)",
"  java.base/java.time.Instant.from(Instant.java:373)",
"  com.capitalone.rupol.ruleengine.util.LocalDateSerializer.serialize(LocalDateSerializer.java:25)",
"Unable to obtain Instant from TemporalAccessor: 2024-02-03T00:00 of type java.time.LocalDateTime",
"  java.base/java.time.Instant.from(Instant.java:378)",
"  com.capitalone.rupol.ruleengine.util.LocalDateSerializer.serialize(LocalDateSerializer.java:25)",
"  com.capitalone.rupol.ruleengine.util.LocalDateSerializer.serialize(LocalDateSerializer.java:11)",
"  com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeOptionalFields(MapSerializer.java:869)",
"  com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:760)",

The LocalDateTime does not carry a time zone. The Instant does not carry a time zone. Strangely, many of the other conversions require specifying a time zone that you don't need. This avoids using a time zone offset at any step, and converts internally from millis to millis.

It is strange that the LocalDateTime does not offer a conversion to Instant, since both LocalDateTime and Instant do not involve any representation of a time zone, but this factory method does the job.

Bron answered 27/2 at 16:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.