使用新的Java 8 DateTimeFormatter进行严格的日期解析

0xb*_*7ed 12 java datetime parsing date java-8

我有一个简单的问题:我想"yyyyMMdd"严格地解析格式化的Java字符串,因此这"19800229"是一个有效的日期,但事实"19820229"并非如此.假设这些是正常公历的AD日期.

我正在尝试使用java.timeJDK 8中的新软件包来解决这个问题,但事实证明它比希望的更复杂.我目前的代码是:

private static final DateTimeFormatter FORMAT = DateTimeFormatter
        .ofPattern("yyyyMMdd").withChronology(IsoChronology.INSTANCE)
        .withResolverStyle(STRICT);

public static LocalDate parse(String yyyyMMdd) {
    return LocalDate.parse(yyyyMMdd, FORMAT);
}
Run Code Online (Sandbox Code Playgroud)

但是,解析诸如"19800228"之类的有效日期对我来说产生了一个难以理解的错误:

java.time.format.DateTimeParseException:无法解析文本'19820228':无法从TemporalAccessor获取LocalDate:{MonthOfYear = 2,DayOfMonth = 28,YearOfEra = 1982},ISO类型为java.time.format.Parsed

我如何使用java.time.format.DateTimeFormatter来解决我的简单用例?

Jan*_*tis 21

Java 8 uuuu用于年份,而不是yyyy.在Java 8中,yyyy意思是"年代"(BC或AD),并且错误消息抱怨MonthOfYear,DayOfMonth和YearOfEra不足以构建日期,因为时代未知.

要解决这个问题,请使用uuuu格式字符串,例如DateTimeFormatter.ofPattern("uuuuMMdd")

或者,如果您想继续使用yyyy,可以设置默认时代,例如

private static final DateTimeFormatter FORMAT = new DateTimeFormatterBuilder()
            .appendPattern("yyyyMMdd")
            .parseDefaulting(ChronoField.ERA, 1 /* era is AD */)
            .toFormatter()
            .withChronology(IsoChronology.INSTANCE)
            .withResolverStyle(ResolverStyle.STRICT);
Run Code Online (Sandbox Code Playgroud)


Tec*_*rip 4

我正在编辑以通过使用使用 DateTimeFormatterBuilder 创建的自定义格式化程序来限制哪种类型的字符串将被视为有效。

public class DateFormmaterTest {

    static DateTimeFormatter CUSTOM_BASIC_ISO_DATE = new DateTimeFormatterBuilder()
            .parseCaseInsensitive().appendValue(YEAR, 4)
            .appendValue(MONTH_OF_YEAR, 2).appendValue(DAY_OF_MONTH, 2)
            .optionalStart().toFormatter()
            .withResolverStyle(ResolverStyle.STRICT)
            .withChronology(IsoChronology.INSTANCE);

    public static void main(String[] args) {

        LocalDate date1 = LocalDate.parse("19800228-5000",
                CUSTOM_BASIC_ISO_DATE);

        System.out.println(date1);

    }
}
Run Code Online (Sandbox Code Playgroud)

2/29/1982 无效,会抛出以下错误:

Caused by: java.time.DateTimeException: Invalid date 'February 29' as '1982' is not a leap year
    at java.time.LocalDate.create(LocalDate.java:429)
Run Code Online (Sandbox Code Playgroud)

日期 19800228-5000 将与 BASIC_ISO_DATE 一起使用,因为它允许您不希望允许的可选偏移量。我的 CUSTOM_BASIC_ISO_DATE 格式化程序不允许这样做并抛出以下内容:

Exception in thread "main" java.time.format.DateTimeParseException: Text '19800228-5000' could not be parsed, unparsed text found at index 8. 
Run Code Online (Sandbox Code Playgroud)

请注意,如果您确定字符串长度 yyyyMMdd,那么您始终可以使用前 8 个字符的子字符串来消除对解析器的需要。然而,这是两件不同的事情。解析器将标记输入上的无效日期格式,并且子字符串当然只会删除多余的字符。