更改Java时间戳格式会导致更改时间戳

时间:2018-06-18 11:26:42

标签: java java-ee timestamp

我对Java时间戳格式化函数感到有些困惑,因为它们似乎会将时间戳更改几分钟。

我的Pivotal CloudFoundry应用程序将一个新条目写入PostgreSQL 9.4.5数据库。这样做,我让PostgreSQL为该条目生成并存储一个时间戳(在我使用的SQL语句中' now()'用于该特定列)。 到目前为止一切正常。当我用我的应用程序读取条目时出现问题,因为我必须将时间戳格式化为ISO 8601(公司策略),这似乎改变了时间戳。我已经使用了这段代码:

public String parseTimestamp(String oldDate) {
    System.out.println("String oldDate: " + oldDate);

    TimeZone timeZone = TimeZone.getTimeZone("Europe/Berlin");
    SimpleDateFormat oldDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS");
    SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    newDateFormat.setTimeZone(timeZone);

    Date tempDate = null;
    try {
        tempDate = oldDateFormat.parse(oldDate);
    } catch (ParseException e) {
        //TODO
    }

    System.out.println("tempDate before format(): " + tempDate);
    String newDate = newDateFormat.format(tempDate);
    System.out.println("tempDate after format(): " + tempDate);
    System.out.println("String newDate: " + newDate);
    return newDate;
}

输出:

String oldDate: 2018-06-18 13:07:27.624828+02
tempDate before format(): Mon Jun 18 13:17:51 CEST 2018
tempDate after format(): Mon Jun 18 13:17:51 CEST 2018
String newDate: 2018-06-18T13:17:51Z

如您所见,时间戳从13:07更改为13:17。所有其他查询条目也显示差异,在~2到10分钟之间变化。但是,当我重新运行查询时,每个差异都保持不变。 OP告诉我,所有涉及的系统都有同步时间,我不确定系统时间是否应该在这里发挥作用。

有人知道发生了什么事吗?

2 个答案:

答案 0 :(得分:2)

首先,我真的很困惑并且想到,你可能在SimpleDateFormat中找到了某种错误。您的代码可以缩减为以下行以显示相同的行为:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS");
String str = "2018-06-18 13:07:27.624828+02";
System.out.println(str);
System.out.println(format.parse(str));

结果:

2018-06-18 13:07:27.624828+02
Mon Jun 18 13:17:51 CEST 2018

解析后的Date对象又增加了十分钟(以及几秒钟)。

仔细看看会发现问题 - 这不是JDK中的错误:

你的毫秒部分是624828 - 这些是六(!)位(不是三位)。 624828毫秒约为624秒,即10分24秒。 SimpleDateFormat正确地总结了这个额外的秒和分钟。

还有什么不对:您的日期格式包含毫秒部分的五位数字。

<强>解决方案:

(新)Java Time API可以处理更大的秒数 - 并且可以在不同时区之间轻松转换:

String str = "2018-06-18 13:07:27.624828+02";
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSx");
OffsetDateTime date = OffsetDateTime.parse(str, pattern);
System.out.println(date);
System.out.println(date.withOffsetSameInstant(ZoneOffset.UTC));

结果:

2018-06-18T13:07:27.624828+02:00
2018-06-18T11:07:27.624828Z

答案 1 :(得分:1)

您的输入日期包含微秒,但SimpleDateFormat仅支持毫秒(最多3位数)。在使用标志宽限启用解析值时,完整的6位数被评估为微秒。所以最后你有624秒额外添加到日期。

您可以尝试将SSSSSS模式与Java 8中引入的DateTimeFormatter一起使用。

但是你可能还有其他问题。您的代码解析输入日期,而不包含末尾包含的时区信息+02。您应该为ISO8601时区格式添加一个字母X.格式化输出日期时,使用表示时区UTC的字母“Z”。但你设定时区CET(柏林)。因此输出日期不是UTC。 UTC中指定输入日期的正确输出为:

2018-06-18 11:07:27Z