我正在比较两个看似相等的日期,但它们包含不同名称的时区:一个是 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 也是正常 ZoneId
的表示。在这种情况下我应该问,为什么下面的测试运行正常?
@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
最佳答案
您可以将 ZonedDateTime
对象转换为 Instant
,如其他答案/评论所述。
ZonedDateTime::isEqual
或者您可以使用 isEqual
method ,它比较两个 ZonedDateTime
实例是否对应于相同的 Instant
:
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime zoneDateTimeEtcUtc = now.withZoneSameInstant(ZoneId.of("Etc/UTC"));
ZonedDateTime zoneDateTimeUtc = now.withZoneSameInstant(ZoneId.of("UTC"));
Assert.assertTrue(zoneDateTimeEtcUtc.isEqual(zoneDateTimeUtc));
关于java - ZonedDateTime 比较 : expected: [Etc/UTC] but was: [UTC],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48462758/