Search code examples
javajava-8java-timedatetimeformatter

Text '2021-06-22T18:27:03.5577Z' could not be parsed at index 20


I have several code snippets. Some of them works and some not but I don't understand why.

DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'");  //(7 positions after last dor)

TIME_FORMATTER.parse("2021-06-22T18:27:03.5577Z")//Broken 4 
TIME_FORMATTER.parse("2021-06-22T18:27:03.55770Z")//Broken 5
TIME_FORMATTER.parse("2021-06-22T18:27:03.557700Z")//Working 6 
TIME_FORMATTER.parse("2021-06-22T18:27:03.5577000Z")//Working 7 
TIME_FORMATTER.parse("2021-06-22T18:27:03.55770000Z")//Broken 8

See this code work, or not work, when running live at IdeOne.com.

Why it works for both: 6 and 7 digits after the decimal separator, but not 4, 5, or 8 digits?

How to create a formatter which would work for 4, 5, 6, 7, or 8 digits?


Solution

  • tl;dr

    You asked:

    How to create Format which will work for 4,5,6,7 numbers after point ?

    Use the predefined formatter, DateTimeFormatter.ISO_INSTANT.

    DateTimeFormatter.ISO_INSTANT.parse("2021-06-22T18:27:03.5577Z")
    

    Never ignore Z

    Never put quote-marks around Z in your formatting pattern. That letter is carries crucial information, and is not mere decoration. That letter indicates an offset from UTC of zero hours-minutes-seconds. Your single-quote-marks around Z indicate that letter should be expected and then ignored.

    When ignoring the offset, you are left with a date and time only. A date and time are not enough to represent a moment. We cannot know if your input meant 6:30 PM in Tokyo, 6:30 PM in Toulouse, or 6:30 PM in Toledo — all very different moments several hours apart.

    For a point on the timeline we require a third piece, the context of an offset or a time zone.

    java.time.Instant.parse

    Your input text complies with the ISO 8601 standard used by default in java.time. So no need to specify a formatting pattern.

    Simply parse the input as an Instant object. The Instant represents a moment as seen in UTC, with an offset of zero.

    The Instant.parse method uses the predefined formatter in the constant DateTimeFormatter.ISO_INSTANT.

    Instant instant4 = Instant.parse("2021-06-22T18:27:03.5577Z") ;
    Instant instant5 = Instant.parse("2021-06-22T18:27:03.55770Z") ;
    Instant instant6 = Instant.parse("2021-06-22T18:27:03.557700Z") ;
    Instant instant7 = Instant.parse("2021-06-22T18:27:03.5577000Z") ;
    Instant instant8 = Instant.parse("2021-06-22T18:27:03.55770000Z") ;
    

    See this code run live at IdeOne.com.

    2021-06-22T18:27:03.557700Z
    2021-06-22T18:27:03.557700Z
    2021-06-22T18:27:03.557700Z
    2021-06-22T18:27:03.557700Z
    

    If curious as to how ISO_INSTANT is written in OpenJDK, see the source code.