scala 如何将 java.sql.Timestamp 转换为 java.time.OffsetDateTime?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/43216737/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert java.sql.Timestamp to java.time.OffsetDateTime?
提问by boh717
I'm working on a Scala project and I need to map OffsetDateTimetype to SQL Timestamptype. In DB I would like to have UTC times.
我正在处理一个 Scala 项目,我需要将OffsetDateTime类型映射到 SQLTimestamp类型。在数据库中,我想要 UTC 时间。
The conversion from OffsetDateTimeto Timestampis straightforward (hint from this question) and it works as expected:
从OffsetDateTimeto的转换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
As you can see, timezone is removed and the Timestamp is two hours back in time (UTC), great!
如您所见,时区被删除,时间戳是两个小时的时间 (UTC),太棒了!
Converting back Timestampto OffsetDateTimeisn't working as expected:
转换回Timestamp至OffsetDateTime不能按预期工作:
OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.systemDefault())
// java.time.OffsetDateTime = 2017-04-04T19:46:33.567+02:00
Timezone has been added to the newly created OffsetDateTime, but the time is not correct (it's still UTC, I need that it is adapted to the actual timezone).
时区已添加到新创建的OffsetDateTime,但时间不正确(它仍然是 UTC,我需要它适应实际时区)。
Why? What am I doing wrong?
为什么?我究竟做错了什么?
回答by Alvaro Carrasco
Although java.sql.Timestampstores the epoch millis, the .toStringmethod uses the default timezone to render the string. Also, the .valueOfinterprets the LocalDateTimeusing your default timezone. 
虽然java.sql.Timestamp存储了纪元毫秒,但该.toString方法使用默认时区来呈现字符串。此外,.valueOf解释LocalDateTime使用您的默认时区。
The combination of both things, causes the first conversion to "look" correct, but it is in fact wrong. The value "2017-04-04 19:46:33.567" is being shown in your default TZ, not UTC.
两者的结合,导致第一次转换“看起来”正确,但实际上是错误的。值“2017-04-04 19:46:33.567”显示在您的默认 TZ 中,而不是 UTC。
Because you passed the valueOfmethod a LocalDateTime(UTC), but it interpreted it as a LocalDateTime(Your default TZ).
因为您传递了valueOf方法 a LocalDateTime(UTC),但它会将其解释为LocalDateTime(您的默认 TZ)。
Here is proof that the first conversion is wrong:
这是第一次转换错误的证明:
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
Now with the .atZoneSameInstantremoved:
现在.atZoneSameInstant删除:
scala> Timestamp.valueOf(now.toLocalDateTime).getTime == now.toInstant.toEpochMilli
res53: Boolean = true
The accepted answer to the referenced stackoverflow question is wrong.
对引用的 stackoverflow 问题的公认答案是错误的。
Once you fix the first conversion (remove .atZoneSameInstant) then your second conversion should work just fine.
一旦您修复了第一个转换 (remove .atZoneSameInstant),那么您的第二个转换应该可以正常工作。
回答by radumanolescu
java.sql.Timestampis a thin wrapper around a longvalue representing milliseconds since the epoch (1970-01-01T00:00:00.000 UTC) - so the UTC timezone is implicit in java.sql.Timestamp. It cannot store any timezone info, but implicitly it's in UTC, and as long as everyone knows that, it all works. There is no way to store timezone info in a java.sql.Timestamp. If you need to remember what timezone you received in your input data, save it as a separate column in the DB. You are able to save a correct moment in time in java.sql.Timestamp- but not the timezone received in the input data. For that you need an extra field.
java.sql.Timestamp是一个围绕long表示自纪元 ( 1970-01-01T00:00:00.000 UTC)以来的毫秒数的值的薄包装器- 因此 UTC 时区隐含在java.sql.Timestamp. 它不能存储任何时区信息,但它隐含在 UTC 中,只要每个人都知道,它就可以正常工作。无法将时区信息存储在java.sql.Timestamp. 如果您需要记住在输入数据中收到的时区,请将其保存为数据库中的单独列。您可以及时保存正确的时刻java.sql.Timestamp- 但不能保存在输入数据中收到的时区。为此,您需要一个额外的字段。
Since you like your DB dates to be in UTC, you can retrieve the data from the DB like this: OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.of("UTC")). This will be the correct point in time, but in the UTC timezone. You cannot retrieve from the DB the fact that the OffsetDateTimewas in the +0200timezone before you saved it to the DB, because java.sql.Timestampdoes not store a timezone component. If you need that info, you need to store it in a separate column in the DB.
既然你喜欢你的DB日期是UTC,你可以从数据库这样的数据:OffsetDateTime.ofInstant(Instant.ofEpochMilli(tstamp.getTime), ZoneId.of("UTC"))。这将是正确的时间点,但在 UTC 时区。OffsetDateTime在将其+0200保存到数据库之前,您无法从数据库中检索它在时区中的事实,因为java.sql.Timestamp它不存储时区组件。如果您需要该信息,则需要将其存储在数据库中的单独列中。

