如何 add/subtract TimeZone Offset to a Timestamp in Java?

How to add/subtract TimeZone Offset to a Timestamp in Java?

我正在使用 JDK 8,并且经常使用 ZonedDateTimeTimestamp。但是我仍然无法解决我面临的问题。

假设我在 GMT (UTC) 中得到一个格式化的 Timestamp 并且我的服务器位于某处。假设它设置为 Asia/Calcutta TimeZone(其 ZoneOffset 为 +05:30)。

如何基本上 add/subtract 我的时区偏移到时间戳?

Input : 2017-09-13 13:10:30.333
Output: 2017-09-13 18:40:30.333

解释:在输入中,5hrs 30mts 的时区偏移量已添加到输入中。此外,输入是时间戳类型,输出也是。

我使用 ZoneID.systemDefault() 函数来检索 JVM 已知的时区。在我的例子中,TimeZone 结果是 Asia/Calcutta.

A java.sql.Timestamp 没有任何时区信息。它只有一个值*:自 unix 纪元以来的纳秒数(1970-01-01T00:00Z"January 1st 1970 at midnight in UTC")。 您没有将此值转换为时区,因为此数字未附加到任何特定时区。

打印Timestamp时,调用了toString()方法,打印出JVM默认时区对应的日期和时间。但是 Timestamp 本身没有附加时区。

查看 this article 了解更多信息。它谈到 java.util.Date,但概念是相同的:这些对象不携带任何格式或时区信息,因此您不能在时区之间转换它们。您可以更改的是这些值在不同区域中的表示

示例:如果我将 1505308230333000000 作为纪元以来的纳秒数。同样的数字在 UTC 中表示 13:10,在圣保罗表示 10:10,在伦敦表示 14:10,在东京表示 22:10,在加尔各答表示 18:40,等等。

Timestampclass只保留大数值*。这个相同的值在每个时区对应不同的date/time,但它的值对每个人来说总是相同的

这就是为什么在不同区域之间转换 Timestamp 没有意义:您的 Timestamp 对象已经代表 both 13:10 在 UTC 和 18:40 in Calcutta(它包含对应于各个时区中的这些 date/times 的大数值 - 更改此值将更改所有时区的相应本地 date/times)。

你可以改变的是这个大数值的String表示(指定时区对应的本地date/time)。


如果你想得到 String 在另一个时区的相应日期和时间,你可以使用 java.time classes.

首先您需要将 java.sql.Timestamp 转换为 java.time.Instant,然后将其转换为时区,从而得到 java.time.ZonedDateTime。最后,我使用 java.time.format.DateTimeFormatter:

将其格式化为 String
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
// convert the timestamp to a zoneddatetime
ZonedDateTime z = timestamp.toInstant().atZone(ZoneId.of("Asia/Calcutta"));
// format it
System.out.println(z.format(fmt)); // 2017-09-13 18:40:30.333

输出为:

2017-09-13 18:40:30.333


如果您已经知道要使用哪个时区(在本例中为 Asia/Calcutta),请不要使用默认时区 (ZoneID.systemDefault()) - 当然您可以根据需要使用它,请记住它 ,因此最好始终明确说明您使用的是哪一个。


*实际上,Timestamp 将大数值保存在两个字段中:一个用于秒,另一个用于纳秒值。但这是一个实现细节,不会改变这个值不附加到任何时区的概念,因此在区域

之间转换 Timestamp 没有意义