What is the difference between ZoneOffset.UTC and ZoneId.of("UTC")?

JavaDatetimeJava 8Java Time

Java Problem Overview


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 ZonedDateTime instances to be equal.

Java Solutions


Solution 1 - Java

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.045Z
2017-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"))); //true
now.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"): false
equals - ZoneId.of("UTC").normalized(): true
equals - ZoneId.of("Z"): true
equals - ZoneId.of("+0"): true
isEqual - ZoneId.of("UTC"): true

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohannes FlügelView Question on Stackoverflow
Solution 1 - JavaDVargaView Answer on Stackoverflow