从java.time.Instant生成的java.sql.Timestamp的最小值/最大值与从Long.MIN\u值/Long.MAX\u值构造时的行为不同
我在编写一个测试用例时遇到了这个问题,在这个测试用例中,我必须获得一系列时间戳之间的一系列记录——使用H2嵌入式数据库和spring数据jpa 原始版本位于: 我的时间戳是java.time.Instant实例 如果用户没有给出开始-结束时间戳,我将继续并分别插入Instant.MIN和Instant.MAX 让我困惑的是,以下测试用例通过了:从java.time.Instant生成的java.sql.Timestamp的最小值/最大值与从Long.MIN\u值/Long.MAX\u值构造时的行为不同,java,java-8,java-time,java.time.instant,Java,Java 8,Java Time,Java.time.instant,我在编写一个测试用例时遇到了这个问题,在这个测试用例中,我必须获得一系列时间戳之间的一系列记录——使用H2嵌入式数据库和spring数据jpa 原始版本位于: 我的时间戳是java.time.Instant实例 如果用户没有给出开始-结束时间戳,我将继续并分别插入Instant.MIN和Instant.MAX 让我困惑的是,以下测试用例通过了: @Test public void test_date_min_max_instants_timestamps() { Timestam
@Test
public void test_date_min_max_instants_timestamps() {
Timestamp past = new Timestamp(Long.MIN_VALUE);
Timestamp future = new Timestamp(Long.MAX_VALUE);
Timestamp present = Timestamp.from(Instant.now());
assertTrue(present.after(past));
assertTrue(future.after(past));
assertTrue(future.after(present));
assertTrue(present.before(future));
assertTrue(past.before(present));
assertTrue(past.before(future));
}
但是,以下测试用例失败:
@Test
public void test_instant_ranges() throws InterruptedException {
Timestamp past = Timestamp.from(Instant.MIN);
Timestamp future = Timestamp.from(Instant.MAX);
Timestamp present = Timestamp.from(Instant.now());
assertTrue(present.after(past));
assertTrue(future.after(past));
assertTrue(future.after(present));
assertTrue(present.before(future));
assertTrue(past.before(present));
assertTrue(past.before(future));
}
此外,如果过去和未来不是最小/最大值,而是正常值,则结果与预期一致
知道java.sql.Timestamp为什么会这样吗
此外,如果Instant表示的时间对于时间戳来说太大,那么它不应该失败吗
另外,如果这个问题已经被问过了,有没有人可以链接一下原文,因为我一直找不到
编辑:添加了我在评论部分提到的调试信息,这样我们就可以把所有东西都放在一个地方
对于从Instant.MIN和Instant.MAX生成的时间戳实例,我有以下值:
past = 169108098-07-03 21:51:43.0
future = 169104627-12-11 11:08:15.999999999
present = 2018-07-23 10:46:50.842
对于由Long.MIN_值和Long.MAX_值生成的时间戳实例,我得到:
为了澄清我的问题,时间戳应该显式失败,而不是静默失败或在内部使用不同的值。目前没有。这是Timestamp类及其从Instant转换中的已知错误。三年半前,它于2015年1月在Java bug数据库中注册,目前仍然开放,没有确定的修复版本。请参阅底部的官方bug报告链接 预期的行为是明确的 Timestamp.fromInstant的文档对此非常清楚: Instant可以在将来和将来进一步存储时间线上的点 在过去比现在更远。在此场景中,此方法将 抛出异常 所以是的,应该抛出一个异常 复制错误很简单 在我的Java10上,我复制了两个示例,其中转换默默地给出了错误的结果,而不是抛出异常。一个例子是:
Instant i = LocalDate.of(-400_000_000, Month.JUNE, 14)
.atStartOfDay(ZoneId.of("Africa/Cairo"))
.toInstant();
Timestamp ts = Timestamp.from(i);
System.out.println("" + i + " -> " + ts + " -> " + ts.toInstant());
这张照片是:
-400000000-06-13T21:54:51Z->184554049-09-1414:20:42.0->+184554049-09-14T12:20:42Z
前一种转换显然是错误的:一个遥远过去的时间被转换成了一个遥远的时间,尽管不是那么遥远的未来。回到瞬间的转换似乎是正确的
附录:JDK源代码
出于好奇,以下是转换方法的实现:
public static Timestamp from(Instant instant) {
try {
Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND);
stamp.nanos = instant.getNano();
return stamp;
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(ex);
}
}
似乎作者预期乘法运算中的算术溢出会导致算术异常。事实并非如此
链接
此外,如果Instant表示的时间对于时间戳来说太大,那么它不应该失败吗?而不是什么?。使用step调试器可以非常快速轻松地回答您的问题。在使用StackOverflow之前,您应该始终尝试使用step调试器解决问题。对于由Instant.MIN和Instant.MAX生成的时间戳实例-过去=169108098-07-03 21:51:43.0未来=169104627-12-11 11:08:15.99999999当前=2018-07-23 10:46:50.842以及由Long.MIN_值和Long.MAX_VALUE,我得到:pass=292278994-08-16 23:12:55.192 future=292278994-08-16 23:12:55.807 present=2018-07-23 10:49:54.281 P.S.我发布这个问题的原因是因为我自己无法解决它。@shmosel没有默默失败或在内部使用不同的值。基本上,我想说的是:如果不可能的话,转换应该会显式失败。感谢@sidmishraw添加更多信息。请在问题中这样做,而不是在评论中这样做,这样我们就把一切都放在一个地方了。谢谢。
public static Timestamp from(Instant instant) {
try {
Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND);
stamp.nanos = instant.getNano();
return stamp;
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(ex);
}
}