Search code examples
javajava-14datetimeformatter

DateTimeFormatterBuilder appendOptional multiple ISO standards results in DateTimeParseException


public class Main {
  public static void main(String[] args) {  
        DateTimeFormatterBuilder dtf = new DateTimeFormatterBuilder()
                .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                .appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
                .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE);
        
        LocalDateTime x = LocalDateTime.parse("2021-10-11T07:00:53.004Z", dtf.toFormatter());
        System.out.println("After formatting: " + x);  
  }  
}  

so i was curious why this does not work, it seems like he automatically assumes the first one to not be optional? if i swap offset_date_time and local_date_time it parses this string but not the local_date_time string

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-10-11T07:00:53.004Z' could not be parsed, unparsed text found at index 23
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2053)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:493)
    at Main.main(Main.java:12)

im on Java 14 if that makes any difference, i would be happy to provide additional information if necassery

in the end i changed the methode too, to allow all 3 of the ISO standards:

 public class Main {
      public static void main(String[] args) {  
    DateTimeFormatterBuilder dtf = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendOptional(DateTimeFormatter.ofPattern("'T'"))
            .appendOptional(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendOptional(DateTimeFormatter.ofPattern("XXX"));
            
            LocalDateTime x = LocalDateTime.parse("2021-10-11T07:00:53.004Z", dtf.toFormatter());
            System.out.println("After formatting: " + x);  
      }  
    }  

Solution

  • Well, that is because the first optional part can be fully consumed, so the DateTimeFormatter consumes the text denoted by the ISO_LOCAL_DATE_TIME.

    Then, the two remaining optional patterns are tried against the remaining text, which is Z, but they cannot be matched.

    At last, there is no pattern left to parse, so the parser notes that the text Z is left unparsed, hence an exception is thrown.