Ram Viswanathan
Ram Viswanathan

Reputation: 201

Local datetime parsing

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?

Upvotes: 3

Views: 165

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338496

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]

Upvotes: 3

ETO
ETO

Reputation: 7279

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");

Upvotes: 1

Hristo Angelov
Hristo Angelov

Reputation: 1049

Use the built in ISO zoned time formatter

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

Upvotes: 0

Related Questions