问题描述
Java 8
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
System.out.println(inst);
此打印
2016-03-13T02:45:00Z
今天,您(通常)不需要一个Timestamp
对象。该java.sql.Timestamp
班是早已过时。一旦我们将其用于与sql数据库之间以纳秒精度传输时间戳值。今天,我们Instant
改为使用该类。Instant
是java.time
现代Java日期和时间API
的类之一(有时我们使用LocalDateTime
相同的API,这取决于您的确切要求和数据库列的数据类型)。
aTimestamp
和an中都没Instant
有时区。不同于Timestamp
所述Instant
在UTC总是打印(由表示Z
在上述输出的结束)。如您所见,以上代码段已将您的CST时间20:45
CST正确转换为第二天UTC。
如果确实需要时间戳,通常是对于您无法更改或现在不想更改的旧版API,则转换很容易:
Timestamp ts = Timestamp.from(inst);
System.out.println(ts);
2016-03-12 20:45:00.0
Timestamp.toString
使用JVM的时区设置来生成字符串,因此您可以识别出我们开始的时间。因此,Timestamp
其中包含正确的时间点。无需以任何方式进行转换。如果错误地将其插入数据库,则问题出在JDBC驱动程序,数据库或其他地方,如果可以的话,您应该更正此错误。
Java 6和7
如果将ThreeTen Backport添加到项目中,则与上述代码非常相似的代码将在Java 7中运行。这是这些java.time
类向Java
6和7的反向移植,并且在底部包括一个链接(它是JSR-310的ThreeTen,是最早描述现代API的地方)。
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
Timestamp ts = DateTimeUtils.tosqlTimestamp(inst);
您会注意到从Java 8唯一的区别是我们转换的方式Instant
到Timestamp
。结果当然是一样的。
如果您不希望依赖ThreeTen
Backport,当然还有一些方法可以获取Timestamp
。我不会像代码中那样使用不推荐使用的构造函数,即使只要没有人篡改JVM的时区设置,它就可以工作。如果您知道要Timestamp
等于02:45
UTC,则一种选择是
Timestamp ts = Timestamp.valueOf("2016-03-12 20:45:00");
但是,它仍然取决于JVM的时区设置。
您的代码出了什么问题?
如前所述,其中Timestamp
没有时区,因此将a转换Timestamp
为UTC没有任何意义。
您的代码中会发生什么:
- 不
Timestamp
建议使用的构造函数使用您的JVM的时区设置(美国/芝加哥,我认为)Timestamp
在您的时区(与3月13日UTC时间3月13日相同的时间点)的相应时间2016年3月12日构造相应的时间。 - 您将其
SimpleDateFormat
正确格式化为2016-03-13 02:45:00
(UTC)。 -
Timestamp.valueOf()
也使用美国/芝加哥时区。但是,在3月12日至13日之间的夜晚,夏季时间(夏令时)在该时区开始。凌晨2时,时钟向前移动到3.因此,有 是 没有2:45这个夜晚。Timestamp
选择3:45代替。
解决方法
public static void main(String[] args) {
Timestamp ts = new Timestamp(116,02,12,20,45,0);
Date d = new Date();
d.setTime(ts.getTime());
System.out.println(d);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
//System.out.println(ts.getTime());
System.out.println(simpleDateFormat.format(ts));
System.out.println(Timestamp.valueOf(simpleDateFormat.format(ts)));
}
在上面的代码中,最后两行打印不同的值。当前时区是CST,我想将其转换为UTC。当我将其转换时,最后两行在一小时内打印不同的值,即最后一次打印3月13日凌晨2:45,最后一次打印3月13日凌晨3:45。他们为何与众不同,我该如何纠正。