FastDateFormat解析器输出不正确的时间

时间:2017-12-15 15:49:31

标签: java timestamp apache-commons

我一直在试图理解为什么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个小时。这里发生了什么?

1 个答案:

答案 0 :(得分:1)

TL; DR

    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表示时间轴上的某个点,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格式模式。在SimpleDateFormatFastDateFormat中,首都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

SimpleDateFormat documentation