我创建了两个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 区域的成员类在第一种情况下是 java.time.ZoneOffset ,在第二种情况下是java.time.ZoneRegion,这使得ZonedDateTime对象不相等。这令人困惑...... 有什么想法吗?
答案 0 :(得分:19)
您正在检查对象相等性,其值为false
,因为这些对象不相等。一个绑定到ZoneId
,另一个绑定到ZoneOffset
。如果要检查它们是否代表同一时间,可以使用名称不是很直观的方法isEqual
。
E.g:
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
顺便说一下,请注意,您不需要将Objects.equals(a,b)
用于您已知的两个非null
对象。您可以直接调用a.equals(b)
。
答案 1 :(得分:2)
equals()
上的ZonedDateTime
方法要求对象的所有组成部分都相等。由于ZoneOffset
不等于ZoneRegion
(即使两者都是ZoneId
的子类),该方法返回false。阅读VALJOs以了解更多关于为何以这种方式比较价值类型的信息。
isEqual
方法仅比较时间线上的时刻,可能是您想要的也可能不是。您还可以使用timeLineOrder()
method仅使用时间线比较两个ZoneDateTime
。
答案 2 :(得分:1)
当使用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");
}
答案 3 :(得分:0)