我在编写一个测试用例时遇到了这个问题,我不得不在一个时间戳范围内获得一系列记录–使用H2
嵌入式数据库和spring-data-jpa
。
原始问题位于:Fetching records BETWEEN two java.time.Instant instances in Spring Data Query
我将时间戳记作为java.time.Instant
实例。
如果用户未提供起始时间戳,我继续进行操作,分别插入Instant.MIN
和Instant.MAX
。
让我感到困惑的是,以下测试用例通过了:
@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));
}
此外,如果past
和future
不是MIN / MAX值,而是正常值,则结果符合预期。
有人知道为什么java.sql.Timestamp的行为是这样的吗?
此外,如果Instant所表示的时间对于Timestamp而言太大,不是应该失败吗?
P.S。如果已经问过这个问题,由于我找不到原始照片,有人可以链接它吗。
编辑:添加了我在注释部分中提到的调试信息,以便我们将所有内容都放在一个地方。
对于由Timestamp
和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
对于由Timestamp
和Long.MIN_VALUE
制成的Long.MAX_VALUE
实例,我得到:
past = 292278994-08-16 23:12:55.192
future = 292278994-08-16 23:12:55.807
present = 2018-07-23 10:49:54.281
为澄清我的问题,时间戳应该显式地失败,而不是无声地失败或在内部使用其他值。目前还没有。
答案 0 :(得分:3)
这是Timestamp
类中的一个已知错误,它是从Instant
转换而来的。它在三年半前的2015年1月在Java错误数据库中注册(并且仍然开放,没有确定的修复版本)。请参阅底部的官方错误报告链接。
Timestamp.from(Instant)
的文档对此非常清楚:
Instant
可以在以后的时间线上存储点,并且 比Date
更远。在这种情况下,此方法将 引发异常。
是的,应该抛出异常。
在Java 10上,我重现了一些示例,其中转换默默地给出了错误的结果,而不是引发异常。一个例子是:
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-14 14:20:42.0-> + 184554049-09-14T12:20:42Z
以前的转换很明显是错误的:过去的时间已经转换为遥远的时间(尽管不是很远)(转换回Instant
似乎是正确的)。
奇怪的是,这里是转换方法的实现:
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);
}
}
似乎作者曾期望乘法中的算术溢出会导致ArithmeticException
。不会。