13

I'm trying to move from Joda to Java 8's ZonedDateTime and I'm hitting a wall with the DateTimeFormatterBuilder that I cannot seem to work around.

I want to accept any of these formats:

2013-09-20T07:00:33
2013-09-20T07:00:33.123
2013-09-20T07:00:33.123+0000
2013-09-20T07:00:33.123Z
2013-09-20T07:00:33.123Z+0000
2013-09-20T07:00:33+0000

Here is my current builder:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .optionalStart()
        .appendPattern(".SSS")
        .optionalEnd()
        .optionalStart()
        .appendZoneId()
        .optionalEnd()
        .optionalStart()
        .appendPattern("Z")
        .optionalEnd()
        .toFormatter();

I'm probably wrong, but it appears that should match the patterns I want... right?

If anyone could point of what I may have missed, it'd be appreciated. I'm also not too sure of the use of appendOffset, so clarity on that is also appreciated if it turns out to be the answer.

Edit:

Text '2013-09-20T07:00:33.061+0000' could not be parsed at index 23

Looking at the builder, this appears to match due to the optional stages?

Edit 2:

After seeing advice from the first answer, I tried this:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .optionalStart()
        .appendPattern(".SSS")
        .optionalEnd()
        .optionalStart()
        .appendZoneOrOffsetId()
        .optionalEnd()
        .toFormatter()

It continues to fail on the string above.

Edit 3:

Latest tests result in this exception:

java.time.format.DateTimeParseException: Text '2013-09-20T07:00:33.061+0000' could not be parsed at index 23
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 java.time.ZonedDateTime.parse(ZonedDateTime.java:582)
whitfin
  • 4,539
  • 6
  • 39
  • 67
  • "I'm probably wrong, but it appears that should match the patterns I want... right?" Did you try to match them in a test program? What happened? – nanofarad Apr 17 '15 at 23:12
  • @hexafraction yeah just put a few strings through; this one specifically is causing issue: `Text '2013-09-20T07:00:33.061+0000' could not be parsed at index 23` – whitfin Apr 17 '15 at 23:13

2 Answers2

16

It may be the reason that +0000 is not a zone id, but a zone offset.

the documentation offers this list:

  Symbol       Meaning                     Presentation      Examples
  ------       -------                     ------------      -------
       V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
       z       time-zone name              zone-name         Pacific Standard Time; PST
       O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
       X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
       x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
       Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

You may use appendOffset("+HHMM", "0000") (doc) or appendZoneOrOffsetId() (doc) instead of appendZoneId().

so your full formatter may look like the following

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                .optionalStart()
                .appendPattern(".SSS")
                .optionalEnd()
                .optionalStart()
                .appendZoneOrOffsetId()
                .optionalEnd()
                .optionalStart()
                .appendOffset("+HHMM", "0000")
                .optionalEnd()
                .toFormatter();

Further the way of creating a ZonedDateTime may influence if there is an exception or not. Therefore I'd recommend the following as this worked without any exceptions.

LocalDateTime time = LocalDateTime.parse("2013-09-20T07:00:33.123+0000", formatter);
ZonedDateTime zonedTime = time.atZone(ZoneId.systemDefault());
sailingthoms
  • 900
  • 10
  • 22
  • With or without the `appendPattern`? The string I left in the question is still erroring with `appendZoneOrOffsetId` – whitfin Apr 17 '15 at 23:27
  • 2
    basically I'd say without, but I'm not sure about `2013-09-20T07:00:33.123Z+0000` because it has the cero-time Z and +0000 offset. As far as I know about this times Z and +0000 mean the same. – sailingthoms Apr 17 '15 at 23:29
  • ok; I tried that and it fails on `2013-09-20T07:00:33.061+0000` - I added my modifications to the question, in case I misunderstood. – whitfin Apr 17 '15 at 23:36
  • 1
    You may even use `appendOffset("+HHMM", "0000")` instead of `appendZoneOrOffsetId()`. I did minor testing and the latter seem to expect "+HH:MM" (with colon) formatted offsets. – sailingthoms Apr 17 '15 at 23:53
  • I appreciate the testing. I copied what you had over, but `2013-09-20T07:00:33.061+0000` is still not working correctly... any ideas? Every form I can think of hasn't seemed to work. – whitfin Apr 18 '15 at 00:00
  • 1
    is there an exception or is the result not correct? – sailingthoms Apr 18 '15 at 00:02
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75557/discussion-between-sailingthoms-and-zackehh). – sailingthoms Apr 18 '15 at 00:04
  • I'm using your solution and it doesn't parse `2016-03-21T14:34:06.395000`. The `optionalStart()` doesn't really do anything. If I needed two formatters, `.parseCaseInsensitive().append(DateTimeFormatter.ISO_LOCAL_DATE_TIME).optionalStart().appendOffset("+HHmm", "Z").toFormatter();` and `.parseCaseInsensitive().append(DateTimeFormatter.ISO_LOCAL_DATE_TIME).toFormatter();` and basically try to parse twice. – stewart99 Jun 22 '16 at 01:12
0

Did you try .appendPattern("ZZZ")? it would probably work!