簡體   English   中英

java.time.Instant制作的java.sql.Timestamp的MIN / MAX行為與從Long.MIN_VALUE / Long.MAX_VALUE構造時的行為不同

[英]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.MINInstant.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));
  }

此外,如果pastfuture不是MIN / MAX值,而是正常值,則結果如預期。

知道為什么java.sql.Timestamp會像這樣嗎?

另外,如果Instant表示的時間對於Timestamp來說太大了,那么它不應該失敗嗎?

PS如果已經問過這個問題,有人可以鏈接原件,因為我找不到它。

編輯:添加了我在評論部分提到的調試信息,以便我們在一個地方擁有所有內容。

對於由Instant.MINInstant.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_VALUELong.MAX_VALUETimestamp實例,我得到了:

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似乎是正確的)。

附錄: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);
    }
}

似乎作者曾預料到乘法中的算術溢出會導致ArithmeticException 它不是。

鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM