「本地...」類型的故意沒有時區的概念。所以他們做而不是代表時間軸上的一個時刻。 A LocalDateTime
表示可能時刻的模糊範圍,但在分配偏移或時區之前沒有真正意義。這意味着應用ZoneId
獲得ZonedDateTime
。
例如,說今年聖誕節開始於12月25日的第一時刻,我們要說:
LocalDateTime ldt = LocalDateTime.of(2017 , 12 , 25 , 0 , 0 , 0 , 0);
但午夜的中風發生在更早的東部比西部。
這就是爲什麼精靈的物流部門在太平洋地區開始繪製聖誕老人的路線,起始地點是Kiribati,太平洋是世界最早的時區,比世界協調時早14小時。在那裏交付後,他們將聖誕老人西向路線發往新西蘭等地的午夜。然後在午夜之後回到亞洲。然後是印度等幾個小時後到達歐洲的午夜,然後是北美東海岸,晚些時候再過幾個小時。所有這些地方都經歷過相同LocalDateTime
在不同的時刻,每個送貨所代表的一個不同ZonedDateTime
對象。
所以......
- 如果你想要錄製的概念的聖誕節午夜25日之後出發,使用
LocalDateTime
和寫入TIMESTAMP WITHOUT TIME ZONE
類型的數據庫列。
- 如果您想記錄聖誕老人每次送貨的確切時刻,請使用
ZonedDateTime
並寫入類型爲TIMESTAMP WITH TIME ZONE
的數據庫列。
關於第二個項目符號,請注意,幾乎每個數據庫系統都將使用區域信息來調整UTC的日期時間並存儲該UTC值。有些還保存區域信息,但某些(如Postgres)在使用它調整爲UTC後丟棄區域信息。所以「帶時區」是一個用詞不當的地方,真的意思是「尊重時區」。如果您關心記住原始區域,您可能需要將其名稱保存在一個單獨的列中。
使用Local…
類型的另一個原因是未來約會。政治家喜歡經常改變他們轄區的時區。他們喜歡採用夏令時(DST)。喜歡改變他們DST切換的日期。他們喜歡放棄採用DST。他們喜歡重新定義他們的時區,改變邊界。他們喜歡重新定義它們的UTC偏移量,有時候會像15分鐘那樣。他們很少提前發出通知,在短短一個月或兩個小時內發出警告。
因此,要進行下一年或六個月的體檢預約,無法預測時區定義。因此,如果您要預約上午9點,則應使用記錄在TIMESTAMP WITHOUT TIME ZONE
類型的數據庫列中的LocalTime
或LocalDateTime
。否則,上午9點的預約,如果在夏令時延期的區域劃分,可能會顯示爲上午8點或上午10點。
生成投影計劃時,可以將時區(ZoneId
)應用於這些「本地」(未分區)值以創建ZonedDateTime
對象。但是,當政客們通過改變區域可能毀掉他們的意義時,不要依賴那些時間太遠的人。
提示:對DST和時區進行頻繁更改意味着您必須保持您的時區tzdata數據庫處於最新狀態。在你的主機操作系統,你的JVM中,或者在你的數據庫系統中,例如Postgres,都有一個tzdata。所有這三個應該經常更新。有時,這些區域的變化速度比計劃的更新週期更快,例如土耳其去年決定在數週前通知DST。所以你可能偶爾需要手動更新這些tzdata文件。 Oracle提供了一個更新其Java實現的tzdata的工具。
處理精確時刻的一般最佳做法是使用UTC跟蹤它們。僅在必要時才應用時區,例如向用戶展示他們希望在自己的教區時區中看到值的用戶。在java.time中,Instant
類表示時間軸中的某個時刻。 UTC的分辨率爲納秒。
Instant instant = Instant.now() ; // Current moment on the timeline in UTC.
ZonedDateTime zdt = instant.atZone(z) ; // Assign a time zone to view the same moment through the lens of a particular region’s wall-clock time.
Instant instant = zdt.toInstant(); // revert back to UTC, stripping away the time zone. But still the same moment in the timeline.
順便說一句,符合JDBC 4.2及更高版本的驅動程序可以直接處理java。時間類型通過:
PreparedStatement::setObject
ResultSet::getObject
避免舊舊的數據類型,如java.util.Date
和java.sql.Timestamp
只要有可能。它們設計不佳,混亂和缺陷。
明白,所有這四個都在UTC時間線上的時刻表示:
- 現代
java.time.Instant
java.time.OffsetDateTime
與ZoneOffset.UTC
分配的偏移
- 傳統
java.util.Date
java.sql.Timestamp
如果你想有一個日期,只值沒有時間的天,沒有時區,使用java.time.LocalDate
。這個類代替java.sql.Date
。
至於具體的數據庫,要知道,SQL標準幾乎沒有觸及到的日期時間類型及其處理的話題。此外,各種數據庫有很大的不同,我真的是廣泛,在他們的支持的日期時間的功能。有些幾乎沒有支持。有些將SQL標準類型與專有類型混合使用,這些類型要麼早於標準類型,要麼作爲標準類型的替代品。另外,JDBC驅動程序的行爲與將日期時間值封送到數據庫或從數據庫封裝日期時間值不同。一定要研究文件和練習,練習,練習。
我非常同意這樣的說法,即一段時間應該以UTC存儲,並且只有在向用戶顯示時才劃分區域。 –
我真的很希望我8歲的女兒(誰聲稱聖誕老人是不真實的)有一段時間讀這個。不僅是一個很好的答案,但是當我得到「這就是爲什麼精靈......」的時候upvoted。:) – NealeU
TimeZone精美的解釋。 Upvoted,謝謝:-) –