Использование DateTimeFormatterBuilder в Java 8, в частности optionals

Я пытаюсь перейти от Joda к Java 8's ZonedDateTime и я бьюсь об стену с DateTimeFormatterBuilder что я, кажется, не могу обойти.

Я хочу принять любой из этих форматов:

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

вот мой текущий строитель:

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

Я, вероятно, ошибаюсь, но, похоже, это должно соответствовать шаблонам, которые я хочу... правильно?

если бы кто-нибудь мог указать на то, что я, возможно, пропустил, это было бы оценено. Я также не слишком уверен в использовании appendOffset, так ясность в этом также приветствуется, если это окажется ответом.

Edit:

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

глядя на строителя, это, кажется, соответствует из-за дополнительных этапов?

Edit 2:

увидев совет из первого ответа, я попробовал это:

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

он продолжает терпеть неудачу на строке выше.

Edit 3:

последние тесты приводят к этому исключение:

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)

1 ответов


это может быть причиной того, что +0000 - это не идентификатор зоны, а смещение зоны.

на документация предлагает такой список:

  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;

вы можете использовать appendOffset("+HHMM", "0000") (doc) или appendZoneOrOffsetId() (doc) вместо appendZoneId().

таким образом, ваш полный формат может выглядеть следующим образом

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

далее способ создания ZonedDateTime может повлиять, если есть исключение или нет. Поэтому я бы рекомендовал следуя, как это работало без каких-либо исключений.

LocalDateTime time = LocalDateTime.parse("2013-09-20T07:00:33.123+0000", formatter);
ZonedDateTime zonedTime = time.atZone(ZoneId.systemDefault());