And*_*niy 13 java datetime date datetime-comparison zoneddatetime
我正在比较似乎相同的两个日期,但它们包含不同的区域名称:一个是Etc/UTC,另一个是UTC.
根据这个问题:UTC和Etc/UTC时区之间有区别吗? - 这两个区域是相同的.但我的测试失败了:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
java.lang.AssertionError:
Expected :2018-01-26T13:55:57.087Z[Etc/UTC]
Actual :2018-01-26T13:55:57.087Z[UTC]
Run Code Online (Sandbox Code Playgroud)
更具体地说,我希望,这ZoneId.of("UTC")将等于ZoneId.of("Etc/UTC"),但它们不是!
正如@NicolasHenneaux 所说,我应该使用compareTo(...)方法.这是个好主意,但zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc)返回-16值,因为这里面的实现ZoneDateTime:
cmp = getZone().getId().compareTo(other.getZone().getId());
Run Code Online (Sandbox Code Playgroud)
断言结果:
java.lang.AssertionError:
Expected :0
Actual :-16
Run Code Online (Sandbox Code Playgroud)
所以问题出在ZoneId实施的某个地方.但我仍然希望如果两个区域ID都有效并且两者都指定相同的区域,那么它们应该是相同的.
我的问题是:它是一个库错误,还是我做错了什么?
UPDATE
有几个人试图说服我这是一种正常行为,比较方法的实现使用id表示是正常String的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);
}
Run Code Online (Sandbox Code Playgroud)
如果Etc/UTC 是相同的UTC,那么我看到两个选项:
Zone.of(...)是破碎的,应该对待Etc/UTC和UTC作为相同的时区.否则我不明白为什么UTC+0并且UTC工作正常.
UPDATE-2我报告了一个错误,ID:9052414.将看看Oracle团队将决定什么.
UPDATE-3接受错误报告(不知道他们是否会将其关闭为"不会修复"):https://bugs.openjdk.java.net/browse/JDK-8196398
小智 9
您可以将ZonedDateTime对象转换Instant为已经告知的其他答案/评论.
ZonedDateTime::isEqual或者您可以使用该isEqual方法,该方法比较两个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));
Run Code Online (Sandbox Code Playgroud)