我一直在绞尽脑汁试图理解为什么 FastDateFormat 解析器返回的时间非常不正确。我尝试转换的字符串时间戳采用 GMT/UTC 格式,我正尝试将其插入 DB2 中的时间戳列。
代码如下:
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个小时。这里发生了什么?
最佳答案
长话短说
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.time
我建议您删除 java.sql.Timestamp
类。它早就过时了,今天我们在 java.time
中有了更好的东西,现代 Java 日期和时间 API。 Timestamp
的最初目的是在 SQL 数据库中存储和检索日期时间值。使用足够新的 JDBC 驱动程序 (JDBC 4.2),您可以并且将希望利用 java.time
中的两个类来实现该目的:Instant
timeline 和 LocalDateTime
表示没有时区的日期和时间。
如果您确实需要Timestamp
(例如您不想立即升级的遗留 API 或较旧的 JDBC 驱动程序),请转换 Instant
从上面到 Timestamp
就在将它交给遗留 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 设置为美国/芝加哥时区。 3 月份距 UTC -5 小时的其他时区将产生相同的结果。由于 Timestamp
是在偏移量 -5:00 处打印的,因此输出中的明显差异略小于 4 天 20 小时的实际差异,“仅”4 天 15 小时。
相比之下,尽管现代 DateTimeFormatter
大多使用相同的格式模式字母,但大写 S
表示秒的小数部分,这就是我们得到预期的 30.417 秒的原因和期望。
行情
All patterns are compatible with SimpleDateFormat (except time zones and some year patterns - see below).
( FastDateFormat
documentation )
S Millisecond Number 978
关于java - FastDateFormat 解析器输出不正确的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47835723/