1

当我尝试将 a 转换ZonedDateTime为 a 时,Timestamp一切都很好,直到我调用Timestamp.from()以下代码:

ZonedDateTime currentTimeUTC = ZonedDateTime.now(ZoneOffset.UTC);
currentTimeUTC = currentTimeUTC.minusSeconds(currentTimeUTC.getSecond());
currentTimeUTC = currentTimeUTC.minusNanos(currentTimeUTC.getNano());
return Timestamp.from(currentTimeUTC.toInstant());

ZonedDateTime.now(ZoneOffset.UTC); -> 2018-04-26T12:31Z
currentTimeUTC.toInstant() -> 2018-04-26T12:31:00Z
Timestamp.from(currentTimeUTC.toInstant()) -> 2018-04-26 14:31:00.0 
// (with Timezone of Europe/Berlin, which is currently +2)

为什么Timestamp.from()不注意即时设置的时区?

4

3 回答 3

4

该类Instant没有时区,它只有自 unix 纪元以来的秒和纳秒值。ATimestamp也代表那个(从纪元开始的计数)。

为什么调试器会在后面显示一个 Z ?

问题出在toString方法上:

Instant.toString()将秒和纳秒值转换为 UTC 中的相应日期/时间 - 因此最后是“Z” - 我相信这样做是为了方便(使 API 更“对开发人员友好”)。

javadoctoString说:

使用 ISO-8601 表示的这个瞬间的字符串表示。
使用的格式与DateTimeFormatter.ISO_INSTANT.

如果我们看一下DateTimeFormatter.ISO_INSTANTjavadoc

以 UTC 格式格式化或解析瞬间的 ISO 瞬间格式化程序,例如 '2011-12-03T10:15:30Z'

由于调试器通常使用该toString方法来显示变量值,这就解释了为什么Instant最后看到的是“Z”,而不是秒/纳秒值。

另一方面,Timestamp.toString使用 JVM 默认时区将秒/纳米值转换为日期/时间字符串。

但是两者的值InstantTimestamp相同的。您可以通过调用 和 方法来检查Instant.toEpochMilliTimestamp.getTime两者都将返回相同的值。


注意:您可以使用以下方法,而不是调用minusSecondsand :minusNanostruncatedTo

ZonedDateTime currentTimeUTC = ZonedDateTime.now(ZoneOffset.UTC);
currentTimeUTC = currentTimeUTC.truncatedTo(ChronoUnit.MINUTES);

这会将所有小于ChronoUnit.MINUTES(在本例中为秒和纳秒)的字段设置为零。

你也可以使用withSecond(0)and withNano(0),但在这种情况下,我认为truncatedTo更好更直接。


注意 2:java.time API 的创建者还为 Java 6 和 7 做了一个反向移植,在项目的 github 问题中你可以看到关于Instant.toString. 这个问题的相关部分:

如果我们真的很严格,那么 Instant 的 toString 就是从 1970-01-01Z 开始的秒数。我们选择不这样做,并输出一个更友好的 toString 来帮助开发者

这强化了我的观点,即该toString方法的设计是为了方便和易于使用。

于 2018-04-26T16:04:22.430 回答
2

Instant 不保存时区信息。它只保存秒和纳秒。当您将 ZonedDateTime 转换为 Instant 时,信息将丢失。转换为 Timestamp 时,Timestamp 将保存默认时区,在您的情况下为 Europe/Berlin。

于 2018-04-26T12:39:30.660 回答
2
于 2018-04-26T22:56:43.177 回答