簡體   English   中英

java 8 - ZonedDateTime 不等於另一個 ZonedDateTime

[英]java 8 - ZonedDateTime not equal another ZonedDateTime

我創建了兩個 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 zone的成員類在第一種情況下是java.time.ZoneOffset ,在第二個 java.time.ZoneRegion 中,這使得 ZonedDateTime 對象不相等。 這令人困惑......有任何想法嗎?

您正在檢查評估為false對象相等性,因為這些對象不相等。 一個綁定到ZoneId ,另一個綁定到ZoneOffset 如果你想檢查它們是否代表同一時間,你可以使用不太直觀的命名方法isEqual

例如:

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

順便說一句,請注意,對於已經知道為非null兩個對象,您不需要使用Objects.equals(a,b) 您可以直接調用a.equals(b)

當使用 Jackson 序列化/反序列化 ZonedDateTime 的實例,然后將它們相互比較以驗證我的代碼是否正常工作時,這也讓我困擾了幾個小時。 我不完全理解其中的含義,但我所學到的只是使用 isEqual 而不是 equals。 但這會給測試計划帶來很大的麻煩,因為大多數斷言實用程序只會調用標准的 .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");
}

ZonedDateTime上的equals()方法要求對象的所有組成部分都相等。 由於ZoneOffset不等於ZoneRegion (即使兩者都是ZoneId子類),該方法返回 false。 閱讀VALJO以了解更多關於為什么以這種方式比較值類型的信息。

isEqual方法只比較時間線上的瞬間,這可能是您想要的,也可能不是。 您還可以使用timeLineOrder() 方法僅使用時間線來比較兩個ZoneDateTime

這也讓我們痛苦了一陣子。 ZonedDateTime值實際上表示相同的時間,但是它們的區域“類型”不同,這就是它們不相等的原因。

上面的答案是正確的,但是我想我會添加一個可能會進一步幫助的視覺效果:

在此處輸入圖片說明

ZonedDateTime代碼中,我們發現,其中顯示了區域比較:

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM