Java - 比较两个 ZonedDateTime 的结果不符合预期

Java - Result when compare two ZonedDateTime is not as expected

我有这个代码:

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

结果为-1。我猜它会将 t1 和 t2 都转换为相同的时区然后进行比较。例如,在第一种情况下,它会(可能)比较

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

这个案例return 1如我所料

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

但是这个 (*) 不是 return 0,它是 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));

我什至尝试在解析字符串后使用 truncatedTo(ChronoUnit.MINUTES) 来忽略秒部分,但没有任何变化。

最感兴趣的是如果我将 t1 / t2 减少/增加一秒,结果将是 -1

例如:

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

在我的用例中,所有用户输入的时间都将以上述格式保存在许多 ZoneOffset 中,我有一些查询需要将其与服务器时间进行比较(忽略时间的秒数)。在上面的 (*) 情况下,我怎样才能得到 t1 等于 t2?

使用toInstant(),然后比较结果,像这样:

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

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是在superclassChronoZonedDateTime中实现的,一个我们平时不关心的class,但是需要去哪里找文档的一些方法。所以上面的引用来自那里。

所以在两个 ZonedDateTime 对象表示同一时刻的情况下,t1 的本地时间是 16:01,它大于 t2 的本地时间10:01。所以 1 是正确的预期结果。另一方面,如果瞬间仅相隔一秒——或仅相隔 1 纳秒——则优先,并且不比较当地时间。

我相信这可以解释您观察到的行为。

引文进一步暗示了为什么必须如此:假设比较具有相同时刻但不同时区的两个 ZonedDateTime 对象返回 0。那么比较将不再与 equals 一致。这被认为是相当不错的属性(虽然不是必需的)。

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.

(引自Comparable interface documentation

因此,如果您只想比较瞬间,根据您喜欢的结果类型,有两种选择:

  1. 使用isBeforeisAfterisEqual:

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

    输出:

false
false
true
  1. 使用:明确比较瞬间。