java 8 - ZonedDateTime 不等于另一个 ZonedDateTime

2022-09-03 04:02:59

我创建了两个ZonedDateTime对象,我认为它们应该是相等的:

public static void main(String[] args) {
    ZoneId zid = ZoneId.of("America/New_York");
    ZoneOffset offset = ZoneOffset.from(LocalDateTime.now().atZone(zid));
    ZonedDateTime zdt0 = ZonedDateTime.of(2014, 8, 24, 21, 10, 1, 777000002, offset);
    ZonedDateTime zdt1 = ZonedDateTime.of(2014, 8, 24, 21, 10, 1, 777000002, zid);
    boolean equals = Objects.equals(zdt0, zdt1);
    System.out.println("equals: " + equals);
}

在调试器中,我看到第一种情况下ZonedDateTime区域的成员类是java.time.ZoneOffset,在第二种情况下是java.time.ZoneRegion,这使得ZonedDateTime对象不相等。这是令人困惑的...有什么想法吗?


答案 1

您正在检查对象相等性,该对象的计算结果为,因为这些对象不等效。一个绑定到 a,另一个绑定到 。如果要检查它们是否表示相同的时间,则可以使用命名不是很直观的方法 。falseZoneIdZoneOffsetisEqual

例如:

ZoneId zid = ZoneId.of("America/New_York");
ZoneOffset offset = ZoneOffset.from(LocalDateTime.now().atZone(zid));
ZonedDateTime zdt0 = ZonedDateTime.of(2014, 8, 24, 21, 10, 1, 777000002, offset);
ZonedDateTime zdt1 = ZonedDateTime.of(2014, 8, 24, 21, 10, 1, 777000002, zid);
System.out.println("isEqual:" + zdt0.isEqual(zdt1));
System.out.println("equals: " + zdt0.equals(zdt1));

指纹:

isEqual:true
equals: false

顺便说一句,请注意,您不需要用于两个您已经知道是非对象的对象。您可以直接调用。Objects.equals(a,b)nulla.equals(b)


答案 2

当使用Jackson序列化/反序列化ZonedDateTime的实例,然后将它们相互比较以获得相等性以验证我的代码正常工作时,这也让我玩了几个小时。我不完全理解其中的含义,但我所学到的只是使用等式而不是相等性。但这给测试计划带来了很大的麻烦,因为大多数断言实用程序只会调用标准的.equals()。

以下是我在挣扎了很长一段时间后最终想到的:

@Test
public void zonedDateTimeCorrectlyRestoresItself() {

    // construct a new instance of ZonedDateTime
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Z"));
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"

    String starting = now.toString();

    // restore an instance of ZonedDateTime from String
    ZonedDateTime restored = ZonedDateTime.parse(starting);
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"

    assertThat(now).isEqualTo(restored); // ALWAYS succeeds

    System.out.println("test");
}

@Test
public void jacksonIncorrectlyRestoresZonedDateTime() throws Exception {

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.findAndRegisterModules();

    // construct a new instance of ZonedDateTime
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Z"));
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"


    String converted = objectMapper.writeValueAsString(now);

    // restore an instance of ZonedDateTime from String
    ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3821} "UTC"

    assertThat(now).isEqualTo(restored); // NEVER succeeds

    System.out.println("break point me");
}

推荐