How can I return LocalDate.now() in milliseconds?

66.2k views Asked by At

I create date now:

ZoneId gmt = ZoneId.of("GMT");
LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDateNow = localDateTime.toLocalDate();

Then I want return this date in milliseconds:

localDateNow.atStartOfDay(gmt) - 22.08.2017
localDateNow.atStartOfDay(gmt).toEpochSecond(); - 1503360000 (18.01.70)

How can I return LocalDate.now() in milliseconds?

1

There are 1 answers

0
AudioBubble On

Calling toInstant().toEpochMilli(), as suggested by @JB Nizet's comment, is the right answer, but there's a little and tricky detail about using local dates that you must be aware of.

But before that, some other minor details:

  • Instead of ZoneId.of("GMT") you can use the built-in constant ZoneOffset.UTC. They're equivalent, but there's no need to create extra redundant objects if the API already provides one that does exactly the same thing.
  • Instead of calling LocalDateTime.now() and then .toLocalDate(), you can call LocalDate.now() directly - they're equivalent.

Now the tricky details: when you call the now() method (for either LocalDateTime or LocalDate), it uses the JVM's default timezone to get the values for the current date, and this value might be different depending on the timezone configured in the JVM.

In the JVM I'm using, the default timezone is America/Sao_Paulo, and the local time here is 09:37 AM. So LocalDate.now() returns 2017-08-22 (August 22th 2017).

But if I change the default timezone to Pacific/Kiritimati, it returns 2017-08-23. That's because in Kiritimati, right now is already August 23th 2017 (and the local time there, at the moment I write this, is 02:37 AM).

So, if I run this code when the default timezone is Pacific/Kiritimati:

LocalDate dtNow = LocalDate.now(); // 2017-08-23
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());

The output is:

1503446400000

Which is the equivalent of August 23th 2017 at midnight in UTC.

If I run the same code when the default timezone is America/Sao_Paulo, the result will be:

1503360000000

Which is the equivalent of August 22th 2017 at midnight in UTC.

Using now() makes your code depends on the JVM's default timezone. And this configuration can be changed without notice, even at runtime, making your code return different results when such change occurs.

And you don't need such an extreme case (like someone misconfiguring the JVM to a "very-far" timezone). In my case, for example, in America/Sao_Paulo timezone, if I run the code at 11 PM, LocalDate will return August 22th, but the current date in UTC will already be August 23th. That's because 11 PM in São Paulo is the same as 2 AM of the next day in UTC:

// August 22th 2017, at 11 PM in Sao Paulo
ZonedDateTime z = ZonedDateTime.of(2017, 8, 22, 23, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2017-08-22T23:00-03:00[America/Sao_Paulo]
System.out.println(z.toInstant()); // 2017-08-23T02:00:00Z (in UTC is already August 23th)

So using a LocalDate.now() is not a guarantee that I'll always have the current date in UTC.


If you want the current date in UTC (regardless of the JVM default timezone) and set the time to midnight, it's better to use a ZonedDateTime:

// current date in UTC, no matter what the JVM default timezone is 
ZonedDateTime zdtNow = ZonedDateTime.now(ZoneOffset.UTC);
// set time to midnight and get the epochMilli
System.out.println(zdtNow.with(LocalTime.MIDNIGHT).toInstant().toEpochMilli());

The output is:

1503360000000

Which is the equivalent of August 22th 2017 at midnight in UTC.

Another alternative is to pass the timezone to LocalDate.now, so it can get the correct values for the current date on the specified zone:

// current date in UTC, no matter what the JVM default timezone is 
LocalDate dtNowUtc = LocalDate.now(ZoneOffset.UTC);
// set time to midnight and get the epochMilli
System.out.println(dtNow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli());