A java.sql.Timestamp
doesn't have any timezone information. It just has one value*: the number of nanoseconds since unix epoch (1970-01-01T00:00Z
or "January 1st 1970 at midnight in UTC"). You don't convert this value to a timezone because this number is not attached to any specific timezone.
打印时Timestamp
,它调用toString()
方法,这会打印 JVM 默认时区中相应的日期和时间。但是Timestamp
它本身没有附加时区。
看一眼本文 https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/了解更多信息。它谈到java.util.Date
,但概念是相同的:这些对象不携带任何格式或时区信息,因此您无法在时区之间转换它们。你可以改变的是表示不同区域中的这些值。
示例:如果我采取1505308230333000000
作为自纪元以来的纳秒数。这个数字代表 UTC 的 13:10、圣保罗的 10:10、伦敦的 14:10、东京的 22:10、加尔各答的 18:40 等等。
The Timestamp
类只保留大数值*。这个相同的值对应于每个时区的不同日期/时间,但它的价值对每个人来说都是一样的.
这就是为什么要转换Timestamp
不同区域之间没有任何意义:您的Timestamp
对象已经代表bothUTC 的 13:10 和加尔各答的 18:40(它包含与相应时区中的这些日期/时间相对应的大数值 - 更改此值将更改所有时区的相应本地日期/时间)。
你可以改变的是String
这个大数值的表示(指定时区中相应的本地日期/时间)。
如果你想获得一个String
不过,您可以使用另一个时区的相应日期和时间java.time
类。
首先你需要转换java.sql.Timestamp
to a 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()
) - 当然,如果你愿意,你可以使用它,只要记住它即使在运行时也可以更改,恕不另行通知 https://stackoverflow.com/a/45797132/7605325,因此最好始终明确您正在使用哪一个。
*Actually, the Timestamp
keeps the big number value in two fields: one for the seconds and another for the nanoseconds value. But that's an implementation detail, that doesn't change the concept that this value is not attached to any timezone and so there's no point in converting the Timestamp
between zones