simpledateformat дата разбора с литералом ' Z ' [дубликат]


этот вопрос уже есть ответ здесь:

Я пытаюсь разобрать дату, которая выглядит так:

2010-04-05T17:16:00Z

это допустимая дата для http://www.ietf.org/rfc/rfc3339.txt. литерал ' Z ' означает, что UTC есть предпочтительная точка отсчета для указанного времени."

Если я попытаюсь разобрать его с помощью SimpleDateFormat и этот шаблон:

yyyy-MM-dd'T'HH:mm:ss

он будет разбираться как Пн апр 05 17: 16: 00 EDT 2010

SimpleDateFormat не может разобрать строку с этими шаблонами:

yyyy-MM-dd'T'HH:mm:ssz
yyyy-MM-dd'T'HH:mm:ssZ

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

12 66

12 ответов:

в шаблоне включение компонента даты-времени " z " указывает на то, что формат часового пояса должен соответствовать общий часовой пояс "стандарт", примерами которого являются Pacific Standard Time; PST; GMT-08:00.

A ' Z ' означает, что часовой пояс соответствует часовой пояс RFC 822 стандартные, например,-0800.

Я думаю, что вам нужен DatatypeConverter ...

@Test
public void testTimezoneIsGreenwichMeanTime() throws ParseException {
    final Calendar calendar = javax.xml.bind.DatatypeConverter.parseDateTime("2010-04-05T17:16:00Z");
    TestCase.assertEquals("gotten timezone", "GMT+00:00", calendar.getTimeZone().getID());
}

Java не анализирует даты ISO правильно.

похоже на ответ Маккензи.

просто исправить Z перед разбором.

код

String string = "2013-03-05T18:05:05.000Z";
String defaultTimezone = TimeZone.getDefault().getID();
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000"));

System.out.println("string: " + string);
System.out.println("defaultTimezone: " + defaultTimezone);
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date));

результат

string: 2013-03-05T18:05:05.000Z
defaultTimezone: America/New_York
date: 2013-03-05T13:05:05.000-0500

дата, которую вы анализируете, находится в формате ISO8601.

в java 7 шаблон для чтения и применения суффикса часового пояса должен читать yyyy-MM-dd'T'HH:mm:ssX

tl; dr

Instant.parse ( "2010-04-05T17:16:00Z" )

стандарт ИСО 8601

строка соответствует ISO 8601 стандарт (из которых упомянутый RFC 3339 профиль).

избегайте j.u. дата

java.утиль.Сроки и. Классы календаря в комплекте с Java, как известно, хлопотно. Избегать их.

вместо того, чтобы использовать Joda-Time библиотека или новая java.пакет времени в Java 8. Как использовать ISO 8601 как их значения по умолчанию для разбора и генерации строковых представлений значений даты-времени.

java.время

The java.время фреймворк встроен в Java 8 и позже вытесняет хлопотную старую java.утиль.Дата./Календарь занятий. Новые классы вдохновлены очень успешным Joda-Time фреймворк, задуманный как его преемник, похожий по концепции, но перестроенный. Определяется JSR 310. Продлен на ThreeTen-Extra. Смотрите учебник.

The Instant класс в java.время представляет собой момент на временной шкале в UTC часовой пояс.

The Z в конце вашей входной строки означает Zulu что означает UTC. Такая строка может быть непосредственно проанализирована с помощью Instant класс, без необходимости указывать форматер.

String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );

дамп в консоли.

System.out.println ( "instant: " + instant );

instant: 2010-04-05T17:16: 00Z

оттуда вы можете применить часовой пояс (ZoneId), чтобы отрегулировать этот Instant на ZonedDateTime. Поиск переполнения стека для обсуждения и примеров.

если вы должны использовать java.util.Date объект, который можно преобразовать, вызвав новые методы преобразования, добавленные к старым классам, таким как статический метод java.util.Date.from( Instant ).

java.util.Date date = java.util.Date.from( instant );

Joda Времени

пример в Joda-Time 2.5.

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );

преобразование в UTC.

DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );

конвертировать в java.утиль.Дата при необходимости.

java.util.Date date = dateTime.toDate();

согласно последней строке на дата и время модели таблица Java 7 API

X часовой пояс ISO 8601 часовой пояс -08; -0800; -08:00

для часового пояса ISO 8601 вы должны использовать X (-08 или Z); XX(-0800 или Z); и XXX(-08:00 или Z), чтобы разобрать ваш "2010-04-05T17:16:00Z" либо "гггг-ММ-ДД не 'чч:мм:набором" или "гггг-ММ-ДД не 'чч:мм:ssXX" или "гггг-ММ-ДД не 'чч:мм:ssXXX" должны работать.

    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z"));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z"));

правильно распечатает 'Пн апр 05 13: 16: 00 EDT 2010'

'X' работает только в том случае, если частичные секунды отсутствуют: т. е. SimpleDateFormat pattern of

"yyyy-MM-dd'T'HH: mm: ssX"

будет правильно разбирать

"2008-01-31T00:00:00Z"

но

" yyyy-MM-dd'T'HH:mm:ss.SX"

разбирать не буду

"2008-01-31T00: 00: 00.000 Z"

грустно, но правда, дата-время с частичными секундами не кажется действительной датой ISO: http://en.wikipedia.org/wiki/ISO_8601

часовой пояс должен быть чем - то вроде "GMT+00:00" или 0000 для того, чтобы быть правильно проанализированы SimpleDateFormat-вы можете заменить Z с этой конструкцией.

проект restlet включает класс InternetDateFormat, который может анализировать даты RFC 3339.

Restlet InternetDateFormat

хотя, вы можете просто заменить трейлинг ' Z ' на "UTC", прежде чем разбирать его.

Я даю еще один ответ, который я нашел api-client-library компания Google

try {
    DateTime dateTime = DateTime.parseRfc3339(date);
    dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault());
    long timestamp = dateTime.getValue();  // get date in timestamp
    int timeZone = dateTime.getTimeZoneShift();  // get timezone offset
} catch (NumberFormatException e) {
    e.printStackTrace();
}

установка guide,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download

вот API reference,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/DateTime

код DateTime Class,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

DateTime единица измерения tests,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java#L121

что касается JSR-310, то другим интересным проектом может быть threetenbp.

JSR-310 предоставляет новую библиотеку даты и времени для Java SE 8. Этот проект является обратным портом к Java SE 6 и 7.

в случае, если вы работаете на Android проект вы можете проверить библиотека ThreeTenABP.

compile "com.jakewharton.threetenabp:threetenabp:${version}"

JSR-310 был включен в Java 8 в качестве java.время.* пакет. Это полная замена для больных API даты и календаря как в Java, так и в Android. JSR-310 был возвращен на Java 6 его создателем, Стивеном Колборном, из которого эта библиотека адаптирована.

в Java 8 используйте предопределенный DateTimeFormatter.ISO_DATE_TIME

 DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
 ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);

Я думаю, это самый простой способ

Так как java 8 просто использовать ZonedDateTime.parse("2010-04-05T17:16:00Z")