为什么ZoneOffset.UTC!= ZoneId.of("UTC")?

Joh*_*gel 100 java datetime java-8 java-time

为什么

ZonedDateTime now = ZonedDateTime.now();
System.out.println(now.withZoneSameInstant(ZoneOffset.UTC)
        .equals(now.withZoneSameInstant(ZoneId.of("UTC"))));
Run Code Online (Sandbox Code Playgroud)

打印出来false

我希望这两个ZonedDateTime实例是平等的.

DVa*_*rga 147

答案来自(强调我的)javadocZoneId ......

ZoneId用于标识用于在InstantDateTime和LocalDateTime之间进行转换的规则.有两种不同类型的ID:

  • 固定偏移 - 与UTC/Greenwich完全分辨的偏移量,对所有本地日期时间使用相同的偏移量
  • 地理区域 - 用于查找从UTC /格林威治的偏移量的特定规则集适用的区域

大多数固定偏移由ZoneOffset表示.在任何ZoneId上调用normalized()将确保将固定的偏移ID表示为ZoneOffset.

......以及(强调我的)javadocZoneId#of:

此方法解析生成ZoneId或ZoneOffset的ID.如果ID为"Z",则返回ZoneOffset,或者以"+"或" - "开头.

参数id被指定为"UTC",因此它将返回ZoneId带有偏移量的a,它也以字符串形式呈现:

System.out.println(now.withZoneSameInstant(ZoneOffset.UTC));
System.out.println(now.withZoneSameInstant(ZoneId.of("UTC")));
Run Code Online (Sandbox Code Playgroud)

输出:

2017-03-10T08:06:28.045Z
2017-03-10T08:06:28.045Z[UTC]
Run Code Online (Sandbox Code Playgroud)

当您使用该equals方法进行比较时,您将检查对象的等效性.由于所描述的差异,评估的结果是false.

normalized()文件中提出使用该方法时,使用的比较equals将返回true,因为normalized()将返回相应的ZoneOffset:

规范化时区ID,尽可能返回ZoneOffset.

now.withZoneSameInstant(ZoneOffset.UTC)
    .equals(now.withZoneSameInstant(ZoneId.of("UTC").normalized())); // true
Run Code Online (Sandbox Code Playgroud)

正如文档所述,如果你使用"Z""+0"作为输入id,ofZoneOffset直接返回,不需要调用normalized():

now.withZoneSameInstant(ZoneOffset.UTC).equals(now.withZoneSameInstant(ZoneId.of("Z"))); //true
now.withZoneSameInstant(ZoneOffset.UTC).equals(now.withZoneSameInstant(ZoneId.of("+0"))); //true
Run Code Online (Sandbox Code Playgroud)

要检查它们是否存储相同的日期时间,您可以使用该isEqual方法:

now.withZoneSameInstant(ZoneOffset.UTC)
    .isEqual(now.withZoneSameInstant(ZoneId.of("UTC"))); // true
Run Code Online (Sandbox Code Playgroud)

样品

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

输出:

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

  • ...API 是一场灾难。 (15认同)
  • 文档还说“如果区域 ID 等于‘GMT’、‘UTC’或‘UT’,则结果是具有相同 ID 且规则等同于 ZoneOffset.UTC 的 ZoneId”。相同的 ID 和规则,但行为不同。`ZoneId.of("Z")` 为您提供 `ZoneOffset.UTC`,但 `ZoneId.of("UTC")` 为您提供 `ZoneId`(不是 `ZoneOffset.UTC`)。至少可以说,这个 API 并不直观。 (12认同)
  • 好肉汁。时间很艰难。我确信 Java 中的下一个时间库会正确处理......对吗?正确的?!? (4认同)