DateTimeFormatter - Strict vs Lenient unexpected behaviour
Asked Answered
V

1

6

I have some text that is only being parsed by a DateTimeFormatter when the parse style is Strict - and not when it's Lenient.

This seems like the opposite behaviour to what I'd expect?

Example:

String pattern = "ddMMyyHH:mm:ss";
String text = "02011104:21:32";

System.out.println(MessageFormat.format("Strict - {0}", new DateTimeFormatterBuilder().parseStrict().appendPattern(pattern).toFormatter().parse(text)));
System.out.println(MessageFormat.format("Lenient - {0}", new DateTimeFormatterBuilder().parseLenient().appendPattern(pattern).toFormatter().parse(text)));

Output:

Strict - {},ISO resolved to 2011-01-02T04:21:32
Exception in thread "main" java.time.format.DateTimeParseException: Text '02011104:21:32' could not be parsed at index 8
Vachill answered 15/7, 2019 at 13:51 Comment(6)
I have reproduced your behaviour. Interesting!Tumefacient
In my debugger I see that in lenient mode it “eats” 4 digits for year (so 1104) even though yy should be for 2-digit year of era. Was that supposed to happen? Because of an error in the docs I cannot tell. Appending yy in appendPattern should be equivalent to calling appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000), but there is no three-arg appendValueReduced method!Tumefacient
Is there anything in particular you had wanted to obtain by using parseLenient or parseStrict? IMHO the documentation is very unclear about what difference it should make. For the record LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern).withResolverStyle(ResolverStyle.LENIENT)) works (but you probably had a reason for wanting to use a builder).Tumefacient
When I use appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2, 2000), I get the same behaviour as yours, so it works without parseLenitent but not with. It sounds to me like a bug, and you may consider filing it as such.Tumefacient
I have tried in Java 9 and Java 11 and have observed no difference.Tumefacient
@OleV.V. thanks for your comments. I think “Interesting” is a good choice of words! Let me try your suggestion of withResolverStyleVachill
V
2

Having posted this as a bug - https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8228353

I got the following reply:

According to DateTimeFormatterBuilder's spec, appendPattern("yy") translates to appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000), where "2" applies both for with and maxWidth. In the method description, it reads:

For strict parsing, the number of characters allowed by width to maxWidth are parsed. For lenient parsing, the number of characters must be at least 1 and less than 10.

Thus in this case, only "11" is read for "yy" in strict mode, then produces the year "2011" with the base value 2000. But in lenient mode, "yy" tries to read greedily just before the ":" and produces the year "1104", then parser throws the exception trying to parse ":" with "HH" pattern.

Vachill answered 18/7, 2019 at 10:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.