Java SimpleDateFormat 上的日期对象解析精度已关闭

Java Date object parsing precision is off on SimpleDateFormat

我有一个字符串形式的日期 2016-10-07T12:46:23Z,在使用 SimpleDateFormat 解析为 Date 对象后,它被转换为 Fri Oct 07 08:46:22 EDT 2016,精度为 1 秒。调试该代码,它被解析为 Fri Oct 07 08:46:22.998 EDT 2016

要解析的 SimpleDateFormat 看起来像

DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));

要解析的代码看起来像

String dateStr = valuesArray.getString(0); values[0] = RESTUtils.DATE_FORMAT_ISO8601.parse(dateStr);

有什么技巧可以在解析后获得正确的秒值吗?

当您使用 SimpleTimeZone 添加时区作为 UTC 时,您会看到第二个差异,如果您注释掉该部分,您将获得准确的秒数。

String str = "2016-10-07T12:46:24Z";
SimpleDateFormat DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
// DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
System.out.println(DATE_FORMAT_ISO8601.parse(str));

SimpleTimeZone 不用于定义时区。根据 documentation

SimpleTimeZone is a concrete subclass of TimeZone that represents a time zone for use with a Gregorian calendar. The class holds an offset from GMT, called raw offset, and start and end rules for a daylight saving time schedule. Since it only holds single values for each, it cannot handle historical changes in the offset from GMT and the daylight saving schedule, except that the setStartYear method can specify the year when the daylight saving time schedule starts in effect.

设置时区的正确方法是执行以下操作

DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("UTC"));

表达式new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")) 定义的偏移量不是零,而是2毫秒,参见Javadoc,从而解释了观察到的结果"Fri Oct 07 08:46:22.998 EDT 2016".

常量 SimpleTimeZone.UTC 并非旨在指示偏移量(作为 SimpleTimeZone-构造函数的第一个参数强制执行)。它的数值“2”更像是一种模式,表示如何为其他构造函数解释开始或结束时间参数。

因此,解释输入中尾随 "Z" 的正确解决方案(零偏移量的 ISO-8601 表示法)是:

DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("GMT"));

或者,如果您真的想使用 class SimpleTimeZone:

DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(0, "UTC"));

如果你在Java-8,你也可以这样做:

Instant instant = Instant.parse("2016-10-07T12:46:23Z");
System.out.println(instant); // 2016-10-07T12:46:23Z
System.out.println(Date.from(instant)); // Fri Oct 07 14:46:23 CEST 2016