Я пытаюсь преобразовать строку формата 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" ) ;
Для меня это приятно.
Ответы:
К сожалению, форматы часового пояса, доступные для SimpleDateFormat (Java 6 и более ранние версии ), не соответствуют стандарту ISO 8601 . SimpleDateFormat понимает строки часового пояса, такие как «GMT + 01: 00» или «+0100», последний в соответствии с RFC # 822 .
Даже если в Java 7 добавлена поддержка дескрипторов часовых поясов в соответствии с ISO 8601, SimpleDateFormat по-прежнему не может правильно проанализировать полную строку даты, поскольку не поддерживает дополнительные части.
Переформатирование вашей входной строки с помощью регулярных выражений, безусловно, является одной из возможностей, но правила замены не так просты, как в вашем вопросе:
Возможно, более простым решением является использование конвертера типов данных в JAXB, поскольку JAXB должен иметь возможность анализировать строку даты ISO8601 в соответствии со спецификацией схемы XML.
javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
даст вамCalendar
объект, и вы можете просто использовать getTime () на нем, если вам нуженDate
объект.Вы могли бы также использовать Joda-Time , но я не знаю, почему вы должны беспокоиться об этом.
источник
Способ, которым благословляет документация Java 7 :
Вы можете найти больше примеров в разделе Примеры в javadoc SimpleDateFormat .
UPD 02/13/2020: Существует совершенно новый способ сделать это в Java 8
источник
java.time
фреймворк в Java 8, вдохновленный Joda-Time , заменив хлопотные классы java.util.Date, .Calendar и SimpleDateFormat.string1
и ,string2
но не знаете , какой вы получите.Хорошо, на этот вопрос уже дан ответ, но я все равно оставлю свой ответ. Это может кому-то помочь.
Я искал решение для Android (API 7).
javax.xml
не будут работать на Android API 7.Закончилась реализация этого простого класса. Он охватывает только наиболее распространенную форму строк ISO 8601, но этого должно быть достаточно в некоторых случаях (когда вы совершенно уверены, что ввод будет в этом формате).
Примечание по производительности: каждый раз я создаю новый экземпляр SimpleDateFormat, чтобы избежать ошибок в Android 2.1. Если вы так же удивлены, как и я, посмотрите эту загадку . Для других движков Java вы можете кэшировать экземпляр в закрытом статическом поле (используя ThreadLocal, чтобы обеспечить безопасность потоков).
источник
s = s.substring(0, 22) + s.substring(23);
- я не вижу смысла в этомjava.time
Java.time API (встроенные в Java 8 и более поздних версий), делает это немного легче.
Если вы знаете, что ввод в UTC , например
Z
(для зулу) на конце,Instant
класс может выполнить синтаксический анализ.Если ваши входные данные могут быть другими значениями смещения от UTC, а не UTC, указанными
Z
(Zulu) на конце, используйтеOffsetDateTime
класс для анализа.Затем извлеките
Instant
и преобразуйте вjava.util.Date
, вызвавfrom
.источник
LocalDateTime
иZoneId
иatZone
. Этот простой однострочник сделает:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Date.from(Instant.parse("2014-12-12T10:39:40Z" ));
достаточно.OffsetDateTime
было бы достаточно проанализировать ISO8601 (который не содержит информацию о часовом поясе, а только смещение).Instant
что позволил сделать анализ. Хотя этого конкретного вопроса недостаточно, на него следует обратить внимание. Поэтому я добавил второй пример кода. К сожалению, только что заметил, что это не мой ответ; Я надеюсь, что Адам одобряет.Библиотека Jackson-databind также имеет класс ISO8601DateFormat, который это делает (фактическая реализация в ISO8601Utils .
источник
2015-08-11T13:10:00
. Я получаюString index out of range: 19
. Глядя на код, кажется, что он требует указания миллисекунд и часового пояса. Это должно быть необязательно.[yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]
. Другими словами, миллисекунды необязательны, но часовой пояс является обязательным.new DateTime("2015-08-11T13:10:00").toDate()
ТЛ; др
Использование java.time
Новый пакет java.time в Java 8 и более поздних версиях был вдохновлен Joda-Time.
OffsetDateTime
Класс представляет момент на временной шкале с офсетной из-UTC , но не часовой пояс.При вызове
toString
генерируется строка в стандартном формате ISO 8601:Чтобы увидеть то же значение через объектив UTC, извлеките
Instant
или отрегулируйте смещение от+01:00
до00:00
.…или…
При необходимости настройте часовой пояс. Временная зона представляет собой историю офсетных из-UTC значений для региона, с набором правил для обработки аномалий , таких как летнее время (DST). Поэтому применяйте часовой пояс, а не просто смещение, когда это возможно.
О java.time
Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как
java.util.Date
,Calendar
, иSimpleDateFormat
.Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, смотрите Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии . Нет необходимости в строках, нет необходимости в
java.sql.*
классах.Где взять классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как
Interval
,YearWeek
,YearQuarter
, и более .источник
Для Java версии 7
Вы можете следить за документацией Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html.
X - используется для часового пояса ISO 8601
источник
Решение DatatypeConverter работает не на всех виртуальных машинах. Следующие работы для меня:
Я обнаружил, что joda не работает «из коробки» (специально для приведенного выше примера с часовым поясом на дату, которая должна быть действительной)
источник
Я думаю, что мы должны использовать
для даты
2010-01-01T12:00:00Z
источник
Начиная с Java 8, есть совершенно новый официально поддерживаемый способ сделать это:
источник
Z
смещением, нам не нужно указывать это явно. ПростоInstant i = Instant.parse(s);
. Строка в вопросе имела+01:00
, в этом случаеDateTimeFormatter.ISO_INSTANT
не работает (по крайней мере, на моем Java 11).ISO_OFFSET_DATE_TIME
для форматирования даты со смещением, например+01:00
( docs.oracle.com/javase/8/docs/api/java/time/format/… )Другой очень простой способ анализа меток времени ISO8601 - это использовать
org.apache.commons.lang.time.DateUtils
:источник
java.time
Обратите внимание, что в Java 8 вы можете использовать класс java.time.ZonedDateTime и его статический
parse(CharSequence text)
метод.источник
Instant
иZonedDateTime
уместно здесь, а неZonedDateTime
.Обходной путь для 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
.Приведенный выше метод для замены [
Z
with+0000
] или [+01:00
with+0100
] при возникновении ошибки в Java 6 (вы можете определить версию Java и заменить try / catch на оператор if).источник
Date
иSimpleDateFormat
плохо спроектированные, запутанные и ошибочные. Теперь они унаследованы, заменены классами java.time, встроенными в Java 8 и более поздние версии. Для Java 6 и Java 7 большая часть функциональности java.time перенесена в проект ThreeTen-Backport . Гораздо лучше добавить эту библиотеку в ваше приложение, чем использовать эти унаследованные классы. Однострочное решение в java.time:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Я столкнулся с той же проблемой и решил ее с помощью следующего кода.
Раньше я пользовалась
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());
Это работало нормально для меня.
источник
Также вы можете использовать следующий класс -
Ссылка на Java Doc - иерархия для пакета org.springframework.extensions.surf.maven.plugin.util
источник
У Java есть дюжина различных способов разбора даты и времени, как показывают отличные ответы. Но что удивительно, ни один из временных классов Java полностью не реализует ISO 8601!
С Java 8 я бы порекомендовал:
Это будет обрабатывать примеры как в 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/ I'm не знаю ни одного класса Java, который мог бы справиться со всеми из них.
источник
OffsetDateTime
будет делать и концептуально соответствует дате и времени смещением лучше.OffsetDateTime
обрабатывает примеры, с которыми вы работаетеZonedDateTime
. Я полагаю, что это не обрабатывает ни один из примеров, которыеZonedDateTime
не делают. В этом смысле это не улучшение (но и не хуже). Извините, я не совсем ясноApache Jackrabbit использует формат ISO 8601 для сохранения дат, и для их анализа существует вспомогательный класс:
org.apache.jackrabbit.util.ISO8601
Поставляется с jackrabbit-jcr-commons .
источник
Как уже упоминалось, Android не имеет хорошего способа поддержки анализа / форматирования дат ISO 8601 с использованием классов, включенных в SDK. Я написал этот код несколько раз, поэтому я наконец создал Gist, включающий класс DateUtils, который поддерживает форматирование и анализ дат ISO 8601 и RFC 1123. Gist также включает в себя тестовый пример, показывающий, что он поддерживает.
https://gist.github.com/mraccola/702330625fad8eebe7d3
источник
SimpleDateFormat для JAVA 1.7 имеет классный шаблон для формата ISO 8601.
Класс SimpleDateFormat
Вот что я сделал:
источник
Z
в строке формата не часовой пояс ISO 8601, вы должны использоватьX
(илиXX
илиXXX
), если вы хотите часовой пояс ISO 8601Делай это так:
Вот вывод:
Ср. 19 октября 15:15:36 CST 2016
источник
Используйте строку как
LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
источник
Я удивлен, что ни одна библиотека java не поддерживает все форматы даты ISO 8601 согласно https://en.wikipedia.org/wiki/ISO_8601 . Joda DateTime поддерживала большинство из них, но не все, и поэтому я добавил собственную логику для обработки всех из них. Вот моя реализация.
источник
Небольшой тест, который показывает, как анализировать дату в ISO8601 и что LocalDateTime не обрабатывает DST.
источник
java.util.Date
,java.util.Calendar
иjava.text.SimpleDateFormat
теперь унаследованные , вытеснены классами java.time, встроенными в Java 8 и более поздние версии . Смотрите Учебник по Oracle .LocalDateTime
не обрабатывает летнее время (DST), поскольку он вообще не обрабатывает часовой пояс. Для этого нам нужноZonedDateTime
. ПредложениеDate
иSimpleDateFormat
есть - ИМХО плохо.У меня была похожая потребность: мне нужно было иметь возможность анализировать любую дату, соответствующую стандарту ISO8601, не зная заранее точного формата, и я хотел легкое решение, которое также будет работать на Android.
Когда я погуглил свои потребности, я наткнулся на этот вопрос и заметил, что AFAIU, ни один ответ полностью не отвечает моим потребностям. Поэтому я разработал jISO8601 и поместил его в Maven Central .
Просто добавьте в вас
pom.xml
:и тогда тебе хорошо идти
Надеется, что это поможет.
источник
Чтобы просто отформатировать такую дату, у меня в приложении на основе Java 6 работало следующее. В проекте thymeleaf есть
DateFormat
класс,JacksonThymeleafISO8601DateFormat
который вставляет пропущенную двоеточие:https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java
Я использовал его для совместимости формата даты ECMAScript.
источник
Базовая функция Предоставлено: @wrygiel.
Эта функция может конвертировать формат ISO8601 в Java Date, который может обрабатывать значения смещения. Согласно определению ISO 8601 смещение может быть упомянуто в разных форматах.
Этот класс имеет статические методы для преобразования
Образец строки ISO8601
}
источник
Казалось, это работает лучше всего для меня:
Мне нужно было конвертировать в / из JavaScript строки даты в Java. Я нашел выше работы с рекомендацией. Было несколько примеров использования SimpleDateFormat, которые были близки, но они, казалось, не были подмножеством, как рекомендовано:
http://www.w3.org/TR/NOTE-datetime
и поддерживаются PLIST и JavaScript Strings, и вот что мне нужно.
Похоже, что это наиболее распространенная форма строки ISO8601 и хорошее подмножество.
Примеры, которые они приводят:
У меня также есть быстрая версия:
...
Я не проверял это, но, думаю, это будет довольно быстро. Вроде работает. :)
источник
Я думаю, что многие люди хотят разбирать строки дат JSON. Если вы зайдете на эту страницу, есть большая вероятность, что вы захотите преобразовать дату JSON JavaScript в дату Java.
Чтобы показать, как выглядит строка даты JSON:
Строка даты JSON: 2013-12-14T01: 55: 33.412Z.
Даты не охватываются спецификацией JSON, но выше приведен очень специфический формат ISO 8601, тогда как ISO_8601 намного больше, и это просто подмножество, хотя и очень важное.
См. Http://www.json.org. См. Http://en.wikipedia.org/wiki/ISO_8601. См. Http://www.w3.org/TR/NOTE-datetime.
Так получилось, что я написал анализатор JSON и анализатор PLIST, которые используют ISO-8601, но не одинаковые биты.
Я написал два способа сделать это для моего проекта. Один стандарт, один быстрый.
Опять же, строка даты JSON является очень специфической реализацией ISO 8601 ....
(Я разместил другой в другом ответе, который должен работать для дат PLIST, которые являются другим форматом ISO 8601).
Дата JSON выглядит следующим образом:
Файлы PLIST (ASCII не GNUNext) также используют ISO 8601, но без миллисекунд, поэтому ... не все даты ISO-8601 одинаковы. (По крайней мере, я еще не нашел тот, который использует milis, и анализатор, который я видел, пропускает часовой пояс вообще OMG).
Теперь о быстрой версии (вы можете найти ее в Boon).
Обратите внимание, что Reflection.toCharArray использует unsafe, если доступно, но по умолчанию - string.toCharArray, если нет.
(Вы можете взять его из примера, заменив Reflection.toCharArray (string) на string.toCharArray ()).
IsJsonDate реализован следующим образом:
В любом случае ... я предполагаю, что довольно много людей, которые приходят сюда ... могут искать строку даты JSON, и хотя это дата ISO-8601, она очень специфическая и требует очень специфического анализа.
Смотрите https://github.com/RichardHightower/boon Boon есть анализатор PLIST (ASCII) и анализатор JSON.
Парсер JSON - самый быстрый из всех известных мне парсеров JSON.
Независимо проверено парнями Gatling Performance.
https://github.com/gatling/json-parsers-benchmark
Он имеет самый быстрый анализатор JSON для потоков, считывателей, bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) и String.
Смотрите другие тесты на:
https://github.com/RichardHightower/json-parsers-benchmark
источник
Instant.parse( "2013-12-14T01:55:33.412Z" )