簡體   English   中英

手動將 java.sql.Timestamp 轉換為 LocalDate 時的奇怪行為

[英]Strange behaviour when manually converting java.sql.Timestamp to LocalDate

我構建了一個將 TimeStamp 轉換為 LocalDate 的小函數,並偶然發現了奇怪的行為。 這是代碼:

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Test {

  private static void convert(long seconds) {
    System.out.printf("At %d seconds%n", seconds);
    Timestamp t = new Timestamp(seconds * 1000L);
    System.out.format("Timestamp: %s%n", t);
    Instant i = t.toInstant();
    System.out.format("Instant:   %s%n", i);
    ZonedDateTime atZone = i.atZone(ZoneId.systemDefault());
    System.out.format("at Zone:   %s%n", atZone);
    LocalDate localDate = atZone.toLocalDate();
    System.out.format("LocalDate: %s%n", localDate);
  }
}

我當地的時區是歐洲/柏林。 現在,當為 Timestamp 0 調用它時,我得到了正確的結果:

At 0 seconds
Timestamp: 1970-01-01 01:00:00.0
Instant:   1970-01-01T00:00:00Z
at Zone:   1970-01-01T01:00+01:00[Europe/Berlin]
LocalDate: 1970-01-01

一切都如預期的那樣。 但是當我用第 1 年的日期調用它時,它辜負了我的期望:

At -62135769600 seconds
Timestamp: 0001-01-01 01:00:00.0
Instant:   0000-12-30T00:00:00Z
at Zone:   0000-12-30T00:53:28+00:53:28[Europe/Berlin]
LocalDate: 0000-12-30

問題:

  1. 轉換為 Instant 后缺少一天,所以當時 UTC 和歐洲/柏林的時區似乎是一天加一小時?
  2. 將 Instant 轉換回我的時區時,6 分 32 秒會在某處丟失! 這是為什么?
  3. 生成的 LocalDate 不正確。 進行轉換的可靠方法是什么?

我在嘗試從 XMLGregorianCalendar 切換到 java.time.ZonedDateTime 時遇到了這個問題,我們的系統依賴於第 1 年來表示“最小”日期。 一旦您在 Julian-Gregorian 過渡之前開始在日期之間轉換,事情就會變得非常奇怪。 例如201年 200年

這是 Javadoc 片段,它暗示了早年有些有趣的事情

GregorianCalendar 實現了可預測的格里高利歷和儒略歷。 也就是說,日期是通過在時間上向后和向前無限地外推當前規則來計算的。 因此,GregorianCalendar 可用於所有年份以生成有意義且一致的結果。 但是,使用 GregorianCalendar 獲得的日期僅從公元 4 年 3 月 1 日起才在歷史上准確,當時采用了現代儒略歷規則。 在此日期之前,閏年規則的應用是不規則的,在公元前 45 年之前,儒略歷甚至不存在。

https://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html

如果你打開 GregorianCalendar 的源代碼,你會發現另一個可愛的“實施說明”,它暗示了更多的瘋狂:

 * Likewise, with the Julian calendar, we assume a consistent
 * 4-year leap year rule, even though the historical pattern of
 * leap years is irregular, being every 3 years from 45 BCE
 * through 9 BCE, then every 4 years from 8 CE onwards, with no
 * leap years in-between.  Thus date computations and functions
 * such as isLeapYear() are not intended to be historically
 * accurate.

我編寫了一個日期轉換庫,我相信它以“預期”的方式實現了日期類型之間的轉換: https : //github.com/beirtipol/date-converters 我希望能夠在 1582 年之前的 java.util 和 java.time 日期之間提供一致的轉換(Julian-> Gregorian shift),但它並不完整。

為了回答您的部分問題,我不確定是否有一種可靠的方法可以在不測試 1582 年之前的每個日期和時區的情況下執行此操作。 我正在嘗試這樣做,如果我弄明白了,我會回帖,但是前面還有很長的測試路!

以下是有關羅馬-朱利安-格里高利輪班的樂趣的更多信息: https : //www.timeanddate.com/calendar/julian-calendar.html

問題似乎是由您的輸入參數引起的轉換函數。 “在 -62135769600 秒”顯示您的輸入值超出了燒焦的長度限制。 下面是代表第一年時間戳的輸入值的測試輸出 (370 * 24 * 60 * 60)。

At 31968000 seconds
Timestamp: 1971-01-06 01:00:00.0
Instant:   1971-01-06T00:00:00Z
at Zone:   1971-01-06T01:00+01:00[Europe/Berlin]
LocalDate: 1971-01-06

暫無
暫無

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

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