7

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?

Hank D
  • 6,271
  • 2
  • 26
  • 35
ampofila
  • 655
  • 2
  • 13
  • 28
  • 3
    Have you tried OffsetDateTime? It doesn't contain enough information to know an actual time zone; all it carries is the offset from UTC. – Hank D May 16 '16 at 12:26
  • Although from the example in the [docs](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html), it seems colon is accepted as zone offset delimeter but when you try it, it throws the exception. if you just remove the colon it should work. so your datetime string should be `02/05/16 11:51.12.083 +0430` – Rahul Sharma May 16 '16 at 12:26
  • @Hank D I tried this OffsetDateTime.parse("02/05/16 11:51.12.083 +04:30",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss.SSS Z")) but I still get the same exception. – ampofila May 16 '16 at 12:31
  • @Rahul I do not control the input so I cannot remove the colon, I do not like to parse this as a String if this is what you mean. Also even with the colon removed I still get the same exception. (ZonedDateTime.parse("02/05/16 11:51.12.083 +0430",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss.SSS Z"))) – ampofila May 16 '16 at 12:33
  • The error must have been different this time, you have capital 'YY' change it to lower case 'yy'. – Rahul Sharma May 16 '16 at 12:48
  • Yes, sorry, this works. But I d still have to remove the colon. – ampofila May 16 '16 at 12:51
  • By the way, fyi, if you can get your inputs in the standard [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format you won’t need formatters. The java.time classes use ISO 8601 by default so you can parse directly, such as [`OffsetDateTime.parse( "2016-02-05T11:51.12.083+04:30" )`](http://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html#parse-java.lang.CharSequence-); – Basil Bourque May 16 '16 at 22:52
  • [`OffsetDateTime`](http://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html) is the best fit for the data seen in this Question. [`LocalDateTime`](http://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html) purposely drops the [offset-from-UTC](https://en.wikipedia.org/wiki/UTC_offset) information. [`ZonedDateTime`](http://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html) is for a full time zone, which is an offset *plus* rules for handling anomalies such as Daylight Saving Time (DST). – Basil Bourque May 16 '16 at 23:00

4 Answers4

12

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
assylias
  • 321,522
  • 82
  • 660
  • 783
2

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"))
Community
  • 1
  • 1
ampofila
  • 655
  • 2
  • 13
  • 28
1

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);
greg-449
  • 109,219
  • 232
  • 102
  • 145
0

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.

Hank D
  • 6,271
  • 2
  • 26
  • 35
  • I have tried this, still the same exception. (ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss.SSS X"))) – ampofila May 16 '16 at 12:35