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 Instant
s and ZonedDateTime
s.
Looking at the API documentation for Instant
and ZonedDateTime
, none of this is the case. I can compare Instant
s with Instant
s and ZonedDateTime
s with ZonedDateTime
s, but the two classes seem to be incompatible. What's more, third-party code like ThreeTen-Extra's Interval
seem to work exclusively with Instant
s.
Is there a reason why Instant
and ZonedDateTime
are not meant to be mixed?
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.
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.
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.
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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With