首页 > 解决方案 > DateTimeFormatter.parse() 更正日期信息而不是抛出异常

问题描述

我在 Java SE8 项目中使用 javac 15.0.1。
我对 LocalDate 有不规则的输入:
String fateDate = "1970-02-29"
使用 LocalDate 的 parse() 我得到这个异常(正确):
LocalDate.parse(fateDate);

线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“1970-02-29”:日期“2 月 29 日”无效,因为“1970”不是闰年

但是使用 DateTimeFormatter 会进行某种更正:

final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("y-M-d");
TemporalAccessor ta = dtf.parse(fateDate);
System.out.println(ta);

产生于:

{},ISO 解析为 1970-02-28

此行为对于所有月份和 day<32 的所有值都是相同的。因此,对于四月,您不会得到 31 的异常,而是将 LocalDate 以 30 作为一天的值。这看起来不像是“早早失败”的完美化身......
为什么会有不同的行为

标签: javaparsinglocaldatedatetimeformatter

解决方案


解析器样式

你自己DateTimeFormatter正在努力变得聪明。它使用了一种确实被称为SMART. 这是来自 的格式化程序的默认设置DateTImeFormatter.ofPattern(),但您当然可以设置它。解析器样式SMART会像您观察到的那样进行小的调整。另一方面,它确实知道 ISO 日历中的一个月不能超过 31 天,因此仍然拒绝第 32 个月或更大的日期。这是一个设计决定,我不知道他们为什么要这样设计。

另一方面,单参数使用具有解析器样式LocalDate.parse()的内置。它拒绝所有在预测公历中无效的日期。DateTimeFormatter.ISO_LOCAL_DATESTRICT

正如我所说,您可以在格式化程序上设置解析器样式:

    String fateDate = "1970-02-29";
    final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d")
            .withResolverStyle(ResolverStyle.STRICT);
    TemporalAccessor ta = dtf.parse(fateDate );
    System.out.println(ta);

编辑:我需要进行另一项更改。因为使用严格的解析器样式,格式化程序根本拒绝将时代的年份、月份和月份的日期解析为日期。您使用的格式字母y表示年代,严格来说Java不知道1970是1970 BCE(BC)还是1970 CE(AD),因此无法解析。使用智能解析器样式,它将默认为普通时代(我们的时代);不严格。相反,我使用u的是有符号年份,这使得 1970 年明确。通过这两项更改,您现在得到了您要求的异常:

线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“1970-02-29”:日期“2 月 29 日”无效,因为“1970”不是闰年

为了完整起见,还有一种解析器样式LENIENT,但您当然不适合您的情况。

链接


推荐阅读