Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 DateTimeFormatter parsing optional sections

I need to parse date-times as strings coming as two different formats:

  • 19861221235959Z
  • 1986-12-21T23:59:59Z

The following dateTimeFormatter pattern properly parses the first kind of date strings

DateTimeFormatter.ofPattern ("uuuuMMddHHmmss[,S][.S]X")

but fails on the second one as dashes, colons and T are not expected.

My attempt was to use optional sections as follows:

DateTimeFormatter.ofPattern ("uuuu[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")

Unexpectedly, this parses the second kind of date strings (the one with dashes), but not the first kind, throwing a

java.time.format.DateTimeParseException: Text '19861221235959Z' could not be parsed at index 0

It's as if optional sections are not being evaluated as optional...

like image 377
Cec Avatar asked Jul 04 '18 15:07

Cec


People also ask

Is DateTimeFormatter thread-safe Java?

A formatter created from a pattern can be used as many times as necessary, it is immutable and is thread-safe.

What is the difference between DateTimeFormatter and SimpleDateFormat?

DateTimeFormatter is a replacement for the old SimpleDateFormat that is thread-safe and provides additional functionality.

How do I use DateTimeFormatter with date?

DateTimeFormatter fmt = DateTimeFormatter. ofPattern("yyyy-MM-dd'T'HH:mm:ss"); System. out. println(ldt.

What is the Java time format DateTimeFormatter?

format. DateTimeFormatterBuilder Class in Java. DateTimeFormatterBuilder Class is a builder class that is used to create date-time formatters. DateTimeFormatter is used as a Formatter for printing and parsing date-time objects.


1 Answers

The problem is that your pattern is considering the entire string as the year. You can use .appendValue(ChronoField.YEAR, 4) to limit it to four characters:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendPattern("[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")
    .toFormatter();

This parses correctly with both of your examples.

If you fancy being even more verbose, you could do:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .optionalStart().appendLiteral('-').optionalEnd()
    .appendPattern("MM")
    .optionalStart().appendLiteral('-').optionalEnd()
    .appendPattern("dd")
    .optionalStart().appendLiteral('T').optionalEnd()
    .appendPattern("HH")
    .optionalStart().appendLiteral(':').optionalEnd()
    .appendPattern("mm")
    .optionalStart().appendLiteral(':').optionalEnd()
    .appendPattern("ss")
    .optionalStart().appendPattern("X").optionalEnd()
    .toFormatter();
like image 63
Michael Avatar answered Nov 15 '22 15:11

Michael