I came across this question on StackOverflow:
Is there any reason to use ZoneId.of("UTC") instead of ZoneOffset.UTC?
Since I had to deal with an issue related to this question in production, I wanted to share my answer here because I think it might be useful to anyone serializing ZonedDateTime with Jackson.
Tl;dr if you use Jackson, you might be better of using ZoneId instead of ZoneOffset.
I can think of one situation where ZoneId.of("UTC") might be preferable over ZoneOffset.UTC. If you use jackson-datatype-jsr310 to deserialize ZonedDataTime from JSON, you get dates with ZoneId.
For example, let's say we have this POJO (getters/setters omitted for brevity):
class Example {
private ZonedDateTime date = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.DAYS);
}
If you print an instance of the class you get:
Example example1 = new Example();
System.out.println(example1);
// output:
// Example(date=2022-06-17T00:00Z) - as expected
What happens when you deserialize JSON containing the above string 2022-06-17T00:00Z?
String json = "{\"date\":\"2022-06-17T00:00Z\"}";
Example example2 = mapper.readValue(json, Example.class);
System.out.println(example2);
// output:
// Example(date=2022-06-17T00:00Z[UTC]) // now with ZoneId(!)
So now we have two variants, one with ZoneOffset and one with ZoneId:
2022-06-17T00:00Z2022-06-17T00:00Z[UTC]
And these are not equal to each other. For example:
Instant instant = Instant.now();
ZonedDateTime z1 = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
ZonedDateTime z2 = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"));
System.out.println(z1.equals(z2)); // => false
As a result example1.equals(example2) will also be false. This could be a source of subtle bugs.
Note: you get same result if your serialize new Example() to a JSON string and deseralize the string back to an object. You will get a date with ZoneId.
Tested with Jackson 2.13.1.
Top comments (0)