javajava-timedatetimeformatter

Java DateTimeFormatter with Optional Sections


I have done some reading on this and tried to work through examples from other StackOverflow threads but I keep running into an exception when parsing the date/time if I try to specify optional sections.

this is the input. The optional sections are the AM/PM which may not always be in the input, and the timezone which may be 4 characters:

09:10:05.584 AM EST Wed Nov 29 2023

This is the pattern that works for this input, but not other inputs, such as if there is no timezone

hh:mm:ss.SSS a zzz E MMM dd yyyy

If I try to do something like this and create optional patterns I get a parse exception at position 12 in the input, which is just after the milliseconds

hh:mm:ss.SSS[ a [z]zzz ]E MMM dd yyyy

this is the code, currently set to the format that fails:


public static final String TIME_FORMAT = "hh:mm:ss.SSS[ a [z]zzz ]E MMM dd yyyy";


public static String ParseDate(String input, String format) {
        
        
        String retVal = "";
        
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format, Locale.ENGLISH);
        
        TemporalAccessor ta = formatter.parseBest(input, LocalDateTime::from, LocalDate::from);
        
        retVal = ta.toString();
       
        System.out.println("Parsed date is: "+ retVal);
        return retVal;
    }

Solution

  • This is a tricky one, because the syntax for an optional section of the DateTimeFormatter class specifically wants the space between the optional element and its predecessor included within square brackets.

    The documentation of the parseBest() method shows an example of a pattern with an optional timezone ID, uuuu-MM-dd HH.mm[ VV], where the space between the minute and the timezone ID is included within the optional section.

    In your snippet, the first optional was written properly hh:mm:ss.SSS[ a... (with the space between SSS and a included within square brackets), but then the optional part for the timezone name was written a [z]zzz instead of a[ z]zzz. In your case, you can either nest the optional sections like so hh:mm:ss.SSS[[ a] zzz] E MMM dd yyyy, or write them as individual optional sections hh:mm:ss.SSS[ a][ z][ zzz] E MMM dd yyyy.

    Here is a re-written version of your code covering the 4 cases:

    public class Main {
        public static void main(String[] args) {
            parseDate("09:10:05.584 AM EST Wed Nov 29 2023", TIME_FORMAT);
            parseDate("09:10:05.584 AM Wed Nov 29 2023", TIME_FORMAT);
            parseDate("09:10:05.584 EST Wed Nov 29 2023", TIME_FORMAT);
            parseDate("09:10:05.584 Wed Nov 29 2023", TIME_FORMAT);
        }
        public static final String TIME_FORMAT = "HH:mm:ss.SSS[ a][ z][zzz] E MMM dd yyyy";
    
        public static String parseDate(String input, String format) {
            String retVal = "";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format, Locale.ENGLISH);
            TemporalAccessor ta = formatter.parseBest(input, LocalDateTime::from, LocalDate::from);
            retVal = ta.toString();
            System.out.println("Parsed date is: " + retVal);
            return retVal;
        }
    }
    

    You can quickly check the code here at this link:

    https://ideone.com/bpfw8o