我一直在试图理解为什么FastDateFormat解析器返回的时间非常不正确。我试图转换的字符串时间戳是GMT / UTC,我试图将它插入DB2中的Timestamp列。
以下是代码:
String gmtTimestamp = "2017-03-12 02:38:30.417000000";
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSSSSSSS", TimeZone.getTimeZone("GMT"));
java.util.Date d = fdf.parse(gmtTimestamp);
Timestamp ts1 = new Timestamp(d.getTime());
System.out.println(ts1);
打印时间为:“2017-03-16 17:28:30.0”,4天,近15个小时。这里发生了什么?
答案 0 :(得分:1)
String gmtTimestamp = "2017-03-12 02:38:30.417000000";
DateTimeFormatter dtf
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSSSS");
Instant i1 = LocalDateTime.parse(gmtTimestamp, dtf)
.atOffset(ZoneOffset.UTC)
.toInstant();
System.out.println(i1);
打印
2017-03-12T02:38:30.417Z
对Instant.toString()
的隐式调用以UTC格式生成日期和时间(出于我们的目的与GMT相同),因此您可以从GMT字符串中识别日期和时间。
我建议您放弃java.sql.Timestamp
课程。它已经过时了,今天我们在java.time
,现代Java日期和时间API方面做得更好。 Timestamp
的最初目的是在SQL数据库中存储和检索日期时间值。使用足够新的JDBC驱动程序(JDBC 4.2),您可以并且希望利用java.time
中的两个类来实现此目的:Instant
表示时间轴上的某个点,LocalDateTime
表示Timestamp
没有时区的日期和时间。
如果您确实需要Instant
(例如,对于遗留API或旧版JDBC驱动程序,您不想立即升级),请将Timestamp
从上面转换为{{1在将其交给遗留API或数据库之前:
Timestamp ts1 = Timestamp.from(i1);
System.out.println(ts1);
在美国/芝加哥时区跑步打印:
2017-03-11 20:38:30.417
Timestamp.toString()
获取JVM的时区设置并输出此时区的日期和时间(这可能令人困惑)。
FastDateFormat
使用SimpleDateFormat
格式模式。在SimpleDateFormat
和FastDateFormat
中,首都S
表示毫秒。所以417000000被视为毫秒(你打算在417毫秒),它与4天20小时相同,它被添加到日期时间值直到秒。我使用SimpleDateFormat
复制了您的结果,并将我的JVM设置为America / Chicago时区。距离UTC 3月-5小时的其他时区将产生相同的结果。由于Timestamp
打印在偏移-5:00,因此输出的明显差异略小于4天20小时的实际差异,“仅”4天15小时。
相比之下,虽然现代DateTimeFormatter
大多使用相同格式的模式字母,但是大写S
意味着小数秒,这就是为什么我们得到预期和期望的30.417秒。
所有模式都与SimpleDateFormat兼容(时区除外) 和一些年份模式 - 见下文。
(FastDateFormat
documentation)
S Millisecond Number 978