DEV Community

Cover image for Is there any reason to use ZoneId.of("UTC") instead of ZoneOffset.UTC?
armandino
armandino

Posted on

2 2

Is there any reason to use ZoneId.of("UTC") instead of ZoneOffset.UTC?

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);
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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(!)
Enter fullscreen mode Exit fullscreen mode

So now we have two variants, one with ZoneOffset and one with ZoneId:

  • 2022-06-17T00:00Z
  • 2022-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
Enter fullscreen mode Exit fullscreen mode

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.

Retry later

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Retry later