如何将java.sql.Timestamp转换成java.time.OffsetDateTime?
How to convert java.sql.Timestamp to java.time.OffsetDateTime?
我正在处理一个 Scala 项目,我需要将 OffsetDateTime
类型映射到 SQL Timestamp
类型。在数据库中,我想要 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
如您所见,时区已被删除,时间戳是两个小时后的时间 (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
是围绕 long
值的薄包装,表示自纪元 (1970-01-01T00:00:00.000 UTC
) 以来的毫秒数 - 因此 UTC 时区隐含在 java.sql.Timestamp
中。它不能存储任何时区信息,但它隐含在 UTC 中,只要每个人都知道,它就可以正常工作。无法在 java.sql.Timestamp
中存储时区信息。如果您需要记住在输入数据中收到的时区,请将其保存为数据库中的单独列。您可以在 java.sql.Timestamp
中及时保存正确的时刻 - 但不能保存输入数据中收到的时区。为此,您需要一个额外的字段。
由于您希望数据库日期采用 UTC 格式,因此您可以像这样从数据库中检索数据:OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.of("UTC"))
。这将是正确的时间点,但在 UTC 时区中。您无法从数据库中检索 OffsetDateTime
在将其保存到数据库之前处于 +0200
时区的事实,因为 java.sql.Timestamp
不存储时区组件。如果您需要该信息,则需要将其存储在数据库中的单独列中。
虽然java.sql.Timestamp
存储了纪元毫秒,.toString
方法使用默认时区来呈现字符串。此外,.valueOf
使用您的默认时区解释 LocalDateTime
。
两者结合,导致第一个转换为 "look" 正确,但实际上是错误的。值“2017-04-04 19:46:33.567”显示在您的默认 TZ 中,而不是 UTC。
因为您向 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
引用的 Whosebug 问题的公认答案是错误的。
修复第一个转换(删除 .atZoneSameInstant
)后,第二个转换应该可以正常工作。
我正在处理一个 Scala 项目,我需要将 OffsetDateTime
类型映射到 SQL Timestamp
类型。在数据库中,我想要 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
如您所见,时区已被删除,时间戳是两个小时后的时间 (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
是围绕 long
值的薄包装,表示自纪元 (1970-01-01T00:00:00.000 UTC
) 以来的毫秒数 - 因此 UTC 时区隐含在 java.sql.Timestamp
中。它不能存储任何时区信息,但它隐含在 UTC 中,只要每个人都知道,它就可以正常工作。无法在 java.sql.Timestamp
中存储时区信息。如果您需要记住在输入数据中收到的时区,请将其保存为数据库中的单独列。您可以在 java.sql.Timestamp
中及时保存正确的时刻 - 但不能保存输入数据中收到的时区。为此,您需要一个额外的字段。
由于您希望数据库日期采用 UTC 格式,因此您可以像这样从数据库中检索数据:OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.of("UTC"))
。这将是正确的时间点,但在 UTC 时区中。您无法从数据库中检索 OffsetDateTime
在将其保存到数据库之前处于 +0200
时区的事实,因为 java.sql.Timestamp
不存储时区组件。如果您需要该信息,则需要将其存储在数据库中的单独列中。
虽然java.sql.Timestamp
存储了纪元毫秒,.toString
方法使用默认时区来呈现字符串。此外,.valueOf
使用您的默认时区解释 LocalDateTime
。
两者结合,导致第一个转换为 "look" 正确,但实际上是错误的。值“2017-04-04 19:46:33.567”显示在您的默认 TZ 中,而不是 UTC。
因为您向 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
引用的 Whosebug 问题的公认答案是错误的。
修复第一个转换(删除 .atZoneSameInstant
)后,第二个转换应该可以正常工作。