Java 8 Date equivalent to Joda's DateTimeFormatterBuilder with multiple parser formats?

Viewed 17012

I currently have a Joda date parser that uses the DateTimeFormatterBuilder with half a dozen different date formats that I may receive.

I'm migrating to Java 8's Date routines and don't see an equivalent.

How can I do something like this using Java 8 Dates?

DateTimeParser[] parsers = { 
    DateTimeFormat.forPattern( "yyyy/MM/dd HH:mm:ss.SSSSSS" ).getParser() ,
    DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss" ).getParser() ,
    DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS Z" ).getParser() ,
    DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSS" ).getParser() ,
    DateTimeFormat.forPattern( "ddMMMyyyy:HH:mm:ss.SSSSSS" ).getParser() ,
    DateTimeFormat.forPattern( "yyyy-MM-dd HH:mm:ss.SSS" ).getParser() 
};

DateTimeFormatter dateTimeFormatterInput = new DateTimeFormatterBuilder()
     .append( null, parsers ).toFormatter();
5 Answers

Based on answer from @Brice I wrote the following method, which worked best for me

private LocalDate parseDate(String date) {
    DateTimeFormatter yearFormat = new DateTimeFormatterBuilder()
            .appendPattern("yyyy")
            .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
            .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
            .toFormatter();
    DateTimeFormatter yearAndMonthFormat = new DateTimeFormatterBuilder()
            .appendPattern("yyyy-MM")
            .parseDefaulting(ChronoField.DAY_OF_MONTH,1)
            .toFormatter();

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendOptional(DateTimeFormatter.ISO_DATE)
            .appendOptional(yearAndMonthFormat)
            .appendOptional(yearFormat)
            .toFormatter();

    LocalDate result = LocalDate.parse(date, formatter);

    return result;
}

Pay attention to the order of optional formatters added to the last one. Reverse order would only work for dates of the type "yyyy". The proposed order allows me to parse all of the following:

  • 2014
  • 2014-10
  • 2014-03-15

Just adding for the case someone would have similar use case.

Here is what I eventually came up with. It handles three different major formats, each with multiple minor formatting differences (such as allowing either - or / delimiters) as well as handling variable number of microseconds (from 0 to 6):

private static final DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .appendPattern( "[ddMMMyyyy:HH:mm:ss" )
        .optionalStart()
        .appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true )
        .optionalEnd()
        .appendPattern( "[ ][Z][X]]" )
        .appendPattern( "[yyyy[-][/]MM[-][/]dd['T'][ ]HH:mm[:][.]ss" )
        .optionalStart()
        .appendFraction( ChronoField.MICRO_OF_SECOND , 1 , 6 , true )
        .optionalEnd()
        .appendPattern( "[Z][X]]" )
        .appendPattern( "[EEE, dd MMM yyyy HH:mm:ss zzz]" )
        .toFormatter();
Related