Java - Result when compare two ZonedDateTime is not as expected

南笙酒味 提交于 2020-12-09 03:56:57

问题


I have this code :

ZonedDateTime t1 = ZonedDateTime.parse("2018-04-06T10:01:00.000+03:00");
ZonedDateTime t2 = ZonedDateTime.parse("2018-04-06T10:01:00.000-03:00");
System.out.println(t1.compareTo(t2));

The result is -1. I guess it will convert both t1 and t2 to the same timezone then compare it. E.g in the first case it will (maybe) compare

t1 = 2018-04-06T07:01:00.000+00:00 to t2 = 2018-04-06T13:01:00.000+00:00

This case return 1 as I expected

ZonedDateTime t1 = ZonedDateTime.parse("2018-04-06T17:01:00.000+03:00");
ZonedDateTime t2 = ZonedDateTime.parse("2018-04-06T10:01:00.000-03:00");
System.out.println(t1.compareTo(t2));

But this one (*) doesn't return 0, it return 1 :

ZonedDateTime t1 = ZonedDateTime.parse("2018-04-06T16:01:00.000+03:00");
ZonedDateTime t2 = ZonedDateTime.parse("2018-04-06T10:01:00.000-03:00");
System.out.println(t1.compareTo(t2));

I even try to use truncatedTo(ChronoUnit.MINUTES) after parse the string to ignore the seconds part but nothing change.

The most interested thing is if I decrease / increase t1 / t2 by one second, the result will be -1

e.g :

ZonedDateTime t1 = ZonedDateTime.parse("2018-04-06T16:01:00.000+03:00");
ZonedDateTime t2 = ZonedDateTime.parse("2018-04-06T10:01:01.000-03:00");
System.out.println(t1.compareTo(t2));

In my use case, all user input time will be saved in the above format in many ZoneOffset and I have some query where I need to compare it with server time (ignore the seconds of the time). How can I get t1 equals t2 in case (*) above?


回答1:


Use toInstant(), then compare the results, like so:

    ZonedDateTime t1 = ZonedDateTime.parse("2018-04-06T16:01:00.000+03:00");
    ZonedDateTime t2 = ZonedDateTime.parse("2018-04-06T10:01:00.000-03:00");
    System.out.println(t1.toInstant().compareTo(t2.toInstant())); 



回答2:


The comparison is based first on the instant, then on the local date-time, then on the zone ID, then on the chronology. It is "consistent with equals", as defined by Comparable.

compareTo is implemented in the superclass ChronoZonedDateTime, a class that we usually don’t care about, but where we need to look for the documentation of some of the methods. So the above quote comes from there.

So in the case where both ZonedDateTime objects denote the same instant, t1’s local time is 16:01, which is greater than the t2’s 10:01. So 1 is the correct and expected result. On the other hand, if the instants are just one second apart — or just 1 nanosecond — that takes precedence, and the local times are not compared.

I believe this explains the behaviour you observed.

The quote furthermore gives a hint as to why this must be so: Suppose that comparing two ZonedDateTime objects with same instant but different time zones returned 0. Then the comparison would no longer be consistent with equals. Which is considered a pretty nice property (though not required).

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C.

(Quoted from Comparable interface documentation)

So if you wanted to compare just the instants, there are two options depending on what type you prefer for your result:

  1. Use isBefore, isAfter or isEqual:

    ZonedDateTime t1 = ZonedDateTime.parse("2018-04-06T16:01:00.000+03:00");
    ZonedDateTime t2 = ZonedDateTime.parse("2018-04-06T10:01:00.000-03:00");
    System.out.println(t1.isBefore(t2));
    System.out.println(t1.isAfter(t2));
    System.out.println(t1.isEqual(t2));
    

    Output:

false
false
true
  1. Use the answer by Yoav Gur: explicitly compare the instants.


来源:https://stackoverflow.com/questions/49686272/java-result-when-compare-two-zoneddatetime-is-not-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!