Общая поддержка формата ISO 8601 в Java 6

Java 7 представила поддержку в SimpleDateFormat класс для формата ISO 8601, через символ X (вместо нижнего или верхнего регистра Z). Поддержка таких форматов в Java 6 требует предварительной обработки, поэтому лучшим подходом является вопрос.

этот новый формат является надмножеством Z (верхний регистр Z), с 2 дополнительными вариациями:

  1. поле "минуты" является необязательным (т. е. допустимы 2-значные вместо 4-значные часовые пояса)
  2. A символ двоеточия ( ' :') может использоваться для отделения 2-значного поля "часы" от 2-значного поля "минуты").

Итак, как можно наблюдать из Java 7 документация SimpleDateFormat, следующие 3 формата теперь действительны (вместо только второго, покрытого Z в Java 6) и, конечно, эквивалент:

  1. -08
  2. -0800
  3. -08:00

как обсуждается в ранее вопрос о специальном случае поддержки такого "расширенного" формата часового пояса, всегда с": "в качестве разделителя, лучший подход для обратной передачи функциональности Java 7 в Java 6-подкласс SimpleDateformat класс и переопределить его parse() метод, я.е:

public Date parse(String date, ParsePosition pos)
{
    String iso = ... // Replace the X with a Z timezone string, using a regex

    if (iso.length() == date.length())
    {
        return null; // Not an ISO 8601 date
    }

    Date parsed = super.parse(iso, pos);

    if (parsed != null)
    {
        pos.setIndex(pos.getIndex()+1); // Adjust for ':'
    }

    return parsed;
}

обратите внимание, что подкласс SimpleDateFormat объекты выше должны быть инициализированы соответствующим Zна основе шаблона, т. е. если подкласс ExtendedSimpleDateformat и вы хотите проанализировать даты, соответствующие шаблону yyyy-MM-dd'T'HH:mm:ssX, то вы должны использовать объекты, созданные как

new ExtendedSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

в вышеуказанном ранее вопрос регулярное выражение :(?=[0-9]{2}$) было предложено избавиться от": "и в аналогичный вопрос регулярное выражение (?<=[+-]d{2})$ было предложено добавить поле "минута" как 00, если это необходимо.

очевидно, что запуск 2 замены успешно может быть использован для достижения полной функциональности. Итак,iso локальная переменная в переопределенном parse() метод будет установлен как

iso = date.replaceFirst(":(?=[0-9]{2}$)","");

или

iso = iso.replaceFirst("(?<=[+-]d{2})$", "00");

С if проверьте между, Чтобы убедиться, что pos значение также устанавливается правильно позже, а также для length() сравнение ранее.

вопрос в том, можем ли мы использовать одно регулярное выражение для достижения того же эффекта, включая информацию, необходимую для не ненужной проверки длины и для правильной настройки pos a спустя несколько строк?

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

2 ответов


Кажется, что вы можете использовать это:

import java.util.Calendar;
import javax.xml.bind.DatatypeConverter;

public class TestISO8601 {
    public static void main(String[] args) {
        parse("2012-10-01T19:30:00+02:00"); // UTC+2
        parse("2012-10-01T19:30:00Z");      // UTC
        parse("2012-10-01T19:30:00");       // Local
    }
    public static Date parse(final String str) {
        Calendar c = DatatypeConverter.parseDateTime(str);
        System.out.println(str + "\t" + (c.getTime().getTime()/1000));
        return c.getTime();
    }
}

вы можете использовать java.время, современный API даты и времени Java, в Java 6. Это казалось бы мне хорошим, а также перспективным решением. Он имеет хорошую поддержку ISO 8601.

import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.format.DateTimeFormatter;

public class DemoIso8601Offsets {
    public static void main(String[] args) {
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+0200", 
                DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX")));
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02", 
                DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX")));
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02:00"));
        System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00Z"));
    }
}

выход из этой программы-это:

2012-10-01T19:30+02:00
2012-10-01T19:30+02:00
2012-10-01T19:30+02:00
2012-10-01T19:30Z

требуется добавить библиотеку Backport ThreeTen в настройку проекта.

  • в Java 8 и более поздних версиях и на новых устройствах Android (от уровня API 26) современный API поставляется встроенный.
  • в Java 6 и 7 получите Threeten Backport, backport новых классов (ThreeTen для JSR 310; см. Ссылки внизу).
  • на (Старше) Android использовать Android издание ThreeTen Backport. Это называется ThreeTenABP. И убедитесь, что вы импортируете классы даты и времени из org.threeten.bp С подпакетами.

как вы можете видеть из кода +02 и +0200 требует форматирования, в котором можно указать формат смещения, а +02:00Z too) соответствует формату по умолчанию и не нуждается в указании.

можем ли мы проанализировать все форматы смещения, используя один и тот же форматер?

при чтении смешанных данных, вы не хотите обрабатывать каждый формат офсетная специально. Лучше использовать дополнительные части в формате pattern string:

    DateTimeFormatter allInOne 
            = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[XXX][XX][X]");
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+0200", allInOne));
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02", allInOne));
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02:00", allInOne));
    System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00Z", allInOne));

выход такой же, как и выше. Квадратные скобки в [XXX][XX][X] означает, что либо format +02:00, +0200 или +02 может быть подарок.

ссылки