Преобразование строки, соответствующей ISO 8601, в java.util.Date - PullRequest
602 голосов
/ 04 февраля 2010

Я пытаюсь преобразовать строку формата ISO 8601 в java.util.Date.

Я обнаружил, что шаблон yyyy-MM-dd'T'HH:mm:ssZ соответствует ISO8601, если используется с локалью (сравните образец).

Однако, используя java.text.SimpleDateFormat, я не могу преобразовать правильно отформатированную строку 2010-01-01T12:00:00+01:00. Я должен сначала преобразовать его в 2010-01-01T12:00:00+0100, без двоеточия.

Итак, текущее решение

SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.GERMANY);
String date = "2010-01-01T12:00:00+01:00".replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
System.out.println(ISO8601DATEFORMAT.parse(date));

что явно не так приятно. Я что-то упустил или есть лучшее решение?


Ответ

Благодаря комментарию JuanZe я обнаружил магию Joda-Time , также описанную здесь .

Итак, решение

DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));

Или, проще, используйте парсер по умолчанию через конструктор:

DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;

Мне это приятно.

Ответы [ 26 ]

6 голосов
/ 20 июля 2014

java.time

Обратите внимание, что в Java 8 вы можете использовать класс java.time.ZonedDateTime и его статический метод parse(CharSequence text).

6 голосов
/ 16 мая 2017

Обходной путь для Java 7+ использует SimpleDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);

Этот код может анализировать формат ISO8601 как:

  • 2017-05-17T06:01:43.785Z
  • 2017-05-13T02:58:21.391+01:00

Но на Java6 SimpleDateFormat не понимает X символа и будет выбрасывать
IllegalArgumentException: Unknown pattern character 'X'
Нам нужно нормализовать дату ISO8601 в формате, читаемом в Java 6, с SimpleDateFormat.

public static Date iso8601Format(String formattedDate) throws ParseException {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
        return df.parse(formattedDate);
    } catch (IllegalArgumentException ex) {
        // error happen in Java 6: Unknown pattern character 'X'
        if (formattedDate.endsWith("Z")) formattedDate = formattedDate.replace("Z", "+0000");
        else formattedDate = formattedDate.replaceAll("([+-]\\d\\d):(\\d\\d)\\s*$", "$1$2");
        DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
        return df1.parse(formattedDate);
    }
}

Метод выше для замены [Z на +0000] или [+01:00 на +0100] при возникновении ошибки в Java 6 (вы можете определить версию Java и заменить try / catch на оператор if).

4 голосов
/ 14 января 2015

Также вы можете использовать следующий класс -

org.springframework.extensions.surf.util.ISO8601DateFormat


Date date = ISO8601DateFormat.parse("date in iso8601");

Ссылка на документ Java - Иерархия для пакета org.springframework.extensions.surf.maven.plugin.util

4 голосов
/ 10 июля 2015

Я столкнулся с такой же проблемой и решил ее с помощью следующего кода.

 public static Calendar getCalendarFromISO(String datestring) {
    Calendar calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()) ;
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
    try {
        Date date = dateformat.parse(datestring);
        date.setHours(date.getHours() - 1);
        calendar.setTime(date);

        String test = dateformat.format(calendar.getTime());
        Log.e("TEST_TIME", test);

    } catch (ParseException e) {
        e.printStackTrace();
    }

    return calendar;
}

Ранее я использовал SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());

Но позже я обнаружил, что основной причиной исключения были yyyy-MM-dd'T'HH:mm:ss.SSSZ,

Так что я использовал

SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());

У меня все работало нормально.

3 голосов
/ 20 июня 2015

Как уже упоминалось, Android не имеет хорошего способа поддержки разбора / форматирования дат ISO 8601 с использованием классов, включенных в SDK. Я написал этот код несколько раз, поэтому я наконец создал Gist, включающий класс DateUtils, который поддерживает форматирование и анализ дат ISO 8601 и RFC 1123. Gist также включает в себя контрольный пример, показывающий, что он поддерживает.

https://gist.github.com/mraccola/702330625fad8eebe7d3

3 голосов
/ 22 апреля 2013

Apache Jackrabbit использует формат ISO 8601 для сохранения дат, и для их анализа существует вспомогательный класс:

org.apache.jackrabbit.util.ISO8601

Поставляется с jackrabbit-jcr-commons .

2 голосов
/ 01 октября 2013

SimpleDateFormat для JAVA 1.7 имеет классный шаблон для формата ISO 8601.

Класс SimpleDateFormat

Вот что я сделал:

Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
         Locale.ENGLISH).format(System.currentTimeMillis());
2 голосов
/ 13 сентября 2017

У Java есть дюжина различных способов разбора даты и времени, как показывают отличные ответы. Но, что удивительно, ни один из временных классов Java полностью не реализует ISO 8601!

С Java 8 я бы порекомендовал:

ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());

Это будет обрабатывать примеры как в формате UTC, так и со смещением, например «2017-09-13T10: 36: 40Z» или «2017-09-13T10: 36: 40 + 01: 00». Это подходит для большинства случаев использования.

Но он не будет обрабатывать такие примеры, как "2017-09-13T10: 36: 40 + 01", который равен действительной дате и времени ISO 8601.
Также не будет обрабатываться только дата, например "2017-09-13".

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

Здесь приведен хороший список примеров ISO 8601 с множеством угловых случаев: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ Я не знаю ни одного Java-класса, который мог бы справиться со всеми ними.

1 голос
/ 18 июля 2017

Использовать строку как LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)

1 голос
/ 19 октября 2016

Сделай так:

public static void main(String[] args) throws ParseException {

    String dateStr = "2016-10-19T14:15:36+08:00";
    Date date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr).getTime();

    System.out.println(date);

}

Вот вывод:

Ср. 19 октября 15:15:36 CST 2016

...