невозможно разобрать String-Date на java.time.LocalDateTime с определенным форматом

Следующий код печатает вывод с датой в строке со смещением временной зоны.

      String BERLIN_TIME_ZONE = "Europe/Berlin";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ssZ");
String dateTimeInString = formatter
        .format(ZonedDateTime.of(LocalDateTime.now(), ZoneId.of(BERLIN_TIME_ZONE)));

System.out.println(dateTimeInString); // 2021-06-07T02:12:08+0200

Это прекрасно работает. Теперь, когда у нас есть dateTimeInString поэтому я хочу преобразовать его обратно в LocalDateTime объект с помощью parse метод.

      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ssZ");
System.out.println(LocalDateTime.parse(dateTimeInString,formatter));

но этот синтаксический анализ вызывает исключение.

      Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-06-07T02:12:08+0200' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at de.finhome.A.main(A.java:19)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
    at java.base/java.time.LocalDateTime.from(LocalDateTime.java:461)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    ... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
    at java.base/java.time.LocalTime.from(LocalTime.java:431)
    at java.base/java.time.LocalDateTime.from(LocalDateTime.java:457)
    ... 4 more

Я проверял разные ресурсы, но не могу понять, в чем проблема.

2 ответа

Измените жетон часа с hh к HH. Строчные буквы h0–12, или то, что в документах называется « часы-час-до-вечера» . Верхний регистр H0–23, или то, что в документах называется часом дня.

В то время как форматировщик может довольно успешно выполнять вывод даты, когда вы пытаетесь прочитать ту же строку, это создает двусмысленность. Парсер не знает, ...T01:...должно быть 1:00 или PM. Поскольку он не может разобрать однозначно, он терпит неудачу.

В качестве альтернативы добавьте что-нибудь в строку формата для AM / PM (вы можете использовать aдля этого). Тогда парсер сможет однозначно интерпретировать час, например 01.

Кажется, ты тоже хочешь изменить LocalDateTime.parse к ZonedDateTime.parse так что вы не выбрасываете зону.

Это не похоже на ситуацию, когда нужно использовать.

Есть две альтернативы: как вы уже используете и OffsetDateTime, который вы, возможно, захотите использовать ...

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

Сделайте что-нибудь вроде этого:

      public static void main(String[] args) {
    // provide a zone
    String BERLIN_TIME_ZONE = "Europe/Berlin";
    // use ZonedDateTime.now() directly and pass the zone
    ZonedDateTime nowBerlin = ZonedDateTime.now(ZoneId.of(BERLIN_TIME_ZONE));
    // then create a String that actually keeps the offset and omits the zone
    String dateTimeInString = nowBerlin.format(
                                DateTimeFormatter.ISO_OFFSET_DATE_TIME
                              );
    // print the result
    System.out.println(dateTimeInString);
    
    // if you now want to convert back, use an OffsetDateTime
    OffsetDateTime nowPlus2h = OffsetDateTime.parse(dateTimeInString);
    // and print the result
    System.out.println(nowPlus2h.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
    // if you want it to not just be a time of 2 hours offset, apply the zone again
    ZonedDateTime nowAgainBerlin = nowPlus2h.atZoneSameInstant(
                                        ZoneId.of(BERLIN_TIME_ZONE)
                                    );
    // check if that's the same as parsed in the beginning
    if (nowAgainBerlin.equals(nowBerlin)) {
        System.out.println("Same instant in Berlin");
    } else {
        System.out.println("Something went wrong in Berlin");
    }
    
    // and if you really want to get a LocalDateTime, you can get it like this
    LocalDateTime localBerlin = nowBerlin.toLocalDateTime();
    LocalDateTime localAgainBerlin = nowPlus2h.toLocalDateTime();
    
    System.out.println(localBerlin + " == " + localAgainBerlin);
}

Это просто вывод

      2021-06-07T15:16:47.259+02:00
2021-06-07T15:16:47.259+02:00
Same instant in Berlin
2021-06-07T15:16:47.259 == 2021-06-07T15:16:47.259

Если вы не хотите, чтобы в вашем выводе были миллисекунды, определите средство форматирования, которое соответствует вашим желаниям, но все же вы не сможете анализировать зоны или смещения до LocalDateTime.

Другие вопросы по тегам