DateTimeFormatter无法解析自己生成的字符串

时间:2017-03-27 13:34:33

标签: java datetime-format java-time

我在解析以下日期格式时遇到问题:

2017-03-27T08:27:43.326TGMT-05:00

我有DateTimeFormatter生成ZonedDateTime字符串的代码,下一步我尝试再次解析此字符串并创建ZonedDateTime实例,但它不起作用我期待:

String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'T'ZZZZ";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
String dateStr = ZonedDateTime.now().format(formatter);

System.out.println(dateStr);

ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr, formatter);
System.out.println(dateParsed);

上面的代码产生:

2017-03-27T08:27:43.326TGMT-05:00
java.time.format.DateTimeParseException: Text '2017-03-27T08:27:43.326TGMT-05:00' could not be parsed: String index out of range: 33

    at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)

寻找有关如何提出能够在ZonedDateTime

之外创建2017-03-27T08:27:43.326TGMT-05:00实例的工作模式的任何见解

2 个答案:

答案 0 :(得分:2)

为了理解错误,我查看了引发异常的DateTimeFormatterBuilder.java:3563源代码。

我看到有一段代码可以解析GMT-05:00之后的秒部分。

因此只有在添加秒部分时才会起作用...

ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr+":00", formatter);

答案 1 :(得分:0)

要了解ZZZZ模式的作用,请查看JDK docs,您可以在其中看到其含义:

Pattern  Count  Equivalent builder methods
-------  -----  --------------------------
ZZZZ     4      appendLocalizedOffset(TextStyle.FULL);

因此,ZZZZ相当于appendLocalizedOffset(TextStyle.FULL)。如果你看一下appendLocalizedOffset方法:

  

将本地化区域偏移(例如'GMT + 01:00')附加到格式化程序。   这会将本地化区域偏移附加到构建器,本地化偏移的格式由此方法的指定样式控制:

     
      
  • 完整 - 具有本地化偏移文字的格式,例如“ GMT ,2位小时和分钟字段,可选第二个字段,如果非零,和冒号。
  •   

请注意,在解析和格式化时它有不同的行为:

  

格式化期间,使用等效于使用TemporalQueries.offset()查询时间的机制获得偏移量。如果无法获得偏移量,则抛出异常,除非格式化程序的部分是可选的。

     

解析期间,使用上面定义的格式解析偏移量。如果无法解析偏移量,则抛出异常,除非格式化程序的部分是可选的。

因此,似乎ZZZZ模式在格式化时添加GMT-05:00(没有秒时为零),但在解析时,它会尝试解析秒数(即使它们不存在) )。 这就是为什么在解析时,你需要最后添加:00(如@freedev in his answer)。

由于ZZZZ似乎是在偏移之前添加GMT的唯一模式(所有其他模式只是添加了GMT的偏移量),我认为唯一的解决方案是添加它用手。您可以使用java.time.format.DateTimeFormatterBuilder类:

来完成
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // append the yyyy-MM-dd'T'HH:mm:ss.SSS pattern
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
    // append "T" and "GMT"
    .appendLiteral("TGMT")
    // append the offset (-05:00)
    .appendOffsetId()
    .toFormatter();

使用此格式化程序,您的代码将按预期工作:

String dateStr = ZonedDateTime.now().format(formatter);
System.out.println(dateStr);

ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr, formatter);
System.out.println(dateParsed);

输出:

  

2017-05-25T08:42:17.799TGMT-05:00

     

2017-05-25T08:42:17.799-05:00

使用您的输入进行测试:

String input = "2017-03-27T08:27:43.326TGMT-05:00";
System.out.println(input);
System.out.println(ZonedDateTime.parse(input, formatter));

输出:

  

2017-03-27T08:27:43.326TGMT-05:00

     

2017-03-27T08:27:43.326-05:00

PS:在这种情况下,我更喜欢使用DateTimeFormatterBuilder,但您可以直接使用DateTimeFormatter.ofPattern执行相同操作:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'TGMT'xxx");

这种方式完全相同。