Java 8日期时间格式化程序行为不端

时间:2018-01-23 14:02:14

标签: java datetime java-8 java-time datetime-parsing

我有以下代码抛出DateTimeParseException

String dateString = "Jul 20 09:32:46"
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("L d HH:mm:ss");
return ZonedDateTime.parse(dateString, formatter);

根据documentation,您会发现Jul是字符L的示例。

但是,异常消息是:

  

java.time.format.DateTimeParseException:无法在索引0处解析文本“Jul”

我错过了什么?

2 个答案:

答案 0 :(得分:6)

这里有一些问题:

  1. 要正确解析'Jul',您必须使用MMM而不是Lhere解释原因)。
  2. 您的日期字符串没有一年。如果没有年份,则无法创建ZonedDateTime。
  3. 如果是 Zoned 日期时间,则必须包含时区信息,这不在您的日期字符串中。如果您不想使用时区,则可以使用LocalDateTime
  4. 以下是一些替代方案:

    使用时区:

    String dateString = "Jul 20 2018 09:32:46+0000";
    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("MMM dd y H:mm:ssZ");
    return ZonedDateTime.parse(dateString, formatter);
    

    没有时区:

    String dateString = "Jul 20 2018 09:32:46";
    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("MMM dd y H:mm:ss");
    return LocalDateTime.parse(dateString, formatter);
    

答案 1 :(得分:2)

The answer by Juan Carlos Mendoza是正确的。我将提出我的建议作为补充:要么改进你的字符串以包括年份和时区,要么构建一个格式化程序,可以在没有它们的情况下解析当前字符串。

改善字符串

    String dateString = "Jul 20 2018 09:32:46 America/Argentina/La_Rioja";
    DateTimeFormatter formatter 
            = DateTimeFormatter.ofPattern("LLL d uuuu HH:mm:ss VV", Locale.ROOT);
    System.out.println(ZonedDateTime.parse(dateString, formatter));

打印

2018-07-20T09:32:46-03:00[America/Argentina/La_Rioja]

同样的格式化程序也会将Jul 20 2018 09:32:46 -08:30解析为2018-07-20T09:32:46-08:30的ZonedDateTime

第一个潜在的问题是语言环境。如果“Jul”是英语,则提供说英语的语言环境,或者在使用7月份被称为其他语言的语言的计算机上解析可能会失败。我建议您始终使用格式化程序指定区域设置。即使你最终选择Locale.getDefault()。它仍会告诉读者(和你自己)你做出了有意识的选择。

下一页the documentation表示ML都可以将月份作为数字/文字,并提供示例7; 07; 7月;七月; J.所以这一行显然是相关的:“数字/文字:如果模式字母的数量是3或更大,请使用上面的文本规则。否则使用上面的数字规则。“由于”Jul“是文本,你需要3个或更多的模式字母。 “少于4个模式字母将使用缩写形式。”“Jul”很短,所以我们需要三个字母。

无论我在格式模式字符串中使用MMM还是LLL,上面的代码都适用于Java 9.0.4。在jdk1.8.0_131中,它与MMM一起使用,但有时会失败LLL,这可能是一个错误(在Mac上测试过)。请参阅Juan Carlos Mendoza,了解ML之间的预期差异。

构建一个有效的格式化程序

    String dateString = "Jul 20 09:32:46";
    ZoneId zone = ZoneId.of("America/Argentina/La_Rioja");
    DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("LLL d HH:mm:ss")
            .parseDefaulting(ChronoField.YEAR, Year.now(zone).getValue())
            .toFormatter(Locale.ROOT)
            .withZone(zone);
    System.out.println(ZonedDateTime.parse(dateString, formatter));

这会将您问题中的字符串解析为2018-07-20T09:32:46-03:00[America/Argentina/La_Rioja]。如果没有与我随机选择的时区一致,请替换您想要的默认时区。如果您不想要当年,也可以替换您想要的年份。

我的Java 8再次需要MMM而不是LLL