Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.time.format.DateTimeParseException when parsing year

Tags:

java

java-8

jdk used : 1.8

Not sure what is the issue, configuredFormat is valid one, inputTime is also valid one, really confused what is the issue.

public class Test {

    public static void main(String[] args) {
        String configuredFormat = "yyyyMMddHHmmssSSS";
        String inputTime = "20200203164553123";

        DateTimeFormatter dt = DateTimeFormatter.ofPattern(configuredFormat);
        DateTimeFormatter strictTimeFormatter = dt.withResolverStyle(ResolverStyle.STRICT);
        try {
            LocalTime.parse(inputTime, strictTimeFormatter);
            System.out.println("success");
        } catch (DateTimeParseException | NullPointerException e) {
            e.printStackTrace();
        }
    }
}

Exception I am Getting :

java.time.format.DateTimeParseException: Text '20200203164553123' could not be parsed at index 0
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.LocalTime.parse(LocalTime.java:441)
    at com.Test.main(Test.java:20)
like image 444
Diwakar Bhatt Avatar asked Dec 08 '22 10:12

Diwakar Bhatt


1 Answers

Lucky for you, there is an exact bug report which uses the exact same pattern that you're trying. Who better to explain than the JDK maintainers?

JDK-8031085

Workaround

DateTimeFormatter dtf = new
DateTimeFormatterBuilder()
    .appendPattern("yyyyMMddHHmmss")
    .appendValue(ChronoField.MILLI_OF_SECOND,3)
    .toFormatter()

Adjacent value parsing is generally a hard problem. It is intended to handle the case where the first element is variable width (the year) and all other elements are fixed width (month, day etc). However, the "S" pattern letter is a fraction, not a value. Specifically, the fraction can be variable width - more or less than three digits are possible options. Given the general case of a variable width year and a variable width millisecond, it is not possible to determine which of the two fields was intended to be variable.

Having said that, the implementation (and javadoc) have not ended up as I intended. The description of "fraction" in DateTimeFormatter describes actions in strict and lenient mode, but there is no way to access strict or lenient mode when using DateTimeFormatter.ofPattern(). This is a documentation bug that should be fixed by removing the discussion of strict vs lenient.

Worse however is that the SSS pattern has therefore ended up using strict mode when lenient mode would be appropriate. As it currently stands, DateTimeFormatter.ofPattern("hhmmss.SSS") requires three digits for milliseconds, when it was originally intended to require 0 to 9 (the lenient behaviour).

I tried changing the whole of the DateTimeFormatter.ofPattern() method to use lenient parsing, and it broke no tests (which is bad in its own way). This might be a valid fix, but only if included in JDK 8, as once people adapt to the strict parsing it will be hard to make it lenient.

Given that the current implementation requires three digits for SSS, it is thus very surprising that adjacent value parsing does not apply.

like image 158
Michael Avatar answered Jan 04 '23 23:01

Michael