3

I am trying to parse an input string to local date time.

Below is my piece of code

 ZonedDateTime z = ZonedDateTime.parse("2019-11-26T19:30:00Z", MY_DATE_TIME_FORMATTER);

where

MY_DATE_TIME_FORMATTER= new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(ISO_LOCAL_DATE)
            .appendLiteral('T')
            .append(ISO_LOCAL_TIME)
            .appendLiteral('Z')
            .appendOffset("+HH:mm", "+0000")
            .toFormatter();

I get the following exception

java.time.format.DateTimeParseException: Text '2019-11-26T19:30:00Z' could not be parsed at index 19

Can you please advise on what I am doing wrong here?

ETO
  • 6,970
  • 1
  • 20
  • 37
Ram Viswanathan
  • 181
  • 3
  • 14
  • thanks @Jens unfortunately i am not able to change my input string. I just used the hardcoded string as an example. With the input string as-is, can I still parse it? – Ram Viswanathan Oct 07 '19 at 19:08
  • can you tell what is your expected output – Ryuzaki L Oct 07 '19 at 19:50
  • Are you sure? I get `java.time.format.DateTimeParseException: Text '2019-11-26T19:30:00Z' could not be parsed at index 20`, note: 20 instead of 19. – Ole V.V. Oct 08 '19 at 14:13

3 Answers3

3

Instant.parse

No formatting pattern needed.

Instant.parse( "2019-11-26T19:30:00Z" ) 

Your input format complies with ISO 8601 standard. That particular format has a Z on the end. That letter means UTC (an offset of zero hours-minutes-seconds), and is pronounced “Zulu”.

The Instant class in java.time represents a moment in UTC, always UTC.

Using ZonedDateTime class for that input is not the most appropriate. We have:

  • Instant for values that are always in UTC.
  • OffsetDateTime for moments where only an offset-from-UTC is known but not a time zone. Use this class for UTC values too when you need more flexibility such as generating strings in various formats. `instant.atOffset(
  • ZonedDateTime for values in a time zone. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.

Table of date-time types in Java, both modern and legacy

To view that same moment adjusted to the offset used by the people of a particular region (a time zone), apply a ZoneId to get a ZonedDateTime object.

Instant instant = Instant.parse( "2019-11-26T19:30:00Z" ) ;     // Default format for parsing a moment in UTC.
ZoneId z = ZoneId.of( "America/Edmonton" ) ;                    // A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.
ZonedDateTime zdt = instant.atZone( z ) ;                       // Same moment, same point on the timeline, different wall-clock time.

See this code run live at IdeOne.com.

instant.toString(): 2019-11-26T19:30:00Z

zdt.toString(): 2019-11-26T12:30-07:00[America/Edmonton]

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

Add

.appendZoneOrOffsetId()

instead of these two lines:

.appendLiteral('Z')
.appendOffset("+HH:mm", "+0000")

The whole builder example:

MY_DATE_TIME_FORMATTER= new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .append(ISO_LOCAL_DATE)
        .appendLiteral('T')
        .append(ISO_LOCAL_TIME)
        .appendZoneOrOffsetId()
        .toFormatter();

P.S. In your specific case I'd rather use the standard ISO formatter (as Hristo mentioned):

ZonedDateTime z = ZonedDateTime.parse("2019-11-26T19:30:00Z", DateTimeFormatter.ISO_ZONED_DATE_TIME);

Moreover, the ZonedDateTime::parse method will work even without the explicit formatter. Since it's used by default:

ZonedDateTime z = ZonedDateTime.parse("2019-11-26T19:30:00Z");
ETO
  • 6,970
  • 1
  • 20
  • 37
0

Use the built in ISO zoned time formatter

    ZonedDateTime.parse("2019-11-26T19:30:00Z", DateTimeFormatter.ISO_ZONED_DATE_TIME);
Hristo Angelov
  • 1,019
  • 1
  • 15
  • 34