Java 8 - ZonedDateTime is not equal to another ZonedDateTime

I created two ZonedDateTime objects, and I think they should be equal:

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

In the debugger, I see that the member class of the ZonedDateTime zone is in the first case java.time.ZoneOffset and in the second java.time.ZoneRegion, and this makes the ZonedDateTime objects not equal. This is confusing ... Any ideas?

+6
source share
3 answers

You check the equality of the object, which evaluates to false , since these objects are not equivalent. One is associated with ZoneId , and the other is with ZoneOffset . If you want to check if they represent the same time, you can use the not very intuitively named isEqual method.

eg:.

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

prints:

 isEqual:true equals: false 

Btw, note that you do not need to use Objects.equals(a,b) for two objects that, as you already know, were not null . You can directly call a.equals(b) .

+12
source

The equals() method on ZonedDateTime requires that all the constituent parts of an object are equal. Since a ZoneOffset not equal to a ZoneRegion (although both are subclasses of ZoneId ), the method returns false. Read about VALJOs to understand how to compare value types in this way.

The isEqual method compares only a point in time, which may or may not be what you want. You can also use the timeLineOrder() method to compare two ZoneDateTime just the time string.

+1
source

This played for hours for me when I used Jackson to serialize / deserialize ZonedDateTime instances and then compare them with each other to make sure my code works correctly. I do not fully understand the consequences, but all I have learned is to use isEqual instead of equals. But this throws a big tie into test plans, since most assertion utilities are simply called standard .equals ().

Here is what I finally came up with after a battle for quite some time:

 @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"); } 
0
source

Source: https://habr.com/ru/post/975147/


All Articles