是否有任何理由使用 ZoneId.of("UTC") 而不是 ZoneOffset.UTC ?

Van*_*kog 18 java timezone datetime utc

有什么理由使用ZoneId.of("UTC")而不是ZoneOffset.UTC

我们知道两者之间的区别,如ZoneOffset.UTC 和 ZoneId.of("UTC") 之间的区别是什么?

<tl;博士>版本:

  • ZoneOffset.UTCZoneOffset返回ID 为“Z”、偏移量为 0 和默认区域规则的meme 。
  • ZoneId.of("UTC")返回ZoneRegionID 为“UTC”并ZoneOffset.UTC包含在内。

</tl;博士>

对于这个问题,我假设使用 UTC 仅仅是为了更容易处理日期和时间,而不是因为某些东西实际上可能位于 UTC 区域或其他一些业务原因将其作为实际的 ZoneRegion。

例如,在处理ZonedDateTime. 我发现的唯一区别是它的打印方式不同。

2021-06-10T15:28:25.000000111Z
2021-06-10T15:28:25.000000111Z[UTC]
Run Code Online (Sandbox Code Playgroud)

我们正在就这个问题来回进行代码审查讨论,所以我想这种冲突并不罕见。

到目前为止,这是我的想法

ZoneOffset.UTC

  • 它是一个常量(此外,它的偏移值(0)甚至被缓存)。
  • 由于缺少区域信息,它的开销(一点点)较少。
  • 在 UTC,与任何其他时区一样,无需考虑夏令时或历史变化。
    因此,偏移量 0 通常足以满足我迄今为止遇到的所有用例(例如在具有特定夏令时状态的某个区域区域之间进行转换)。

ZoneId.of("UTC")

  • 一般来说,我认为 ZoneRegions 优于 ZoneOffsets,因为存在一系列附加的特定于位置的数据,例如特定的夏令时或历史上的时移。
  • 然而,对于 UTC,ZoneId.of("UTC")只是一个区域环绕ZoneOffset.UTC,到目前为止我找不到任何好处。据我所知,在 UTC 中,除了继承的ZoneOffset.UTC规则之外,不存在与区域相关的数据。
  • 每次都需要解析。

所以我的_猜测_是:

除非您出于某些(例如商业)原因确实需要 UTC 时区/地区,否则您应该更喜欢ZoneOffset.UTC. 它在性能足迹方面有一个(较小的)优势,而 UTC ZoneRegion 似乎没有提供任何我能看到或想到的好处。

然而,由于 Java Date Time API 的复杂性,很难判断我在本次讨论中是否遗漏了一些内容。
有人应该使用吗ZoneId.of("UTC")

arm*_*ino 6

我能想到一种ZoneId.of("UTC")可能比 更好的情况ZoneOffset.UTC。如果您使用jackson-modules-java8从 JSON反序列化ZonedDataTime,您将获得带有ZoneId.

例如,假设我们有这个 POJO(为简洁起见,省略了 getters/setters):

class Example {
    private ZonedDateTime date = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.DAYS);
}
Run Code Online (Sandbox Code Playgroud)

如果打印该类的实例,您将得到:

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

// output:
// Example(date=2022-06-17T00:00Z) - as expected
Run Code Online (Sandbox Code Playgroud)

当您反序列化包含上述字符串的 JSON 时会发生什么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(!)
Run Code Online (Sandbox Code Playgroud)

所以现在我们有两种变体,一种带有ZoneOffset,另一种带有ZoneId

  • 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
Run Code Online (Sandbox Code Playgroud)

结果example1.equals(example2)也将是false。这可能是微妙错误的来源。

注意:如果序列化为new Example()JSON 字符串并将字符串反序列化回对象,您会得到相同的结果。您将与 有个约会ZoneId

与杰克逊一起测试2.13.1


编辑:我最终为此问题提交了一个错误:https://github.com/FasterXML/jackson-modules-java8/issues/244

  • 这些信息非常有帮助。谢谢! (2认同)