2014-09-11 17 views
6

Tôi tạo ra hai đối tượng ZonedDateTime và tôi nghĩ rằng họ cần được bình đẳng:java 8 - ZonedDateTime không bằng một 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); 
} 

Trong debugger Tôi thấy rằng lớp của thành viên của ZonedDateTime khu trong trường hợp đầu tiên là java.time.ZoneOffset và trong java.time.ZoneRegion thứ hai và điều này làm cho các đối tượng ZonedDateTime không bằng nhau. Điều này gây nhầm lẫn ... Bất kỳ ý tưởng nào?

Trả lời

12

Bạn đang kiểm tra tính bình đẳng đối tượng đánh giá là false vì các đối tượng này không tương đương. Một tài khoản được liên kết với một số ZoneId, số còn lại là ZoneOffset. Nếu bạn muốn kiểm tra xem họ có đại diện cho cùng một thời gian hay không, bạn có thể sử dụng phương thức không được trực quan có tên là isEqual.

ví dụ .:

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)); 

in:

isEqual:true 
equals: false 

Btw, lưu ý rằng bạn không cần phải sử dụng Objects.equals(a,b) cho hai đối tượng bạn đã biết là không null. Bạn có thể gọi trực tiếp a.equals(b).

+0

Cảm ơn bạn! Điều này là hữu ích và bạn đúng: isEqual không phải là rất trực quan ... –

1

Phương thức equals() trên ZonedDateTime yêu cầu tất cả các bộ phận cấu thành của đối tượng đều bằng nhau. Vì một số ZoneOffset không bằng ZoneRegion (mặc dù cả hai đều là lớp con của ZoneId), nhưng phương thức trả về false. Đọc về VALJOs để hiểu thêm về lý do tại sao các loại giá trị được so sánh theo cách này.

Phương thức isEqual chỉ so sánh ngay trên dòng thời gian, có thể hoặc không thể là thứ bạn muốn. Bạn cũng có thể sử dụng timeLineOrder()method để so sánh hai ZoneDateTime chỉ sử dụng dòng thời gian.

0

Điều này chơi địa ngục trên tôi trong giờ quá khi sử dụng Jackson để tuần tự hóa/deserialize trường hợp của ZonedDateTime và sau đó so sánh chúng với nhau để bình đẳng để xác minh rằng mã của tôi đã hoạt động chính xác. Tôi không hoàn toàn hiểu được ý nghĩa nhưng tất cả những gì tôi học được là sử dụng isEqual thay vì bằng. Nhưng điều này ném một cờ lê lớn trong kế hoạch thử nghiệm như hầu hết các tiện ích khẳng định sẽ chỉ gọi tiêu chuẩn .equals().

Đây là những gì cuối cùng tôi đã đưa ra sau khi gặp khó khăn trong một thời gian khá:

@Test 
public void zonedDateTimeCorrectlyRestoresItself() { 

    // construct a new instance of ZonedDateTime 
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Z")); 
    // offset = {[email protected]} "Z" 
    // zone = {[email protected]} "Z" 

    String starting = now.toString(); 

    // restore an instance of ZonedDateTime from String 
    ZonedDateTime restored = ZonedDateTime.parse(starting); 
    // offset = {[email protected]} "Z" 
    // zone = {[email protected]} "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 = {[email protected]} "Z" 
    // zone = {[email protected]} "Z" 


    String converted = objectMapper.writeValueAsString(now); 

    // restore an instance of ZonedDateTime from String 
    ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class); 
    // offset = {[email protected]} "Z" 
    // zone = {[email protected]} "UTC" 

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

    System.out.println("break point me"); 
} 
Các vấn đề liên quan