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

StackOverflow https://stackoverflow.com/questions/2580925

Вопрос

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

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

2010-04-05T17:16:00Z

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

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

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

Он будет проанализирован как понедельник 5 апреля 17:16:00 по восточному времени 2010 г.

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

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

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

Это было полезно?

Решение

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

Буква «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

вр; доктор

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

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

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

Избегайте j.u.Date

Классы java.util.Date и .Calendar, поставляемые в комплекте с Java, общеизвестно неприятны.Избежать их.

Вместо этого используйте либо Джода-Время библиотеку или новый пакет java.time в Java 8.Оба используют ISO 8601 по умолчанию для анализа и создания строковых представлений значений даты и времени.

java.time

А java.time Framework, встроенный в Java 8 и более поздние версии, заменяет неприятные старые классы java.util.Date/.Calendar.Новые классы вдохновлены весьма успешным Джода-Время Framework, задуманный как его преемник, схожий по концепции, но с переработанной архитектурой.Определяется ДжСР 310.Расширено ТриДесять-Экстра проект.См. Руководство.

А Instant класс в java.time представляет момент на временной шкале в универсальное глобальное время часовой пояс.

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

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

Дамп на консоль.

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

мгновенный:2010-04-05T17:16:00З

Оттуда вы можете применить часовой пояс (ZoneId), чтобы настроить это Instant в ZonedDateTime.Найдите в Stack Overflow обсуждение и примеры.

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

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

Джода-Время

Пример в 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.util.Date.

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

Судя по последней строке Шаблоны даты и времени стол API Java 7

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

Для часового пояса ISO 8601 вы должны использовать:

  • X для (-08 или Z),
  • XX для (-0800 или Z),
  • XXX для (-08:00 или Z);

поэтому для анализа вашего "2010-04-05T17:16:00Z" вы можете использовать либо «гггг-ММ-дд'Т'ЧЧ:мм:ссХ» или «гггг-ММ-дд'Т'ЧЧ:мм:ссХХ» или «гггг-ММ-дд'Т'ЧЧ:мм:ссХХХ» .

    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"));

правильно распечатает «Пн, 5 апреля, 13:16:00 по восточному времени 2010 г.»

«X» работает только в том случае, если неполные секунды отсутствуют:то естьШаблон SimpleDateFormat

"гггг-ММ-дд'Т'ЧЧ:мм:ссХ"

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

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

но

"гггг-ММ-дд'Т'ЧЧ:мм:сс.SX"

НЕ буду анализировать

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

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

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

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

Рестлет ИнтернетДатаФормат

Хотя, возможно, вы просто захотите заменить завершающую букву «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();
}

Инструкция по установке,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download

Вот ссылка на API,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/DateTime

Исходный код DateTime Сорт,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

DateTime модульные тесты,
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, то может быть интересен еще один проект. тридесять пунктов.

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

В случае, если вы работаете над Андроид проект, который вы, возможно, захотите проверить Библиотека ThreeTenABP.

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

JSR-310 был включен в Java 8 как пакет java.time.*.Это полная замена устаревших API-интерфейсов Date и Calendar как в 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")

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top