【发布时间】:2018-07-05 21:01:14
【问题描述】:
我正在比较两个似乎相等的日期,但它们包含不同的区域名称:一个是 Etc/UTC,另一个是 UTC。
根据这个问题:Is there a difference between the UTC and Etc/UTC time zones? - 这两个区域是相同的。但是我的测试失败了:
import org.junit.Test;
import java.sql.Timestamp;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import static org.junit.Assert.assertEquals;
public class TestZoneDateTime {
@Test
public void compareEtcUtcWithUtc() {
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime zoneDateTimeEtcUtc = now.withZoneSameInstant(ZoneId.of("Etc/UTC"));
ZonedDateTime zoneDateTimeUtc = now.withZoneSameInstant(ZoneId.of("UTC"));
// This is okay
assertEquals(Timestamp.from(zoneDateTimeEtcUtc.toInstant()), Timestamp.from(zoneDateTimeUtc.toInstant()));
// This one fails
assertEquals(zoneDateTimeEtcUtc,zoneDateTimeUtc);
// This fails as well (of course previous line should be commented!)
assertEquals(0, zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc));
}
}
结果:
java.lang.AssertionError:
Expected :2018-01-26T13:55:57.087Z[Etc/UTC]
Actual :2018-01-26T13:55:57.087Z[UTC]
更具体地说,我希望ZoneId.of("UTC") 将等于ZoneId.of("Etc/UTC"),但它们不是!
作为@NicolasHenneaux suggested,我可能应该使用compareTo(...) 方法。这是个好主意,但是zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc) 返回-16 值,因为ZoneDateTime 内部的这个实现:
cmp = getZone().getId().compareTo(other.getZone().getId());
断言结果:
java.lang.AssertionError:
Expected :0
Actual :-16
所以问题出在ZoneId 实现的某个地方。但我仍然希望,如果两个区域 id 都有效并且都指定同一个区域,那么它们应该是相等的。
我的问题是:这是一个库错误,还是我做错了什么?
更新
有几个人试图说服我这是一种正常行为,比较方法的实现使用String id 表示@987654338 是正常 @。在这种情况下,我应该问,为什么以下测试运行正常?
@Test
public void compareUtc0WithUtc() {
ZonedDateTime now = ZonedDateTime.now();
ZoneId utcZone = ZoneId.of("UTC");
ZonedDateTime zonedDateTimeUtc = now.withZoneSameInstant(utcZone);
ZoneId utc0Zone = ZoneId.of("UTC+0");
ZonedDateTime zonedDateTimeUtc0 = now.withZoneSameInstant(utc0Zone);
// This is okay
assertEquals(Timestamp.from(zonedDateTimeUtc.toInstant()), Timestamp.from(zonedDateTimeUtc0.toInstant()));
assertEquals(0, zonedDateTimeUtc.compareTo(zonedDateTimeUtc0));
assertEquals(zonedDateTimeUtc,zonedDateTimeUtc0);
}
如果Etc/UTC 是 与UTC 相同,那么我看到两个选项:
- compareTo/equals 方法不应使用 ZoneId id,而应比较它们的规则
-
Zone.of(...)已损坏,应将Etc/UTC和UTC视为相同的时区。
否则我不明白为什么 UTC+0 和 UTC 可以正常工作。
UPDATE-2我报告了一个错误,ID : 9052414。将看看 Oracle 团队将做出什么决定。
UPDATE-3 已接受错误报告(不知道他们是否会将其关闭为“无法修复”):https://bugs.openjdk.java.net/browse/JDK-8196398
【问题讨论】:
-
你喜欢搜索这些错误吗? :)
-
说真的,我今天没喝酒。我在工作中发现了它:)
-
可能只是一个提示,我现在看不到 :(,但是如果 equals 也从区域中查看实际的字符串会怎样
-
@Eugene 当然可以!问题是这个区域不相等
-
@Eugene,我已经更新了我的问题,将问题缩小到
ZoneId
标签: java date datetime zoneddatetime datetime-comparison