2017-04-04 189 views
4

我正在開發一個Scala項目,我需要將OffsetDateTime類型映射到SQL Timestamp類型。在數據庫我想有UTC時間。如何將java.sql.Timestamp轉換爲java.time.OffsetDateTime?

OffsetDateTimeTimestamp轉化爲簡單的(提示從this question),它按預期工作:

import java.time._ 
import java.sql.Timestamp 
val ofsdatetime = OffsetDateTime.now() 
// ofsdatetime: java.time.OffsetDateTime = 2017-04-04T21:46:33.567+02:00 

val tstamp = Timestamp.valueOf(ofsdatetime.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime()) 
// tstamp: java.sql.Timestamp = 2017-04-04 19:46:33.567 

正如你所看到的,時區被刪除,時間戳爲兩個小時回來時(UTC) ,太棒了!

轉換回TimestampOffsetDateTime不能按預期工作

OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.systemDefault()) 

// java.time.OffsetDateTime = 2017-04-04T19:46:33.567+02:00 

時區已被添加到新創建的OffsetDateTime,但時間是不正確的(它仍然是UTC,我需要它適應於實際的時區)。

爲什麼?我究竟做錯了什麼?

回答

9

儘管java.sql.Timestamp存儲時代毫秒,.toString方法使用默認時區來渲染字符串。此外,.valueOf使用您的默認時區來解釋LocalDateTime

這兩種情況的組合導致第一次轉換爲「看起來」正確,但實際上是錯誤的。價值「2017-04-04 19:46:33.567」顯示在您的默認TZ中,而不是UTC。

因爲您通過了valueOf方法a LocalDateTime(UTC),但它將其解釋爲LocalDateTime(您的默認TZ)。

這裏是證明了第一次轉換是錯誤的:

scala> val now = OffsetDateTime.now 
now: java.time.OffsetDateTime = 2017-04-04T14:50:12.534-06:00 

scala> Timestamp.valueOf(now.atZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime).getTime == now.toInstant.toEpochMilli 
res54: Boolean = false 
.atZoneSameInstant刪除

現在:

scala> Timestamp.valueOf(now.toLocalDateTime).getTime == now.toInstant.toEpochMilli 
res53: Boolean = true 

接受的答案被引用的計算器的問題是錯誤的。

一旦你修復了第一次轉換(刪除.atZoneSameInstant),那麼你的第二次轉換應該工作得很好。

2
java.sql.Timestamp

是周圍從epoch(1970-01-01T00:00:00.000 UTC)一個long代表值毫秒的薄包裝紙 - 這樣的UTC時區是在java.sql.Timestamp隱式的。它不能存儲任何時區信息,但隱含在UTC中,只要每個人都知道,它一切正常。沒有辦法將時區信息存儲在java.sql.Timestamp中。如果您需要記住您在輸入數據中收到的時區,請將其另存爲數據庫中的單獨列。您可以在java.sql.Timestamp中保存一個正確的時間 - 但不是輸入數據中收到的時區。爲此,你需要一個額外的領域。

既然你喜歡你的數據庫日期是UTC,你可以像這樣從數據庫中檢索數據:OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.of("UTC"))。這將是正確的時間點,但在UTC時區。因爲java.sql.Timestamp不存儲時區組件,所以您無法從數據庫檢索到OffsetDateTime時區在+0200時區之前的事實。如果您需要這些信息,則需要將其存儲在數據庫的單獨列中。

相關問題