Parsing an ISO 8601 date in Java8 when all fields (including separators, but not including years) are optional

前端 未结 4 1659
北海茫月
北海茫月 2021-01-15 06:26

I have a requirement for parsing ISO8601 formatted strings in Java with various levels of accuracy. Some examples of the string I need to parse are:

  • 2018
相关标签:
4条回答
  • 2021-01-15 06:32

    You can create a DateTimeFormatter with DateTimeFormatterBuilder, which has a method called parseDefaulting(). parseDefaulting() could set the default value if there is no matching.

    0 讨论(0)
  • 2021-01-15 06:40

    Well that took me longer than I had expected. The only valid parser is:

    DateTimeFormatter dtf = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4)
            .appendPattern("[['-']MM[['-']dd[['T']HH[[':']mm[[':']ss['.'SSS]]]]]]")
            .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
            .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
            .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
            .toFormatter();
    
    String[] s = {
            "2018",
            "2018-10",
            "2018-10-15",
            "2018-10-15T12:00",
            "2018-10-15T12:00:30",
            "2018-10-15T12:00:30.123",
            "20181015",
            "201810151200",
            "20181015120030",
            "20181015120030.123",
            "20181015T12:00:30.123"
    };
    for (String line : s) {
      System.out.println(LocalDateTime.parse(line, dtf));
    }
    

    The problem is that yyyy creates a ValueParser(minWidth=4, maxWidth=19, SignStyle.PAD_EXEEDS) which parses the date 20181015 as year=20181015 as an example. So we have to restrict the digit width of year to 4.

    The documentation states:

    Year: The count of letters determines the minimum field width below which padding is used.

    But does not specify a maximum width.

    0 讨论(0)
  • create a lookup table of DateFormatters or whatever you're using based on the length of the input String and the occurrence of 'T'

    0 讨论(0)
  • 2021-01-15 06:57

    For the first cases with separators (-, :) one can use:

        DateTimeFormatter dtf = DateTimeFormatter
            .ofPattern("uuuu[-MM[-dd[['T']HH[:]mm[[:]ss[[.]SSS]]]]]");
        ParsePosition pos = new ParsePosition(0);
        TemporalAccessor result = dtf.parse(text, pos);
    

    However neither uuuuMMdd nor [-] or ['-'] worked for me in Java 8.

    0 讨论(0)
提交回复
热议问题