java.time.format.DateTimeParseException: Text could not be parsed at index 21

165,532

Solution 1

The default parser can parse your input. So you don't need a custom formatter and

String dateTime = "2012-02-22T02:06:58.147Z";
ZonedDateTime d = ZonedDateTime.parse(dateTime);

works as expected.

Solution 2

If your input always has a time zone of "zulu" ("Z" = UTC), then you can use DateTimeFormatter.ISO_INSTANT (implicitly):

final Instant parsed = Instant.parse(dateTime);

If time zone varies and has the form of "+01:00" or "+01:00:00" (when not "Z"), then you can use DateTimeFormatter.ISO_OFFSET_DATE_TIME:

DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
final ZonedDateTime parsed = ZonedDateTime.parse(dateTime, formatter);

If neither is the case, you can construct a DateTimeFormatter in the same manner as DateTimeFormatter.ISO_OFFSET_DATE_TIME is constructed.


Your current pattern has several problems:

  • not using strict mode (ResolverStyle.STRICT);
  • using yyyy instead of uuuu (yyyy will not work in strict mode);
  • using 12-hour hh instead of 24-hour HH;
  • using only one digit S for fractional seconds, but input has three.

Solution 3

Your original problem was wrong pattern symbol "h" which stands for the clock hour (range 1-12). In this case, the am-pm-information is missing. Better, use the pattern symbol "H" instead (hour of day in range 0-23). So the pattern should rather have been like:

uuuu-MM-dd'T'HH:mm:ss.SSSX (best pattern also suitable for strict mode)

Solution 4

The following worked for me

import java.time.*;
import java.time.format.*;

public class Times {

  public static void main(String[] args) {
    final String dateTime = "2012-02-22T02:06:58.147Z";
    DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
    final ZonedDateTime parsed = ZonedDateTime.parse(dateTime, formatter.withZone(ZoneId.of("UTC")));
    System.out.println(parsed.toLocalDateTime());
  }
}

and gave me output as

2012-02-22T02:06:58.147
Share:
165,532
daydreamer
Author by

daydreamer

Hello Viewer, Some of the places to see my work are BonsaiiLabs My Website

Updated on March 09, 2020

Comments

  • daydreamer
    daydreamer about 4 years

    I get the datetime value as

    created_at  '2012-02-22T02:06:58.147Z'
    Read-only. The time at which this task was created.
    

    Which is given by Asana API

    I am using Java 8 to parse the date time as following

    import java.time.*;
    import java.time.format.*;
    
    public class Times {
    
      public static void main(String[] args) {
        final String dateTime = "2012-02-22T02:06:58.147Z";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SX");
    
    
        final ZonedDateTime parsed = ZonedDateTime.parse(dateTime, formatter);
        System.out.println(parsed);
      }
    }
    

    When I run this, I get the following error

    Exception in thread "main" java.time.format.DateTimeParseException: Text '2012-02-22T02:06:58.147Z' could not be parsed at index 21
        at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
        at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
        at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)
        at Times.main(Times.java:11)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
    

    What is not right here?

  • Meno Hochschild
    Meno Hochschild about 8 years
    Good observation regarding strict or lenient mode! I had originally assumed lenient mode in my answer. For information: Pattern with only one S-symbol instead of ".SSS" is okay in lenient mode.
  • UserBSS1
    UserBSS1 almost 3 years
    Saved by "format "+01:00" or "+01:00:00" (when not "Z"), then you can use DateTimeFormatter.ISO_OFFSET_DATE_TIME"