如何在Java中的Timestamp中添加/减去TimeZone Offset?

时间:2017-09-11 18:54:03

标签: java datetime timezone java-time timezone-offset

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

假设我在GMT(UTC)中获得格式化Timestamp,而我的服务器位于某处。让我们说它设置为Asia/Calcutta TimeZone(其ZoneOffset为+05:30)。

如何基本上将时区偏移量加/减到时间戳?

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

说明:在输入中,时区偏移量为5小时30毫米,已添加到输入中。此外,输入的类型为Timestamp,输出也是如此。

我使用ZoneID.systemDefault()函数来检索JVM已知的TimeZone。就我而言,TimeZone原来是Asia/Calcutta

1 个答案:

答案 0 :(得分:2)

java.sql.Timestamp没有任何时区信息。它只有一个值*:自UTC时间(1970-01-01T00:00Z“1月1日 st 1970年午夜的UTC”)以来的纳秒数。 您不会将此值转换为时区,因为此数字未附加到任何特定时区。

打印Timestamp时,它会调用toString()方法,并在JVM默认时区中打印相应的日期和时间。但是Timestamp本身并没有附加时区。

请查看this article了解详情。它讨论java.util.Date,但概念是相同的:这些对象不携带任何格式或时区信息,因此您无法在时区之间进行转换。您可以更改的是不同区域中这些值的表示

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

Timestamp类只保留大数值*。此相同值对应于每个时区中的不同日期/时间,但其值对于每个人始终相同。

这就是为什么在不同区域之间转换Timestamp没有任何意义:您的Timestamp对象已经代表 13:10(UTC)和18:40(加利福尼亚州)在相应时区中与这些日期/时间对应的大数值 - 更改此值将更改所有时区的相应本地日期/时间。

您可以更改的是此大数值的String表示(指定时区中相应的本地日期/时间)。

但是,如果您想在另一个时区获得具有相应日期和时间的String,则可以使用java.time类。

首先,您需要将java.sql.Timestamp转换为java.time.Instant,然后将其转换为时区,从而生成java.time.ZonedDateTime。最后,我使用String

将其格式化为java.time.format.DateTimeFormatter
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()) - 当然您可以根据需要使用它,只需保留请注意它can be changed without notice, even at runtime,所以最好总是明确表示你正在使用哪一个。

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