Both of these DateTimeFormatters are nearly identical, however only the second one throws an exception. Both of these patterns are valid as far as I can tell.
Why does changing minWidth
cause parsing to fail in the second case?
I'm using Java 21.
This works, output is {},ISO resolved to 2024-12-31T23:59:59.123
var result1 = new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendFraction(ChronoField.NANO_OF_SECOND, 3, 3, false) // minWidth is 3
.toFormatter()
.parse("20241231235959123");
System.out.println(result1);
This throws an exception:
var result2 = new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendFraction(ChronoField.NANO_OF_SECOND, 1, 3, false) // minWidth is 1
.toFormatter()
.parse("20241231235959123");
System.out.println(result2);
The exception:
Exception in thread "main" java.time.format.DateTimeParseException: Text '20241231235959123' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2108)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1936)
at Main.main(Main.java:24)
This is because the pattern yyyy
is a variable-width pattern (it can parse between 4 and 19 digits), and the fractional part is also a variable-width pattern. The parser has no way of determining which numbers belong to which part.
Consider a simpler example:
var result = new DateTimeFormatterBuilder()
.appendPattern("yyyy")
.appendFraction(ChronoField.NANO_OF_SECOND, 1, 3, false)
.toFormatter()
.parse("123456");
What is the year in "123456"? Is it 1234, and 56 is fractional part? Or is it 12345, and 6 is the fractional part? This is ambiguous.
You need to add some other delimiter (e.g. set decimal point to true), or limit the year to a fixed width.
var result = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4) // fixed year to 4 digits
.appendPattern("MMddHHmmss")
.appendFraction(ChronoField.NANO_OF_SECOND, 1, 3, false) // minWidth is 1
.toFormatter()
.parse("20241231235959123");