java - ZonedDateTime 比较 : expected: [Etc/UTC] but was: [UTC]

标签 java date datetime zoneddatetime datetime-comparison

我正在比较两个看似相等的日期,但它们包含不同名称的时区:一个是 Etc/UTC,另一个是 UTC

根据这个问题:Is there a difference between the UTC and Etc/UTC time zones? - 这两个区域是相同的。但是我的测试失败了:

import org.junit.Test;
import java.sql.Timestamp;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import static org.junit.Assert.assertEquals;

public class TestZoneDateTime {

    @Test
    public void compareEtcUtcWithUtc() {
        ZonedDateTime now = ZonedDateTime.now();
        ZonedDateTime zoneDateTimeEtcUtc = now.withZoneSameInstant(ZoneId.of("Etc/UTC"));
        ZonedDateTime zoneDateTimeUtc = now.withZoneSameInstant(ZoneId.of("UTC"));

        // This is okay
        assertEquals(Timestamp.from(zoneDateTimeEtcUtc.toInstant()), Timestamp.from(zoneDateTimeUtc.toInstant()));
        // This one fails
        assertEquals(zoneDateTimeEtcUtc,zoneDateTimeUtc);

        // This fails as well (of course previous line should be commented!)
        assertEquals(0, zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc));
    }
}

结果:

java.lang.AssertionError: 
Expected :2018-01-26T13:55:57.087Z[Etc/UTC]
Actual   :2018-01-26T13:55:57.087Z[UTC]

更具体地说,我希望 ZoneId.of("UTC") 等于 ZoneId.of("Etc/UTC"),但是它们不是!

作为@NicolasHenneaux suggested ,我可能应该使用 compareTo(...) 方法。这是个好主意,但是 zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc) 返回 -16 值,因为 ZoneDateTime 中的这个实现:

cmp = getZone().getId().compareTo(other.getZone().getId());

断言结果:

java.lang.AssertionError: 
Expected :0
Actual   :-16

所以问题出在 ZoneId 实现的某个地方。但我仍然希望,如果两个区域 ID 都有效并且都指定同一个区域,那么它们应该是相等的。

我的问题是:这是一个库错误,还是我做错了什么?

更新

有几个人试图说服我这是一个正常行为,而且比较方法的实现使用 String id 也是正常 ZoneId 的表示。在这种情况下我应该问,为什么下面的测试运行正常?

    @Test
    public void compareUtc0WithUtc() {
        ZonedDateTime now = ZonedDateTime.now();
        ZoneId utcZone = ZoneId.of("UTC");
        ZonedDateTime zonedDateTimeUtc = now.withZoneSameInstant(utcZone);
        ZoneId utc0Zone = ZoneId.of("UTC+0");
        ZonedDateTime zonedDateTimeUtc0 = now.withZoneSameInstant(utc0Zone);

        // This is okay
        assertEquals(Timestamp.from(zonedDateTimeUtc.toInstant()), Timestamp.from(zonedDateTimeUtc0.toInstant()));
        assertEquals(0, zonedDateTimeUtc.compareTo(zonedDateTimeUtc0));
        assertEquals(zonedDateTimeUtc,zonedDateTimeUtc0);
    }

如果 Etc/UTC UTC 相同,那么我会看到两个选项:

  • compareTo/equals 方法不应使用 ZoneId id,但应比较它们的规则
  • Zone.of(...) 已损坏,应将 Etc/UTCUTC 视为相同的时区。

否则我不明白为什么 UTC+0UTC 工作正常。

UPDATE-2 我报告了一个错误,ID :9052414。看看 Oracle 团队的决定。

UPDATE-3 已接受错误报告(不知道他们是否会以“无法修复”为由将其关闭):https://bugs.openjdk.java.net/browse/JDK-8196398

最佳答案

您可以将 ZonedDateTime 对象转换为 Instant,如其他答案/评论所述。

ZonedDateTime::isEqual

或者您可以使用 isEqual method ,它比较两个 ZonedDateTime 实例是否对应于相同的 Instant:

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime zoneDateTimeEtcUtc = now.withZoneSameInstant(ZoneId.of("Etc/UTC"));
ZonedDateTime zoneDateTimeUtc = now.withZoneSameInstant(ZoneId.of("UTC"));

Assert.assertTrue(zoneDateTimeEtcUtc.isEqual(zoneDateTimeUtc));

关于java - ZonedDateTime 比较 : expected: [Etc/UTC] but was: [UTC],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48462758/

相关文章:

java - ApplicationInfo 元数据返回 null

java - 如何在 Java 中使用 Executors 执行返回不同对象的方法

java - Spring中缓存方法最简单/最透明的方式是什么?

PHP 设置时区而不更改日期?

javascript - 在 Javascript 中依次运行倒数计时器

Java Collections 使用正则表达式过滤元素

javascript - 渲染 Highstock 日期时出错

bash - UNIX 日期 : How to convert week number (date +%W) to a date range (Mon-Sun)?

python - 如何在添加 timedelta 时不从 datetime 开始第二天?

datetime - 如何使用 jest 传递带有 Date 作为预期属性值之一的 expect.toMatchObject()?