Scalaプロジェクトに取り組んでおり、OffsetDateTime
タイプをSQLTimestamp
タイプにマップする必要があります。DBでUTC時間を設定したいと思います。
OffsetDateTime
からTimestamp
への変換は簡単で( この質問 からのヒント)、期待どおりに機能します。
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
ご覧のとおり、タイムゾーンが削除され、タイムスタンプが2時間前に戻っています(UTC)。
Timestamp
からOffsetDateTime
への変換が期待どおりに機能しない:
OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.systemDefault())
// Java.time.OffsetDateTime = 2017-04-04T19:46:33.567+02:00
新しく作成されたOffsetDateTime
にタイムゾーンが追加されましたが、時刻が正しくありません(UTCのままなので、実際のタイムゾーンに適合させる必要があります)。
どうして?私は何が間違っているのですか?
Java.sql.Timestamp
はエポックミリを格納しますが、.toString
メソッドはデフォルトのタイムゾーンを使用して文字列をレンダリングします。また、.valueOf
はデフォルトのタイムゾーンを使用してLocalDateTime
を解釈します。
両方の組み合わせにより、最初の変換が正しく「見える」ようになりますが、実際には間違っています。値「2017-04-0419:46:33.567」は、UTCではなくデフォルトのTZに表示されています。
valueOf
メソッドに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
参照されたstackoverflowの質問に対する受け入れられた答えは間違っています。
最初の変換を修正したら(.atZoneSameInstant
を削除して)、2番目の変換は問題なく機能するはずです。
_Java.sql.Timestamp
_は、エポック(_1970-01-01T00:00:00.000 UTC
_)からのミリ秒を表すlong
値の薄いラッパーです。したがって、UTCタイムゾーンは_Java.sql.Timestamp
_に暗黙的に含まれます。タイムゾーン情報を保存することはできませんが、暗黙的にUTCであり、誰もがそれを知っている限り、すべて機能します。タイムゾーン情報を_Java.sql.Timestamp
_に保存する方法はありません。入力データで受信したタイムゾーンを覚えておく必要がある場合は、DBの別の列として保存してください。 _Java.sql.Timestamp
_に正しい時刻を保存することはできますが、入力データで受信したタイムゾーンを保存することはできません。そのためには、追加のフィールドが必要です。
DBの日付をUTCにしたいので、次のようにDBからデータを取得できます:OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.of("UTC"))
。これは正しい時点ですが、UTCタイムゾーンです。 _+0200
_はタイムゾーンコンポーネントを格納しないため、DBに保存する前にOffsetDateTime
が_Java.sql.Timestamp
_タイムゾーンにあったという事実をDBから取得することはできません。その情報が必要な場合は、DBの別の列に保存する必要があります。