Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compatibility between Instant and ZonedDateTime

It is my understanding that a ZonedDateTime is really an enhanced version of an Instant. It has all the data an Instant has (precise value along UTC timeline), plus time zone information. So my naïve assumption was that a ZonedDateTime is-an Instant and that any method taking an Instant will happily take a ZonedDateTime instead. Furthermore, I expected isBefore(), isAfter() etc. to work seamlessly between Instants and ZonedDateTimes.

Looking at the API documentation for Instant and ZonedDateTime, none of this is the case. I can compare Instants with Instants and ZonedDateTimes with ZonedDateTimes, but the two classes seem to be incompatible. What's more, third-party code like ThreeTen-Extra's Interval seem to work exclusively with Instants.

Is there a reason why Instant and ZonedDateTime are not meant to be mixed?

like image 588
Daniel Wolf Avatar asked Nov 10 '16 10:11

Daniel Wolf


People also ask

How does ZonedDateTime compare to date?

ZonedDateTime equals() method in Java with ExamplesThe equals() method of ZonedDateTime class in Java is used to compare this ZonedDateTime to the another date-time object passed as parameter. The comparison is based on the offset date-time and the zone.

Should I use OffsetDateTime or ZonedDateTime?

Use OffsetDateTime to store unique instants in the universal timelines irrespective of the timezones, such as keeping the timestamps in the database or transferring information to remote systems worldwide. Use ZonedDateTime for displaying timestamps to users according to their local timezone rules and offsets.

Is ZonedDateTime a UTC?

A ZonedDateTime represents a date-time with a time offset and/or a time zone in the ISO-8601 calendar system. On its own, ZonedDateTime only supports specifying time offsets such as UTC or UTC+02:00 , plus the SYSTEM time zone ID.


2 Answers

Instant and ZonedDateTime have different state - Instant is just a number of nanoseconds from the epoch, while ZonedDateTime consists of a LocalDateTime, ZoneId and ZoneOffset. As such, the two classes can be converted to/from each other, but are not the same (and you lose information when converting ZonedDateTime to Instant).

The behaviour of isBefore() and isAfter() matches exactly between the two however. Whereas the implementation of Comparable matches the recommended behaviour, which is that "It is strongly recommended (though not required) that natural orderings be consistent with equals." ie. compareTo() takes account of the local date-time, time-zone and offset, whereas isBefore() and isAfter() only consider the instant.

Writing a comparator to compare an Instant and a ZonedDateTime is relatively simple:

Comparator<TemporalAccessor> comparator =
    (a, b) -> Instant.from(a).compareTo(Instant.from(b));

which can also be written as:

Comparator<TemporalAccessor> comparator = Comparator.comparing(Instant::from);
like image 186
JodaStephen Avatar answered Nov 07 '22 20:11

JodaStephen


Because the translation is not injective. Take Sunday, October 30th 2016 2:15 AM in Germany/Munich for example: Which Instant does this date/time represent? This is not independently answerable without some assumptions because you don't know if this time should be translated into the Instant before or after the offset for daylight saving time (DST) should be applied. Or Sunday, March 27th 2016 2:15 AM in Germany/Munich: This date/time combination should not exist, as the clock should be set to 3 AM when reaching 2 AM.

Without DST the three possible cases for translating a LocalDateTime into an Instant (exact match, summertime-gap, wintertime-overlap) would be reduced to one and the conversion would be injective, AFAIK.

Edit: "Hands on" this problem, when displaying date/time in our JSF based application, we always pass the offset calculated accordingly to the current state of the DST into the formatter.

like image 25
Smutje Avatar answered Nov 07 '22 21:11

Smutje