Как получить DateTime {Zoned, Offset} из строки "06.03.2018 06:00 CET"? - PullRequest
0 голосов
/ 27 апреля 2018

Я пытаюсь проанализировать дату и время из европейской ленты RSS. Дата выглядит так: "06.03.2018 06:00 CET". Я хочу ZonedDateTime или OffsetDateTime, но я не могу убедить Java разобрать строку. Что я делаю не так?

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.YYYY HH:mm z");
ZonedDateTime zdt = ZonedDateTime.parse("06.03.2018 06:00 CET", dtf);

Caused by: java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: {WeekBasedYear[WeekFields[SUNDAY,1]]=2018, MonthOfYear=3, DayOfMonth=6},ISO,Europe/Paris resolved to 06:00 of type java.time.format.Parsed

// seems to be crashing here:  LocalDate.java:363
public static LocalDate from(TemporalAccessor temporal) {
    Objects.requireNonNull(temporal, "temporal");
    LocalDate date = temporal.query(TemporalQueries.localDate());
    if (date == null) {  // <== SOMEHOW THIS IS NULL
        throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " +
                temporal + " of type " + temporal.getClass().getName());
    }
    return date;
}

Значение temporal равно:

{WeekBasedYear[WeekFields[SUNDAY,1]]=2018, MonthOfYear=3, DayOfMonth=6},ISO,Europe/Paris resolved to 06:00

1 Ответ

0 голосов
/ 27 апреля 2018

Прописные буквы Y представляют недельный год (подробное объяснение см. здесь ), а поле года представлено строчными буквами y. См. Javadoc для деталей: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns

Поэтому измените ваш шаблон на "дд.мм. гггг ЧЧ: мм z".

Еще одна деталь заключается в том, что сокращения часовых поясов неоднозначны. CET используется более чем одной страной, поэтому он может быть сопоставлен с несколькими часовыми поясами: https://www.timeanddate.com/time/zones/cet#tz-where

Некоторые аббревиатуры могут работать (иначе «не выбрасывает исключение»), но они будут сопоставлены с произвольным значением по умолчанию, которое вы не можете контролировать. В моей JVM работает этот код:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm z");
ZonedDateTime zdt = ZonedDateTime.parse("06.03.2018 06:00 CET", dtf);

Производит ZonedDateTime равно:

2018-03-06T06: 00 + 01: 00 [Европа / Париж]

CET был сопоставлен с «Европа / Париж» (что является произвольным выбором JVM, но это не гарантия того, что вы всегда получите это). И CET также используется во многих других часовых поясах, таких как «Европа / Берлин», «Европа / Мадрид» и многие другие.

Если вы хотите точно контролировать, какой часовой пояс вы хотите использовать при сокращении, вы можете создать набор с вашими вариантами выбора и использовать DateTimeFormatterBuilder для создания DateTimeFormatter:

// set of preferred zones
Set<ZoneId> preferredZones = new HashSet<ZoneId>();
// my arbitrary choice for CET
preferredZones.add(ZoneId.of("Europe/Berlin"));
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
    // date/time
    .appendPattern("dd.MM.yyyy HH:mm ")
    // zone names
    .appendZoneText(TextStyle.SHORT, preferredZones)
    // create formatter
    .toFormatter(Locale.US);

ZonedDateTime zdt = ZonedDateTime.parse("06.03.2018 06:00 CET", dtf);

Теперь для ZonedDateTime будет установлен часовой пояс, который я выбрал в своем наборе предпочтительных зон:

2018-03-06T06: 00 + 01: 00 [Europe / Berlin]

...