[英]java.sql.Timestamp made from java.time.Instant's MIN/MAX behaves differently than when constructed from Long.MIN_VALUE / Long.MAX_VALUE
我在編寫測試用例時遇到了這個問題,我必須在一系列時間戳之間獲得一系列記錄 - 使用H2
嵌入式數據庫和spring-data-jpa
。
原始問題位於: 在Spring Data Query中獲取兩個java.time.Instant實例之間的記錄
我有時間戳作為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來說太大了,那么它不應該失敗嗎?
PS如果已經問過這個問題,有人可以鏈接原件,因為我找不到它。
編輯:添加了我在評論部分提到的調試信息,以便我們在一個地方擁有所有內容。
對於由Instant.MIN
和Instant.MAX
制作的Timestamp
實例,我有以下值:
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_VALUE
和Long.MAX_VALUE
的Timestamp
實例,我得到了:
past = 292278994-08-16 23:12:55.192
future = 292278994-08-16 23:12:55.807
present = 2018-07-23 10:49:54.281
為了澄清我的問題,時間戳應該顯式失敗,而不是靜默失敗或在內部使用不同的值。 目前它沒有。
這是Timestamp
類中的已知錯誤及其從Instant
轉換。 它是在2015年1月的Java bug數據庫中注冊的,三年半前(並且仍然沒有確定的修復版本)。 請參閱底部官方錯誤報告的鏈接。
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
。 它不是。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.