Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将java.sql.Timestamp转换为java.time.OffsetDateTime?_Java_Scala_Java 8_Slick - Fatal编程技术网

如何将java.sql.Timestamp转换为java.time.OffsetDateTime?

如何将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-

我正在处理一个Scala项目,我需要将
OffsetDateTime
类型映射到SQL
Timestamp
类型。在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
方法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
现在,已删除
.atzonesamainstant

scala> Timestamp.valueOf(now.toLocalDateTime).getTime == now.toInstant.toEpochMilli
res53: Boolean = true
引用的stackoverflow问题的公认答案是错误的


一旦您修复了第一次转换(删除
.atZoneSameInstant
),那么您的第二次转换应该可以正常工作。

这是一个很好的答案,但是您认为我们应该直接调用
Timestamp.toInstant()
?上面的代码调用:
Instant.ofEpochMilli(tstamp.getTime)
。据我所知,我们将失去毫秒以下的精度。