Why is ZoneOffset.UTC != ZoneId.of("UTC")?
The answer comes from the javadoc of ZoneId
(emphasis mine) ...
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.
... and from the javadoc of ZoneId#of
(emphasis mine):
This method parses the ID producing a ZoneId or ZoneOffset. A ZoneOffset is returned if the ID is 'Z', or starts with '+' or '-'.
The argument id is specified as "UTC"
, therefore it will return a ZoneId
with an offset, which also presented in the string form:
System.out.println(now.withZoneSameInstant(ZoneOffset.UTC));System.out.println(now.withZoneSameInstant(ZoneId.of("UTC")));
Outputs:
2017-03-10T08:06:28.045Z2017-03-10T08:06:28.045Z[UTC]
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
.
When the normalized()
method is used as proposed in the documentation, the comparison using equals
will return true
, as normalized()
will return the corresponding ZoneOffset
:
Normalizes the time-zone ID, returning a ZoneOffset where possible.
now.withZoneSameInstant(ZoneOffset.UTC) .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized())); // true
As the documentation states, if you use "Z"
or "+0"
as input id, of
will return the ZoneOffset
directly and there is no need to call normalized()
:
now.withZoneSameInstant(ZoneOffset.UTC).equals(now.withZoneSameInstant(ZoneId.of("Z"))); //truenow.withZoneSameInstant(ZoneOffset.UTC).equals(now.withZoneSameInstant(ZoneId.of("+0"))); //true
To check if they store the same date time, you can use the isEqual
method instead:
now.withZoneSameInstant(ZoneOffset.UTC) .isEqual(now.withZoneSameInstant(ZoneId.of("UTC"))); // true
Sample
System.out.println("equals - ZoneId.of(\"UTC\"): " + nowZoneOffset .equals(now.withZoneSameInstant(ZoneId.of("UTC"))));System.out.println("equals - ZoneId.of(\"UTC\").normalized(): " + nowZoneOffset .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized())));System.out.println("equals - ZoneId.of(\"Z\"): " + nowZoneOffset .equals(now.withZoneSameInstant(ZoneId.of("Z"))));System.out.println("equals - ZoneId.of(\"+0\"): " + nowZoneOffset .equals(now.withZoneSameInstant(ZoneId.of("+0"))));System.out.println("isEqual - ZoneId.of(\"UTC\"): "+ nowZoneOffset .isEqual(now.withZoneSameInstant(ZoneId.of("UTC"))));
Output:
equals - ZoneId.of("UTC"): falseequals - ZoneId.of("UTC").normalized(): trueequals - ZoneId.of("Z"): trueequals - ZoneId.of("+0"): trueisEqual - ZoneId.of("UTC"): true