I have this method to calculate midnigt and current time as long values:
/**
* Returns the time range between the midnight and current time in milliseconds.
*
* @param zoneId time zone ID.
* @return a {@code long} array, where at index: 0 - midnight time; 1 - current time.
*/
public static long[] todayDateRange(ZoneId zoneId) {
long[] toReturn = new long[2];
LocalTime midnight = LocalTime.MIDNIGHT;
LocalDate today = LocalDate.now(zoneId);
LocalDateTime todayMidnight = LocalDateTime.of(today, midnight);
ZonedDateTime todayMidnightZdt = todayMidnight.atZone(zoneId);
toReturn[0] = todayMidnightZdt.toInstant().toEpochMilli();
ZonedDateTime nowZdt = LocalDateTime.now().atZone(zoneId);
toReturn[1] = nowZdt.toInstant().toEpochMilli();
return toReturn;
}
Perhaps there is the simpler way to do that?
You could also do:
I can't think of a simpler way to do it.
LocalDateTime vs ZonedDateTime
There's a (tricky) difference between
LocalDateTime.now().atZone(zoneId)
andZonedDateTime.now(zoneId)
.For the code below, I'm using a JVM in which the default timezone is
America/Sao_Paulo
and will try to get the current date and time in another timezone (Europe/London
). At the moment I run this code, it's August 20th 2017, but in São Paulo the time is 17:56 and in London is 21:56.When I do:
It creates a
LocalDateTime
with the current date and time in the JVM's default timezone. In this case, it'll get the current date and time in São Paulo's timezone (which is August 20th 2017, at 17:56):When I call the
atZone
method, it creates aZonedDateTime
that corresponds to this date and time in the specified zone:The
nowAtZone
variable will be:The same date (August 20th 2017) and time (17:56) in London timezone. Note that it's not the current date/time in London. If I get the equivalent epochMilli:
It will be:
Now, if I don't use the
LocalDateTime
and direclty use theZonedDateTime
instead:It will get the current date and time in London, which will be:
Note that the time changed (it's 21:56). That's because right now, at this moment, that's the current time in London. If I get the epochMilli value:
The value will be:
Note that it's different from the first case using
LocalDateTime
(even if you ignore the difference in the milliseconds value, because the hour is different). If you want the current date and time at the specified timezone, you must useZonedDateTime.now(zoneId)
.Using
LocalDateTime.now().atZone()
not only gives a different result, but it will also change if you run in different JVM's, or if the JVM default timezone changes (someone might misconfigure it, or another application running in the same VM callsTimeZone.setDefault()
).Daylight Saving Time
Just remind about corner cases due to DST (Daylight Saving Time) issues. I'm gonna use the timezone I live in as example (
America/Sao_Paulo
).In São Paulo, DST started at October 16th 2016: at midnight, clocks shifted 1 hour forward from midnight to 1 AM (and the offset changes from
-03:00
to-02:00
). So all local times between 00:00 and 00:59 didn't exist in this timezone (you can also think that clocks changed from 23:59:59.999999999 directly to 01:00). If I create a local date in this interval, it's adjusted to the next valid moment:When DST ends: in February 19th 2017 at midnight, clocks shifted back 1 hour, from midnight to 23 PM of 18th (and the offset changes from
-02:00
to-03:00
). So all local times from 23:00 to 23:59 existed twice (in both offsets:-03:00
and-02:00
), and you must decide which one you want. By default, it uses the offset before DST ends, but you can use thewithLaterOffsetAtOverlap()
method to get the offset after DST ends:Note that the dates before and after DST ends have different offsets (
-02:00
and-03:00
). This affects the value of epochMilli.The above can also happen if you adjust the time using
with
method.After modification the code now is much simpler: