我正在使用JDK 8,并且我玩了很多 ZonedDateTime
和 Timestamp
。但是我仍然无法解决我面临的问题的解决方案。
可以说,我在GMT(UTC)中获得了格式化的Timestamp
,并且我的服务器位于某个地方。假设它设置为Asia/Calcutta
时区(其区域offset为 +05:30
)。
如何基本上添加/减去我的时区偏移到时间戳?
Input : 2017-09-13 13:10:30.333
Output: 2017-09-13 18:40:30.333
说明:在输入中,添加了5小时30mts的时区偏移量已添加到输入中。另外,输入是类型的时间戳,输出也是。
我使用ZoneID.systemDefault()
功能检索JVM已知的时区。就我而言,时区结果为 Asia/Calcutta
。
a java.sql.Timestamp
没有任何时区信息。它只有一个值*:自Unix Epoch(1970-01-01T00:00Z
或" 1月1日 ST 1970年午夜时分在UTC的nanseconds)的数量" )。您不会将此值转换为时区,因为此数字未连接到任何特定时区。
打印Timestamp
时,它调用toString()
方法,然后在JVM默认时区打印相应的日期和时间。但是Timestamp
本身没有附带时区。
请查看本文以获取更多信息。它讨论了java.util.Date
,但是概念是相同的:这些对象没有任何格式或时区信息,因此您无法在时区之间转换它们。您可以更改的是不同区域中这些值的表示。
示例:如果我将1505308230333000000
作为纳秒数的数量,则自时代以来。同样的数字在UTC中代表13:10,在圣保罗的10:10,伦敦14:10,在东京22:10,在加尔各答18:40,等等。
Timestamp
类只能保持大数值*。相同的值对应于每个时区中的不同日期/时间,,但每个人的值始终相同。
这就是为什么在不同区域之间转换 Timestamp
是没有道理的:您的 Timestamp
对象已经代表在utc中和calcutta中的18:40(它包含与这些相对应的大数字值各个时区的日期/时间 - 更改此值将改变各个时区的本地日期/时间)。
您可以更改的是此大数字的String
表示(指定时区中的相应本地日期/时间)。
如果要在另一个时区中获得带有相应日期和时间的String
,则可以使用java.time
类。
首先,您需要将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