Разбор строки в ZonedDateTime с помощью DateTimeFormatter

Я пытаюсь разобрать этот String на ZonedDateTime:

"Mon 14 Aug 2017 02:00 AM CEST"

Вот моя последняя попытка:

System.out.println("Test ZonedDateTime: " + ZonedDateTime.parse(
            "Mon 14 Aug 2017 02:00 AM CEST",
            DateTimeFormatter.ofPattern("EEEE dd M yyyy KK:mm a z")));

И ответ:

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Mon 14 Aug 2017 02:00 AM CEST' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)
at be.hypertux.test.localtime.Main.main(Main.java:17)

Любые идеи?


person Anonymuf    schedule 17.08.2017    source источник


Ответы (2)


Одна проблема заключается в том, что короткие имена часовых поясов, такие как CEST и CET, двусмысленны и нестандартны. . В идеале следует использовать названия часовых поясов IANA (всегда в формате Continent/City, например America/Sao_Paulo или Europe/Berlin). .

Я предполагаю, что CEST – это летнее время Центральной Европы, то есть используется во многих странах (вот почему это двусмысленно: вы не можете знать какая это страна или регион, потому что это слишком широкий диапазон).

Хотя большинство сокращений не распознаются (из-за их двусмысленности), некоторые «значения по умолчанию» предполагаются по соображениям совместимости с предыдущими версиями. В используемой мной версии (JDK 1.8.0_131) по умолчанию используется Europe/Paris, но не уверен, что это то, что вам нужно. И не гарантируется, что он будет работать для всех сокращений. В этом случае вы можете определить предпочтительный часовой пояс для использования (и это будет произвольный выбор, но другого пути нет, поскольку CEST неоднозначен).

Другая проблема заключается в том, что месяц и день недели указаны на английском языке (Aug и Mon), а вы не указали java.util.Locale. В этом случае DateTimeFormatter принимает языковой стандарт системы по умолчанию (и, вероятно, это не английский язык — проверьте значение Locale.getDefault()). В любом случае, локаль по умолчанию может быть изменена без предварительного уведомления даже во время выполнения, поэтому лучше указать ее при работе с локализованными данными (такими как месяц и день недели). имена).

Таким образом, вы должны указать локаль и определить произвольный часовой пояс в качестве предпочтительного для использования при обнаружении неоднозначного имени, такого как CEST. Для этого вы можете использовать java.time.format.DateTimeFormatterBuilder, набор предпочтительных часовых поясов и java.time.format.TextStyle:

// create set of preferred timezones
Set<ZoneId> zones = new HashSet<>();
// my arbitrary choice for CEST
zones.add(ZoneId.of("Europe/Brussels"));
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // date and time
    .appendPattern("EEE dd MMM yyyy hh:mm a ")
    // timezone short name with custom set of preferred zones
    .appendZoneText(TextStyle.SHORT, zones)
    // create formatter (use English locale for month and day of week)
    .toFormatter(Locale.ENGLISH);

String input = "Mon 14 Aug 2017 02:00 AM CEST";
System.out.println(ZonedDateTime.parse(input, formatter));

Вывод будет:

2017-08-14T02:00+02:00[Европа/Брюссель]

Обратите внимание, что я использовал Europe/Brussels в качестве предпочтительного часового пояса. Вы можете проверить все доступные имена зон (и выбрать соответственно) с помощью ZoneId.getAvailableZoneIds().


Я использую hh для часов, что соответствует hour-clock-of-am-pm field (значения от 1 до 12). Но в своем коде вы использовали KK, то есть поле часы-утра-послеполуденного (значения от 0 до 11). Проверьте, какой из них лучше всего подходит для вашего случая.


Часовой пояс — это набор всех различных смещений, которые регион имел, имеет и будет иметь во время своего существования. история, а также даты начала и окончания перехода на летнее время и т. д. Если 2 региона имеют некоторую разницу в этой истории, они будут иметь разные часовые пояса (даже если сегодня они используют одни и те же правила).

Тот факт, что Париж и Брюссель используют одни и те же правила сегодня (CET и CEST), не означает, что так будет всегда (поскольку правила часовых поясов определяются правительствами и законами, и нет никакой гарантии, что они не будут изменены в ближайшее время). любое время в будущем).

Вот почему вы должны определить какой-то конкретный часовой пояс, а не полагаться на двусмысленные короткие имена (хотя их использование является обычным и широко распространенным).

person Community    schedule 17.08.2017
comment
Спасибо за большой ответ ;-). Моя проблема заключалась в значении Locale по умолчанию (которое было на BE). А по проблеме зоны я просто делаю себе упражнение, пытаюсь разобрать данные, полученные из запроса от YQL, чтобы узнать погоду. Так что у меня не слишком большой выбор, и поскольку это не является целью моего проекта, я позволю себе стандарты Yahoo и Java ^^ - person Anonymuf; 18.08.2017

Чтобы ваша строка формата работала, ваша дата должна быть отформатирована следующим образом: Monday 14 8 2017 02:00 AM CEST

Выньте E и добавьте пару M, и это должно сработать.

person Joe C    schedule 17.08.2017
comment
Пробовал с EEE dd LLL yyyy KK:mm a z, то же исключение:/ - person Anonymuf; 17.08.2017
comment
Mс, а не Lс. - person Joe C; 17.08.2017
comment
Тоже пробовал, такое же сообщение не удалось разобрать с индексом 0. - person Anonymuf; 17.08.2017
comment
У меня работает нормально. - person Joe C; 17.08.2017
comment
Как сказал @Hugo, проблема заключалась в значении Locale по умолчанию, которое не позволяло мне распознавать день недели. Спасибо, в любом случае. - person Anonymuf; 18.08.2017