ZoneOffset.UTC 대신 ZoneId.of("UTC")를 사용해야 하는 이유가 있습니까?

4942 단어 javaapitimezone
StackOverflow에서 다음 질문을 발견했습니다.

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

프로덕션에서 이 질문과 관련된 문제를 처리해야 했기 때문에 Jackson과 직렬화ZonedDateTime하는 모든 사람에게 유용할 수 있다고 생각하여 여기에서 답변을 공유하고 싶었습니다.

Tl; dr Jackson을 사용하는 경우 ZoneId 대신 ZoneOffset 를 사용하는 것이 좋습니다.

ZoneId.of("UTC")ZoneOffset.UTC 보다 더 나은 한 가지 상황을 생각할 수 있습니다. jackson-datatype-jsr310을 사용하여 JSON에서 역직렬화ZonedDataTime하면 날짜가 ZoneId로 표시됩니다.

예를 들어 POJO(간결성을 위해 getter/setter 생략)가 있다고 가정해 보겠습니다.

class Example {
    private ZonedDateTime date = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.DAYS);
}


클래스의 인스턴스를 인쇄하면 다음과 같은 결과가 나타납니다.

Example example1 = new Example();
System.out.println(example1);

// output:
// Example(date=2022-06-17T00:00Z) - as expected


위의 문자열2022-06-17T00:00Z을 포함하는 JSON을 역직렬화하면 어떻게 됩니까?

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(!)


이제 ZoneOffsetZoneId가 있는 두 가지 변형이 있습니다.
  • 2022-06-17T00:00Z
  • 2022-06-17T00:00Z[UTC]

  • 그리고 이들은 서로 동등하지 않습니다. 예를 들어:

    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
    


    그 결과 example1.equals(example2)false가 됩니다. 이는 미묘한 버그의 원인이 될 수 있습니다.

    참고: JSON 문자열로 직렬화new Example()하고 문자열을 다시 객체로 역직렬화하면 동일한 결과를 얻습니다. 당신은 ZoneId로 날짜를 얻을 것입니다.

    Jackson2.13.1으로 테스트했습니다.

    좋은 웹페이지 즐겨찾기