дата синтаксического анализа simpledateformat с литералом 'Z' [дубликат]
-
24-09-2019 - |
Вопрос
На этот вопрос уже есть ответ здесь:
Я пытаюсь проанализировать дату, которая выглядит так:
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")