Один класс для разбора любого формата даты в Java - PullRequest
0 голосов
/ 07 января 2019

Я разбираю даты в следующих форматах. Я поддерживаю массив этих форматов и анализирую каждую строку даты во всех этих форматах.

Код, который я использовал, был -

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
simpleDateFormat.setTimeZone(timeZone); //timeZone is a java.util.TimeZone object       
Date date = simpleDateFormat.parse(dateString);

Теперь я также хочу проанализировать формат yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX, но при использовании SimpleDateFormat 6-значные микросекунды не учитываются. Поэтому я посмотрел на пакет java.time.

Для разбора yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX форматов мне понадобится класс OffsetDateTime , а для других форматов мне понадобится класс ZonedDateTime . Формат будет установлен в DateTimeFormatter class.

Есть ли способ использовать один класс, например SimpleDateFormat, для передачи всех форматов?

1 Ответ

0 голосов
/ 07 января 2019

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

private static void parseAndPrint(String formatPattern, String dateTimeString) {
    // Try parsing without zone first
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
    Instant parsedInstant;
    try {
        parsedInstant = formatter.parse(dateTimeString, Instant::from);
    } catch (DateTimeParseException dtpe) {
        // Try parsing with zone
        ZoneId defaultZone = ZoneId.of("Asia/Calcutta");
        formatter = formatter.withZone(defaultZone);
        parsedInstant = formatter.parse(dateTimeString, Instant::from);
    }
    System.out.println("Parsed instant: " + parsedInstant);
}

Давайте попробуем:

    parseAndPrint("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", "2018-10-22T02:17:58.717853Z");
    parseAndPrint("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", "2018-10-22T02:17:58.717853");
    parseAndPrint("EEE MMM d HH:mm:ss zzz yyyy", "Mon Oct 22 02:17:58 CEST 2018");

Вывод на Java 8:

Parsed instant: 2018-10-22T02:17:58.717853Z
Parsed instant: 2018-10-21T20:47:58.717853Z
Parsed instant: 2018-10-22T00:17:58Z

Первый пример имеет смещение в строке и последнее сокращение строки часового пояса в строке, и в обоих случаях они соблюдаются: напечатанный момент скорректировал время в UTC (поскольку Instant всегда печатается в UTC , его toString метод гарантирует). Средний пример не имеет ни смещения, ни часового пояса в строке, поэтому используется часовой пояс по умолчанию для Азии / Калькутты, указанный в методе.

Тем не менее, синтаксический анализ трех или четырехбуквенных сокращений часовых поясов, подобных CEST, является опасной и обескураживающей практикой, поскольку сокращения часто бывают неоднозначными. Я включил пример только для демонстрации.

Есть ли способ использовать один класс ...?

Я использовал Instant для всех случаев, так что да, есть способ использовать только один класс. Ограничение заключается в том, что впоследствии вы не знаете, был ли в строке какой-либо часовой пояс или смещение, и каким он был. Вы не знали, когда использовали SimpleDateFormat и Date, поэтому я решил, что все в порядке?

Ошибка в Java 8?

Результаты вашей демонстрации на тестере REX разочаровывают и ошибочны и не согласуются с результатами, полученными на Java 11. Мне кажется, что вы пострадали от ошибки в Java 8, возможно этот: синтаксический анализ с DateTimeFormatter.withZone не ведет себя, как описано в javadocs .

...