ampofila
ampofila

Reputation: 676

Java 8 LocalDateTime ZonedDateTime cannot parse date with time zone

I am trying to use Java 8 new Date pattern instead of Joda and I have the following problem:

Both

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS Z"))

and

LocalDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS Z"))

throw 'java.time.format.DateTimeParseException' exception. While

org.joda.time.DateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormat.forPattern("dd/MM/yy HH:mm.ss.SSS Z"))

works fine.

Cause of the exception is:

java.time.format.DateTimeParseException: Text '02/05/16 11:51.12.083 +04:30' could not be parsed at index 22

Am I doing something wrong?

Upvotes: 7

Views: 13864

Answers (4)

assylias
assylias

Reputation: 328598

If you read the javadoc of DateTimeFormatter, you will find a section detailing how to use the Z offset (emphasis mine):

Offset Z: This formats the offset based on the number of pattern letters. One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero. Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero. Five letters outputs the hour, minute, with optional second if non-zero, with colon. It outputs 'Z' if the offset is zero. Six or more letters throws IllegalArgumentException.

So using 5 Zs will work as expected:

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30",
                    DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS ZZZZZ"));

Note that you can obtain similar results with:

  • z
  • zz
  • zzz
  • zzzz
  • xxx
  • XXX
  • xxxxx
  • XXXXX

Upvotes: 13

greg-449
greg-449

Reputation: 111142

Using DateTimeFormatterBuilder to get exact control of the parser and using appendOffsetId works:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
      .appendValue(ChronoField.DAY_OF_MONTH, 2)
      .appendLiteral('/')
      .appendValue(ChronoField.MONTH_OF_YEAR, 2)
      .appendLiteral('/')
      .appendValueReduced(ChronoField.YEAR, 2, 2, 2000)
      .appendLiteral(' ')
      .appendValue(ChronoField.HOUR_OF_DAY)
      .appendLiteral(':')
      .appendValue(ChronoField.MINUTE_OF_HOUR)
      .appendLiteral('.')
      .appendValue(ChronoField.SECOND_OF_MINUTE)
      .appendLiteral('.')
      .appendValue(ChronoField.MILLI_OF_SECOND)
      .appendLiteral(' ')
      .appendOffsetId()
      .toFormatter();

OffsetDateTime.parse("02/05/16 11:51.12.083 +04:30", formatter);

Upvotes: 1

Hank D
Hank D

Reputation: 6471

You need to use XXX for the zone offset. This will work for ZonedDateTime and OffsetDateTime

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

It will parse with LocalDateTime as well, but the zone offset will be truncated.

Upvotes: 0

ampofila
ampofila

Reputation: 676

I found the answer in this post Unparsable Date with colon-separated timezone

In order to parse a timestamp that carries a timezone with a semicolon instead of X or Z as the DateFormatter javadoc indicates, you need to use XXX. All the following work:

LocalDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

OffsetDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

Upvotes: 2

Related Questions