如何将java.sql.Timestamp转换为java.time.OffsetDateTime?
我正在处理一个Scala项目,我需要将如何将java.sql.Timestamp转换为java.time.OffsetDateTime?,java,scala,java-8,slick,Java,Scala,Java 8,Slick,我正在处理一个Scala项目,我需要将OffsetDateTime类型映射到SQLTimestamp类型。在DB中,我希望有UTC时间 从OffsetDateTime到Timestamp的转换非常简单(来自的提示),它可以按预期工作: import java.time._ import java.sql.Timestamp val ofsdatetime = OffsetDateTime.now() // ofsdatetime: java.time.OffsetDateTime = 2017-
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
正如您所看到的,时区被删除,时间戳是两小时前的时间(UTC),太棒了
将时间戳
转换回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
是一个很薄的包装,它围绕着一个长的值,表示从纪元开始的毫秒(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
保存到DB之前,您无法从DB中检索到OffsetDateTime
在+0200
时区中的事实,因为java.sql.Timestamp
不存储时区组件。如果需要该信息,则需要将其存储在数据库中的单独列中。尽管java.sql.Timestamp
存储历元毫秒,但.toString
方法使用默认时区渲染字符串。另外,.valueOf
使用默认时区解释LocalDateTime
两者的结合,导致第一次转换“看起来”正确,但实际上是错误的。值“2017-04-04 19:46:33.567”显示在默认的TZ中,而不是UTC中
因为您传递了valueOf
方法aLocalDateTime
(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
现在,已删除.atzonesamainstant
:
scala> Timestamp.valueOf(now.toLocalDateTime).getTime == now.toInstant.toEpochMilli
res53: Boolean = true
引用的stackoverflow问题的公认答案是错误的
一旦您修复了第一次转换(删除.atZoneSameInstant
),那么您的第二次转换应该可以正常工作。这是一个很好的答案,但是您认为我们应该直接调用Timestamp.toInstant()
?上面的代码调用:Instant.ofEpochMilli(tstamp.getTime)
。据我所知,我们将失去毫秒以下的精度。