Johannes Flügel Johannes Flügel - 2 months ago 19
Java Question

Why is ZoneOffset.UTC != ZoneId.of("UTC")

Why does

ZonedDateTime now = ZonedDateTime.now();
System.out.println(now.withZoneSameInstant(ZoneOffset.UTC)
.equals(now.withZoneSameInstant(ZoneId.of("UTC"))));


print out
false
?

I would expect the both zonedDateTimes to be equal.

Answer

The answer comes from the javadoc of ZoneId:

A ZoneId is used to identify the rules used to convert between an Instant and a LocalDateTime. There are two distinct types of ID:

  • Fixed offsets - a fully resolved offset from UTC/Greenwich, that uses the same offset for all local date-times
  • Geographical regions - an area where a specific set of rules for finding the offset from UTC/Greenwich apply

Most fixed offsets are represented by ZoneOffset. Calling normalized() on any ZoneId will ensure that a fixed offset ID will be represented as a ZoneOffset.

As you use the equals method for comparison, you check for object equivalence. Because of the described difference, the result of the evaluation is false.

If you use the normalized() method as proposed in the documentation, the comparison using equals will be evaluated as true:

now.withZoneSameInstant(ZoneOffset.UTC)
    .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized()));

To check whether they store the same date time, you can use the isEqual method instead:

now.withZoneSameInstant(ZoneOffset.UTC)
    .isEqual(now.withZoneSameInstant(ZoneId.of("UTC")));

Sample

System.out.println("equals: " + now.withZoneSameInstant(ZoneOffset.UTC)
        .equals(now.withZoneSameInstant(ZoneId.of("UTC"))));
System.out.println("equals + normalized: " + now.withZoneSameInstant(ZoneOffset.UTC)
        .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized())));
System.out.println("isEqual: "+ now.withZoneSameInstant(ZoneOffset.UTC)
        .isEqual(now.withZoneSameInstant(ZoneId.of("UTC"))));

Output:

equals: false
equals + normalized: true
isEqual: true
Comments