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
Я могу явно установить TimeZone для использования в SimpleDateFormat для получения ожидаемого результата, но я не думаю, что это необходимо. Есть что-то, чего я не хватает? Есть ли альтернативный синтаксический анализатор даты?
Ответы
Ответ 1
В шаблоне включение компонента времени "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());
}
Ответ 2
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
Ответ 3
Дата разбора в формате ISO8601.
В java 7 шаблон для чтения и применения суффикса часового пояса должен читать yyyy-MM-dd'T'HH:mm:ssX
Ответ 4
TL;DR
Instant.parse ( "2010-04-05T17:16:00Z" )
Стандарт ISO 8601
Ваша строка соответствует стандарту ISO 8601 (из которых упомянутый RFC 3339 является профилем).
Избегайте j.u.Date
Классы java.util.Date и .Calendar в комплекте с Java, как известно, являются неприятными. Избегайте их.
Вместо этого используйте либо библиотеку Joda-Time, либо новый пакет java.time в Java 8. Оба используют ISO 8601 в качестве значений по умолчанию для синтаксического анализа и генерации строковых представлений значений даты и времени.
java.time
Структура java.time, встроенная в Java 8 и более поздняя версия, вытесняет неприятные старые классы java.util.Date/.Calendar. Новые классы вдохновлены очень успешной структурой Joda-Time, предназначенной в качестве ее преемника, аналогичной по своей концепции, но переориентированной. Определено JSR 310. Расширено в проекте ThreeTen-Extra. См. Tutorial.
Класс Instant
в java.time представляет момент на временной шкале в часовой пояс UTC.
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.util.Date.
java.util.Date date = dateTime.toDate();
Ответ 5
В соответствии с последней строкой в таблице шаблонов даты и времени API Java 7
X Часовой пояс ISO 8601 часовой пояс -08; -08 00; -08: 00
Для часового пояса ISO 8601 вы должны использовать:
- Х для (-08 или Z),
- XX для (-08 00 или 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"));
правильно распечатает "Пн Апр 05 13:16:00 ПО ВОСТОЧНОМУ ВРЕМЕНИ 2010"
Ответ 6
"X" работает только в том случае, если частичных секунд нет: например, шаблон SimpleDateFormat
"YYYY-MM-dd'T'HH: мм: SSX"
Будет правильно разбираться
"2008-01-31T00: 00: 00Z"
но
"YYYY-MM-dd'T'HH: мм: ss.SX"
НЕ будет анализировать
"2008-01-31T00: 00: 00.000Z"
Грустно, но верно, дата-время с частичными секундами не является действительной датой ISO: http://en.wikipedia.org/wiki/ISO_8601
Ответ 7
Часовой пояс должен быть чем-то вроде "GMT + 00: 00" или 0000, чтобы правильно разбираться с SimpleDateFormat - вы можете заменить Z этой конструкцией.
Ответ 8
Проект restlet включает класс InternetDateFormat, который может анализировать даты RFC 3339.
Restlet InternetDateFormat
Хотя вы можете просто заменить конечную "Z" на "UTC" перед ее анализом.
Ответ 9
Я предоставляю другой ответ, который я нашел 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
Ответ 10
Что касается JSR-310, то другой интересный проект может быть threetenbp.
JSR-310 предоставляет новую библиотеку даты и времени для Java SE 8. Этот проект является backport для Java SE 6 и 7.
Если вы работаете над проектом Android, вы можете проверить библиотеку ThreeTenABP.
compile "com.jakewharton.threetenabp:threetenabp:${version}"
JSR-310 был включен в Java 8 как пакет java.time. *. Это полная замена для опасных API дат и календаря как на Java, так и на Android. JSR-310 был передан на Java 6 его создателем, Стивеном Коулборном, из которого адаптирована эта библиотека.
Ответ 11
В Java 8 используйте предопределенный DateTimeFormatter.ISO_DATE_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);
Я думаю, что это самый простой способ
Ответ 12
Так как java 8 просто использует ZonedDateTime.parse("2010-04-05T17:16:00Z")