Java 8 DateTimeFormatter拒绝带偏移的正确ISO 8601日期/时间

时间:2019-02-05 14:04:55

标签: java date time iso8601

我为DateTimeFormatter使用格式字符串: uuuu-MM-dd'T'HH:mm:ssX

必须支持所有可能的时区偏移格式,包括: Z,00,00:00,0000

根据官方的DateTimeFormatter文档,“ X”限定符必须匹配以以下格式偏移:

X区域偏移量'Z',表示零偏移量-X Z; -08; -0830; -08:30; -083015; -08:30:15;

但实际上不是

输入字符串:“ 2014-01-01T00:30:00 + 00:00”

结果 java.time.format.DateTimeParseException:无法解析文本'2014-01-01T00:30:00 + 00:00',在索引22处找到了未解析的文本

输入字符串:“ 2014-01-01T00:30:00Z”

结果正确

代码:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX");
OffsetDateTime parsed = OffsetDateTime.parse(dateTimeAsString, formatter);

JDK 1.8.0_192(Oracle,不是OpenJDK)

3 个答案:

答案 0 :(得分:5)

这有点复杂。 As jvdmr says,X的数量很重要。 FittedBox( fit: BoxFit.contain, child: Column( .... 将识别XXXXX,但不能识别-08:30:15-083015将识别后者,但不能识别前者。

要考虑所有可能的示例格式,我们需要指定不同的可能性。可以在格式模式字符串中使用方括号来完成此操作。这些包含可选部分。进行一些实验后发现,以下模式涵盖了所有示例:

  

XXXX

让我们尝试一下:

uuuu-MM-dd'T'HH:mm:ss[XXXXX][XXXX][X]

此代码段的输出为:

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[XXXXX][XXXX][X]");
    for (String dts : new String[] {
            "2014-01-01T00:30:00-08:30:15", "2014-01-01T00:30:00-083015",
            "2014-01-01T00:30:00-08:30", "2014-01-01T00:30:00-0830",
            "2014-01-01T00:30:00-08", "2014-01-01T00:30:00Z",
    }) {
        System.out.println(OffsetDateTime.parse(dts, formatter));
    }

修改

VelNaga suggests不能硬编码ISO日期时间格式。由于编写格式模式字符串容易出错,因此这是一个好主意。例如:

2014-01-01T00:30-08:30:15
2014-01-01T00:30-08:30:15
2014-01-01T00:30-08:30
2014-01-01T00:30-08:30
2014-01-01T00:30-08:00
2014-01-01T00:30Z

使用此格式化程序的输出与使用上述格式化程序的输出相同。它比较复杂,但是我们很容易最终认为这是值得的,因为它不那么容易出错,而且更清晰易读。

答案 1 :(得分:4)

来自docs (重点是我的)

  

偏移量X和x:这将根据格式字母的数量来格式化偏移量一个字母仅输出小时,例如“ +01”,除非分钟非零,在这种情况下,也会输出分钟,例如“ +0130”。两个字母输出小时和分钟,不带冒号,例如'+0130'。 三个字母输出小时和分钟,带有冒号,例如'+01:30'。四个字母输出小时和分钟,第二个字母可选,不带冒号,例如,'+ 013015'。五个字母输出小时和分钟,可选秒,并带有冒号,例如“ +01:30:15”。六个或更多字母会引发IllegalArgumentException。当要输出的偏移量为零时,模式字母“ X”(大写)将输出“ Z”,而模式字母“ x”(小写)将输出“ +00”,“ + 0000”或“ +00” :00'。

这对于解析日期也相反。您要同时解析有无冒号,这意味着您必须使用可选部分,因为没有单个模式支持此功能。尝试以下模式:"uuuu-MM-dd'T'HH:mm:ss[XXX][XXXX]"

答案 2 :(得分:0)

不要对任何ISO日期格式进行硬编码。 DateFormatter已经具有用于ISO日期格式转换的静态方法。使用以下代码,

  

DateTimeFormatter格式化程序= DateTimeFormatter.ISO_ZONED_DATE_TIME;

     

已解析的OffsetDateTime = OffsetDateTime.parse(dateTimeAsString,   格式化程序);

肯定会起作用。请找到此link,以获取更多格式化程序选项。