Преобразование строки, соответствующей ISO 8601, в java.util.Date

668

Я пытаюсь преобразовать строку формата 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" ) ;

Для меня это приятно.

Ice09
источник
243
Будьте готовы получить много ответов "Use JodaTime" ...
JuanZe
3
@ Ice09: Если документация API для DateTimeFormat верна (хотя документация JoDa может вводить в заблуждение, быть неправильной или неполной), шаблон, который вы использовали в своем собственном «ответе», не совместим с ISO8601.
jarnbjo
21
Я не уверен, когда это было добавлено, но «X», кажется, решает эту проблему в SimpleDateFormat. Шаблон "гггг-ММ-дд'ТХЧ: мм: ссХ" успешно анализирует пример в вопросе.
Млохбихлер
12
'X' доступен с Java 7.
Ларс Грэммель
3
Java 8 делает это легко! В ответах ниже есть скрытый драгоценный камень Адама: stackoverflow.com/a/27479533/1262901
Фабиан Келлер,

Ответы:

477

К сожалению, форматы часового пояса, доступные для SimpleDateFormat (Java 6 и более ранние версии ), не соответствуют стандарту ISO 8601 . SimpleDateFormat понимает строки часового пояса, такие как «GMT + 01: 00» или «+0100», последний в соответствии с RFC # 822 .

Даже если в Java 7 добавлена ​​поддержка дескрипторов часовых поясов в соответствии с ISO 8601, SimpleDateFormat по-прежнему не может правильно проанализировать полную строку даты, поскольку не поддерживает дополнительные части.

Переформатирование вашей входной строки с помощью регулярных выражений, безусловно, является одной из возможностей, но правила замены не так просты, как в вашем вопросе:

  • Некоторые часовые пояса не являются полными часами вне UTC , поэтому строка не обязательно заканчивается на «: 00».
  • ISO8601 позволяет включать только количество часов в часовой пояс, поэтому «+01» эквивалентно «+01: 00»
  • ISO8601 позволяет использовать «Z» для обозначения UTC вместо «+00: 00».

Возможно, более простым решением является использование конвертера типов данных в JAXB, поскольку JAXB должен иметь возможность анализировать строку даты ISO8601 в соответствии со спецификацией схемы XML. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")даст вам Calendarобъект, и вы можете просто использовать getTime () на нем, если вам нужен Dateобъект.

Вы могли бы также использовать Joda-Time , но я не знаю, почему вы должны беспокоиться об этом.

jarnbjo
источник
18
JAXB-решение - это действительно креативный подход! Это работает также, я проверил это с моим образцом. Тем не менее, для тех, кто сталкивается с проблемой и имеет право использовать JodaTime, я бы посоветовал использовать ее, так как она кажется более естественной. Но ваше решение не требует дополнительных библиотек (по крайней мере, с Java 6).
Ice09
36
Вот обратное: Календарь c = GregorianCalendar.getInstance (); c.setTime (aDate); return javax.xml.bind.DatatypeConverter.printDateTime (c);
Александр Юнгберг
4
На самом деле это не так просто, потому что вы должны инициализировать jaxb datatypeConverter. В итоге я сам использовал DatatypeFactory, как DataTypeConverterImpl для себя. Что за головная боль
gtrak
3
@ Симон: Нет, часовые пояса, конечно, не игнорируются. Вы должны делать что-то не так. Если вы введете более нескольких символов и расскажете нам, что вы на самом деле делаете, кто-то может объяснить вам, что именно.
Джарнбджо
4
@jarnbjo Вы первый и единственный человек, с которым я столкнулся, который предпочитает стандартные, до 1.8, классы java date, а не joda-time. Я считаю, что joda-time - это буквальная радость, особенно по сравнению со стандартным API, который является мерзостью.
НимЧимпский
245

Способ, которым благословляет документация Java 7 :

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String string1 = "2001-07-04T12:08:56.235-0700";
Date result1 = df1.parse(string1);

DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String string2 = "2001-07-04T12:08:56.235-07:00";
Date result2 = df2.parse(string2);

Вы можете найти больше примеров в разделе Примеры в javadoc SimpleDateFormat .

UPD 02/13/2020: Существует совершенно новый способ сделать это в Java 8

Антонио
источник
7
Ваш ответ помог мне преобразовать ISODate MongoDB в локальную дату. С уважением.
Голубое небо,
9
@ b.long Java добавила более чем константу для таких форматов, соответствующих ISO 8601. Java получила совершенно новую платформу для работы с датой и временем, которая включает встроенную поддержку по умолчанию для таких форматов. Посмотрите на новый java.timeфреймворк в Java 8, вдохновленный Joda-Time , заменив хлопотные классы java.util.Date, .Calendar и SimpleDateFormat.
Василий Бурк
2
Разве это не значит, что вам нужно знать формат даты заранее? Что делать , если вы должны принять string1и , string2но не знаете , какой вы получите.
Тимммм
16
'Z' должен быть в кавычках
кервин
7
@kervin Если Z в кавычках, не будет ли средство форматирования искать именно символ Z, а не все строки смещения, которые он может представлять? Кажется, что цитирование Z сработало бы только по совпадению, если бы ваши строки дат были в UTC.
spaaarky21
201

Хорошо, на этот вопрос уже дан ответ, но я все равно оставлю свой ответ. Это может кому-то помочь.

Я искал решение для Android (API 7).

  • Йода не могла быть и речи - она ​​огромна и страдает от медленной инициализации. Это также казалось большим излишним для этой конкретной цели.
  • Ответы с участием javax.xmlне будут работать на Android API 7.

Закончилась реализация этого простого класса. Он охватывает только наиболее распространенную форму строк ISO 8601, но этого должно быть достаточно в некоторых случаях (когда вы совершенно уверены, что ввод будет в этом формате).

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Helper class for handling a most common subset of ISO 8601 strings
 * (in the following format: "2008-03-01T13:00:00+01:00"). It supports
 * parsing the "Z" timezone, but many other less-used features are
 * missing.
 */
public final class ISO8601 {
    /** Transform Calendar to ISO 8601 string. */
    public static String fromCalendar(final Calendar calendar) {
        Date date = calendar.getTime();
        String formatted = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .format(date);
        return formatted.substring(0, 22) + ":" + formatted.substring(22);
    }

    /** Get current date and time formatted as ISO 8601 string. */
    public static String now() {
        return fromCalendar(GregorianCalendar.getInstance());
    }

    /** Transform ISO 8601 string to Calendar. */
    public static Calendar toCalendar(final String iso8601string)
            throws ParseException {
        Calendar calendar = GregorianCalendar.getInstance();
        String s = iso8601string.replace("Z", "+00:00");
        try {
            s = s.substring(0, 22) + s.substring(23);  // to get rid of the ":"
        } catch (IndexOutOfBoundsException e) {
            throw new ParseException("Invalid length", 0);
        }
        Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
        calendar.setTime(date);
        return calendar;
    }
}

Примечание по производительности: каждый раз я создаю новый экземпляр SimpleDateFormat, чтобы избежать ошибок в Android 2.1. Если вы так же удивлены, как и я, посмотрите эту загадку . Для других движков Java вы можете кэшировать экземпляр в закрытом статическом поле (используя ThreadLocal, чтобы обеспечить безопасность потоков).

wrygiel
источник
2
Возможно, это должно было быть превращено в собственный вопрос с его собственным ответом?
Thorbear
5
Это была первая страница, на которую я наткнулся, когда искал ответ, поэтому он показался мне подходящим. Для большинства разработчиков Java Android не совсем Java. Однако в большинстве случаев один работает так же, как другой, поэтому многие разработчики Android будут искать «java» при поиске.
Вригиэль
1
Обратите внимание, что это не учитывает разрешение в миллисекундах. Это легко добавить.
Скай Келси
6
Мне пришлось добавить .SSS за доли секунды, но работает отлично, спасибо. Почему вы делаете s = s.substring(0, 22) + s.substring(23);- я не вижу смысла в этом
Дори
1
input = input.replaceAll ("[Zz]", "+0000"); тоже будет работать и операции с подстрокой можно избежать.
Javanator
115

java.time

Java.time API (встроенные в Java 8 и более поздних версий), делает это немного легче.

Если вы знаете, что ввод в UTC , например Z(для зулу) на конце, Instantкласс может выполнить синтаксический анализ.

java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));

Если ваши входные данные могут быть другими значениями смещения от UTC, а не UTC, указанными Z(Zulu) на конце, используйте OffsetDateTimeкласс для анализа.

OffsetDateTime odt = OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" );

Затем извлеките Instantи преобразуйте в java.util.Date, вызвав from.

Instant instant = odt.toInstant();  // Instant is always in UTC.
java.util.Date date = java.util.Date.from( instant );
Адам
источник
8
Этот ответ работает слишком усердно. Java.util.Date по определению не имеет часового пояса. Так что нет необходимости во всем, что связано с часовым поясом: LocalDateTimeи ZoneIdи atZone. Этот простой однострочник сделает:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Василий Бурк
5
@BasilBourque Это излишне сложно: Date.from(Instant.parse("2014-12-12T10:39:40Z" ));достаточно.
assylias
3
@assylias, вы правы, но это будет работать только тогда, когда строка даты является зоной UTC, ISO8601 допускает любой часовой пояс ...
Адам
2
@ Adam Мой плохой - я не понял, вопрос был более общим, чем ваш пример. В качестве дополнительного комментария OffsetDateTimeбыло бы достаточно проанализировать ISO8601 (который не содержит информацию о часовом поясе, а только смещение).
assylias
1
@assylias Спасибо за ваш комментарий о том, Instantчто позволил сделать анализ. Хотя этого конкретного вопроса недостаточно, на него следует обратить внимание. Поэтому я добавил второй пример кода. К сожалению, только что заметил, что это не мой ответ; Я надеюсь, что Адам одобряет.
Василий Бурк
67

Библиотека Jackson-databind также имеет класс ISO8601DateFormat, который это делает (фактическая реализация в ISO8601Utils .

ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");
david_p
источник
Не удается разобрать эту дату 2015-08-11T13:10:00. Я получаю String index out of range: 19. Глядя на код, кажется, что он требует указания миллисекунд и часового пояса. Это должно быть необязательно.
Тимммм
2
Процитируем документацию, разбора формат: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]. Другими словами, миллисекунды необязательны, но часовой пояс является обязательным.
david_p
2
Ах да, на самом деле, похоже, ты прав. Тем не менее, я почти уверен, что ISO8601 позволяет вам опустить часовой пояс, поэтому он все еще не прав. JodaTime работает, хотя:new DateTime("2015-08-11T13:10:00").toDate()
Timmmm
3
Этот класс устарел, новый - StdDateFormat. В противном случае это работает так же.
JohnEye
51

ТЛ; др

OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" )

Использование java.time

Новый пакет java.time в Java 8 и более поздних версиях был вдохновлен Joda-Time.

OffsetDateTimeКласс представляет момент на временной шкале с офсетной из-UTC , но не часовой пояс.

OffsetDateTime odt = OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" );

При вызове toStringгенерируется строка в стандартном формате ISO 8601:

2010-01-01T12: 00 + 01: 00

Чтобы увидеть то же значение через объектив UTC, извлеките Instantили отрегулируйте смещение от +01:00до 00:00.

Instant instant = odt.toInstant();  

…или…

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC );

При необходимости настройте часовой пояс. Временная зона представляет собой историю офсетных из-UTC значений для региона, с набором правил для обработки аномалий , таких как летнее время (DST). Поэтому применяйте часовой пояс, а не просто смещение, когда это возможно.

ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of( "America/Montreal" ) );

О 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?

  • Java SE 8 , Java SE 9 , Java SE 10 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API с комплексной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP… .

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .


Базилик Бурк
источник
27

Для Java версии 7

Вы можете следить за документацией Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html.

X - используется для часового пояса ISO 8601

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

System.out.println(nowAsISO);

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);

System.out.println(finalResult);
d.danailov
источник
Это означает, что требуется часовой пояс . Согласно ISO 8601 это необязательно. Как и секунды, и т. Д. Так что это только анализирует определенное подмножество ISO 8601.
Timmmm
1
Прекрасно работает с Java 1.8
Тьяго Перейра
20

Решение DatatypeConverter работает не на всех виртуальных машинах. Следующие работы для меня:

javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()

Я обнаружил, что joda не работает «из коробки» (специально для приведенного выше примера с часовым поясом на дату, которая должна быть действительной)

Джеймс Скривен
источник
15

Я думаю, что мы должны использовать

DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")

для даты 2010-01-01T12:00:00Z

Тоби
источник
5
Почему это лучший ответ, чем другие, включая принятый ответ с 76 голосами против?
Эрик Робертсон
3
@ErickRobertson: Это просто, из коробки, гибкий, без конверсий, и большинство людей не заботятся о часовых поясах.
TWiStErRob
7
Не стоит много работать со временем, если вам нет дела до часовых поясов!
Дори
16
Это игнорирует часовой пояс полностью. Использовал это, пока я не понял, что это происходит, поэтому я переключился на JodaTime.
Джошуа Пинтер
3
Выбрасывание часового пояса просто приведет к ошибкам в какой-то момент.
Барт ван Куйк
11

Начиная с Java 8, есть совершенно новый официально поддерживаемый способ сделать это:

    String s = "2020-02-13T18:51:09.840Z";
    TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse(s);
    Instant i = Instant.from(ta);
    Date d = Date.from(i);
Антонио
источник
2
Если строка в мгновенном формате, с конечным Zсмещением, нам не нужно указывать это явно. Просто Instant i = Instant.parse(s);. Строка в вопросе имела +01:00, в этом случае DateTimeFormatter.ISO_INSTANTне работает (по крайней мере, на моем Java 11).
Оле В.В.
3
@ OleV.V. Вы можете использовать ISO_OFFSET_DATE_TIMEдля форматирования даты со смещением, например +01:00( docs.oracle.com/javase/8/docs/api/java/time/format/… )
Лукас Баскеротто
1
Это правда, @LucasBasquerotto. Хотя в ответах Адама и Бэзила Бурка явно не упоминается этот форматер, они уже делают нечто подобное.
Оле В.В.
Это не может проанализировать "2020-06-01T14: 34: 00-05: 00", который является строкой, созданной методом toISOString () Javascript.
Хосе Солорзано
10

Другой очень простой способ анализа меток времени ISO8601 - это использовать org.apache.commons.lang.time.DateUtils:

import static org.junit.Assert.assertEquals;

import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;

public class ISO8601TimestampFormatTest {
  @Test
  public void parse() throws ParseException {
    Date date = DateUtils.parseDate("2010-01-01T12:00:00+01:00", new String[]{ "yyyy-MM-dd'T'HH:mm:ssZZ" });
    assertEquals("Fri Jan 01 12:00:00 CET 2010", date.toString());
  }
}
tmandry
источник
6

java.time

Обратите внимание, что в Java 8 вы можете использовать класс java.time.ZonedDateTime и его статический parse(CharSequence text)метод.

Мартин Руст
источник
Входные строки в Вопросе имеют только смещение от UTC, а не полный часовой пояс. Так Instantи ZonedDateTimeуместно здесь, а не ZonedDateTime.
Василий Бурк
6

Обходной путь для 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.

public static Date iso8601Format(String formattedDate) throws ParseException {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
        return df.parse(formattedDate);
    } catch (IllegalArgumentException ex) {
        // error happen in Java 6: Unknown pattern character 'X'
        if (formattedDate.endsWith("Z")) formattedDate = formattedDate.replace("Z", "+0000");
        else formattedDate = formattedDate.replaceAll("([+-]\\d\\d):(\\d\\d)\\s*$", "$1$2");
        DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
        return df1.parse(formattedDate);
    }
}

Приведенный выше метод для замены [ Zwith +0000] или [ +01:00with +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" )
Василий Бурк
5

Я столкнулся с той же проблемой и решил ее с помощью следующего кода.

 public static Calendar getCalendarFromISO(String datestring) {
    Calendar calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()) ;
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
    try {
        Date date = dateformat.parse(datestring);
        date.setHours(date.getHours() - 1);
        calendar.setTime(date);

        String test = dateformat.format(calendar.getTime());
        Log.e("TEST_TIME", test);

    } catch (ParseException e) {
        e.printStackTrace();
    }

    return calendar;
}

Раньше я пользовалась 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());

Это работало нормально для меня.

Абхай Кумар
источник
Как раз то, что мне нужно, без необходимости использовать joda-time, XML API или что-то еще. Просто правильный шаблон.
Филипп Джозеффи
4

У Java есть дюжина различных способов разбора даты и времени, как показывают отличные ответы. Но что удивительно, ни один из временных классов Java полностью не реализует ISO 8601!

С Java 8 я бы порекомендовал:

ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());

Это будет обрабатывать примеры как в 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будет делать и концептуально соответствует дате и времени смещением лучше.
Оле В.В.
Привет @ OleV.V. спасибо за предложение. К сожалению нет: OffsetDateTime.parse () сгенерирует исключение для нескольких допустимых строк ISO 8601, например, «2017-09-13T10: 36: 40 + 01» или «2017-09-13»
Даниэль Винтерштейн,
Я только хотел сказать, что он OffsetDateTimeобрабатывает примеры, с которыми вы работаете ZonedDateTime. Я полагаю, что это не обрабатывает ни один из примеров, которые ZonedDateTimeне делают. В этом смысле это не улучшение (но и не хуже). Извините, я не совсем ясно
Оле В.В.
1
Это должен быть принятый ответ в 2020 году, учитывая положение вещей.
slashCoder
3

Apache Jackrabbit использует формат ISO 8601 для сохранения дат, и для их анализа существует вспомогательный класс:

org.apache.jackrabbit.util.ISO8601

Поставляется с jackrabbit-jcr-commons .

Александр Климетчек
источник
Хотя подмножество Jackrabbit может работать, имеет больше смысла использовать полноценную специализированную библиотеку. В Java это означает либо Joda-Time, либо java.time.
Василий Бурк
3

Как уже упоминалось, Android не имеет хорошего способа поддержки анализа / форматирования дат ISO 8601 с использованием классов, включенных в SDK. Я написал этот код несколько раз, поэтому я наконец создал Gist, включающий класс DateUtils, который поддерживает форматирование и анализ дат ISO 8601 и RFC 1123. Gist также включает в себя тестовый пример, показывающий, что он поддерживает.

https://gist.github.com/mraccola/702330625fad8eebe7d3

Мэтт Аккола
источник
2

SimpleDateFormat для JAVA 1.7 имеет классный шаблон для формата ISO 8601.

Класс SimpleDateFormat

Вот что я сделал:

Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
         Locale.ENGLISH).format(System.currentTimeMillis());
Eesha
источник
2
Zв строке формата не часовой пояс ISO 8601, вы должны использовать X(или XXили XXX), если вы хотите часовой пояс ISO 8601
Войта
d имеет тип String
Тим Чайлд
1

Делай это так:

public static void main(String[] args) throws ParseException {

    String dateStr = "2016-10-19T14:15:36+08:00";
    Date date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr).getTime();

    System.out.println(date);

}

Вот вывод:

Ср. 19 октября 15:15:36 CST 2016

yinhaomin
источник
1

Используйте строку как LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)

Степан
источник
1

Я удивлен, что ни одна библиотека java не поддерживает все форматы даты ISO 8601 согласно https://en.wikipedia.org/wiki/ISO_8601 . Joda DateTime поддерживала большинство из них, но не все, и поэтому я добавил собственную логику для обработки всех из них. Вот моя реализация.

import java.text.ParseException;
import java.util.Date;

import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;

public class ISO8601DateUtils {
	
	/**
	 * It parses all the date time formats from https://en.wikipedia.org/wiki/ISO_8601 and returns Joda DateTime.
	 * Zoda DateTime does not support dates of format 20190531T160233Z, and hence added custom logic to handle this using SimpleDateFormat.
	 * @param dateTimeString ISO 8601 date time string
	 * @return
	 */
	public static DateTime parse(String dateTimeString) {
		try {
			return new DateTime( dateTimeString );
		} catch(Exception e) {
			try {
				Date dateTime = DateUtils.parseDate(dateTimeString, JODA_NOT_SUPPORTED_ISO_DATES);
				return new DateTime(dateTime.getTime());
			} catch (ParseException e1) {
				throw new RuntimeException(String.format("Date %s could not be parsed to ISO date", dateTimeString));
			}
		}
	}
  
  	private static String[] JODA_NOT_SUPPORTED_ISO_DATES = new String[] {
			// upto millis
			"yyyyMMdd'T'HHmmssSSS'Z'",
			"yyyyMMdd'T'HHmmssSSSZ",
			"yyyyMMdd'T'HHmmssSSSXXX",
			
			"yyyy-MM-dd'T'HHmmssSSS'Z'",
			"yyyy-MM-dd'T'HHmmssSSSZ",
			"yyyy-MM-dd'T'HHmmssSSSXXX",
			
			// upto seconds
			"yyyyMMdd'T'HHmmss'Z'",
			"yyyyMMdd'T'HHmmssZ",
			"yyyyMMdd'T'HHmmssXXX",
			
			"yyyy-MM-dd'T'HHmmss'Z'", 
			"yyyy-MM-dd'T'HHmmssZ",
			"yyyy-MM-dd'T'HHmmssXXX",
			
			// upto minutes
			"yyyyMMdd'T'HHmm'Z'",
			"yyyyMMdd'T'HHmmZ",
			"yyyyMMdd'T'HHmmXXX",

			"yyyy-MM-dd'T'HHmm'Z'",
			"yyyy-MM-dd'T'HHmmZ",
			"yyyy-MM-dd'T'HHmmXXX",
			
			//upto hours is already supported by Joda DateTime
	};
}

raok1997
источник
1

Небольшой тест, который показывает, как анализировать дату в ISO8601 и что LocalDateTime не обрабатывает DST.

 @Test
    public void shouldHandleDaylightSavingTimes() throws ParseException {

        //ISO8601 UTC date format
        SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

        // 1 hour of difference between 2 dates in UTC happening at the Daylight Saving Time
        Date d1 = utcFormat.parse("2019-10-27T00:30:00.000Z");
        Date d2 = utcFormat.parse("2019-10-27T01:30:00.000Z");

        //Date 2 is before date 2
        Assert.assertTrue(d1.getTime() < d2.getTime());
        // And there is 1 hour difference between the 2 dates
        Assert.assertEquals(1000*60*60, d2.getTime() - d1.getTime());

        //Print the dates in local time
        SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm z Z", Locale.forLanguageTag("fr_CH"));
        localFormat.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));

        //Both dates are at 02h30 local time (because of DST), but one is CEST +0200 and the other CET +0100 (clock goes backwards)
        Assert.assertEquals("2019-10-27 02:30 CEST +0200", localFormat.format(d1));
        Assert.assertEquals("2019-10-27 02:30 CET +0100", localFormat.format(d2));

        //Small test that shows that LocalDateTime does not handle DST (and should not be used for storing timeseries data)
        LocalDateTime ld1 = LocalDateTime.ofInstant(d1.toInstant(), ZoneId.of("Europe/Zurich"));
        LocalDateTime ld2 = LocalDateTime.ofInstant(d2.toInstant(), ZoneId.of("Europe/Zurich"));

        //Note that a localdatetime does not handle DST, therefore the 2 dates are the same
        Assert.assertEquals(ld1, ld2);

        //They both have the following local values
        Assert.assertEquals(2019, ld1.getYear());
        Assert.assertEquals(27, ld1.getDayOfMonth());
        Assert.assertEquals(10, ld1.getMonthValue());
        Assert.assertEquals(2, ld1.getHour());
        Assert.assertEquals(30, ld1.getMinute());
        Assert.assertEquals(0, ld1.getSecond());

    }
ddtxra
источник
3
К вашему сведению, ужасно проблемные классы даты и времени, такие как java.util.Date, java.util.Calendarи java.text.SimpleDateFormatтеперь унаследованные , вытеснены классами java.time, встроенными в Java 8 и более поздние версии . Смотрите Учебник по Oracle .
Василий Бурк
Вы правы, что LocalDateTimeне обрабатывает летнее время (DST), поскольку он вообще не обрабатывает часовой пояс. Для этого нам нужно ZonedDateTime. Предложение Dateи SimpleDateFormatесть - ИМХО плохо.
Оле В.В.
1
Действительно ZonedDateTime работает. И java.time.Instant также является хорошей альтернативой для обработки DST. Я знаю, что java.util.Date устарела и не должна использоваться, но я только отвечал на оригинальный вопрос: Как преобразовать строку в 8601 в java.util.date ....
ddtxra
0

У меня была похожая потребность: мне нужно было иметь возможность анализировать любую дату, соответствующую стандарту ISO8601, не зная заранее точного формата, и я хотел легкое решение, которое также будет работать на Android.

Когда я погуглил свои потребности, я наткнулся на этот вопрос и заметил, что AFAIU, ни один ответ полностью не отвечает моим потребностям. Поэтому я разработал jISO8601 и поместил его в Maven Central .

Просто добавьте в вас pom.xml:

<dependency>
  <groupId>fr.turri</groupId>
  <artifactId>jISO8601</artifactId>
  <version>0.2</version>
</dependency>

и тогда тебе хорошо идти

import fr.turri.jiso8601.*;
...
Calendar cal = Iso8601Deserializer.toCalendar("1985-03-04");
Date date = Iso8601Deserializer.toDate("1985-03-04T12:34:56Z");

Надеется, что это поможет.

gturri
источник
0

Чтобы просто отформатировать такую ​​дату, у меня в приложении на основе Java 6 работало следующее. В проекте thymeleaf есть DateFormatкласс, JacksonThymeleafISO8601DateFormatкоторый вставляет пропущенную двоеточие:

https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java

Я использовал его для совместимости формата даты ECMAScript.

ЭКИП
источник
-1

Базовая функция Предоставлено: @wrygiel.

Эта функция может конвертировать формат ISO8601 в Java Date, который может обрабатывать значения смещения. Согласно определению ISO 8601 смещение может быть упомянуто в разных форматах.

±[hh]:[mm]
±[hh][mm]
±[hh]

Eg:  "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30" all mean the same time. - 06:30PM UTC

Этот класс имеет статические методы для преобразования

  • Объект строки в формате ISO8601 в дату (местное время)
  • Дата до строки ISO8601
  • Летнее время рассчитывается автоматически

Образец строки ISO8601

/*       "2013-06-25T14:00:00Z";
         "2013-06-25T140000Z";
         "2013-06-25T14:00:00+04";
         "2013-06-25T14:00:00+0400";
         "2013-06-25T140000+0400";
         "2013-06-25T14:00:00-04";
         "2013-06-25T14:00:00-0400";
         "2013-06-25T140000-0400";*/


public class ISO8601DateFormatter {

private static final DateFormat DATE_FORMAT_1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
private static final DateFormat DATE_FORMAT_2 = new SimpleDateFormat("yyyy-MM-dd'T'HHmmssZ");
private static final String UTC_PLUS = "+";
private static final String UTC_MINUS = "-";

public static Date toDate(String iso8601string) throws ParseException {
    iso8601string = iso8601string.trim();
    if(iso8601string.toUpperCase().indexOf("Z")>0){
        iso8601string = iso8601string.toUpperCase().replace("Z", "+0000");
    }else if(((iso8601string.indexOf(UTC_PLUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_PLUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_PLUS), UTC_PLUS);
    }else if(((iso8601string.indexOf(UTC_MINUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_MINUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_MINUS), UTC_MINUS);
    }

    Date date = null;
    if(iso8601string.contains(":"))
        date = DATE_FORMAT_1.parse(iso8601string);
    else{
        date = DATE_FORMAT_2.parse(iso8601string);
    }
    return date;
}

public static String toISO8601String(Date date){
    return DATE_FORMAT_1.format(date);
}

private static String replaceColon(String sourceStr, int offsetIndex){
    if(sourceStr.substring(offsetIndex).contains(":"))
        return sourceStr.substring(0, offsetIndex) + sourceStr.substring(offsetIndex).replace(":", "");
    return sourceStr;
}

private static String appendZeros(String sourceStr, int offsetIndex, String offsetChar){
    if((sourceStr.length()-1)-sourceStr.indexOf(offsetChar,offsetIndex)<=2)
        return sourceStr + "00";
    return sourceStr;
}

}

АХ
источник
2
Осторожно - DateFormat и производные классы не совместимы с многопоточностью! Использование статических объектов SimpleDateFormat, таких как DATE_FORMAT_1 и DATE_FORMAT_2, означает, что несколько потоков, вызывающих функции ISO8601DateFormatter, будут использовать один и тот же объект DateFormat. Это приводит к повреждению данных и неправильным датам, возвращаемым из вызовов DateFormat. Чтобы это исправить, вы должны просто сделать константы строк шаблона и создать локальные переменные SimpleDateFormat, когда это необходимо. Это гарантирует, что каждый объект просто используется одним потоком.
Тео
Лучшим решением для обеспечения безопасности потоков является использование библиотеки даты и времени, созданной для обеспечения безопасности потоков. В Java этот мир будет либо Joda-Time, либо java.time.
Василий Бурк
-1

Казалось, это работает лучше всего для меня:

public static Date fromISO8601_( String string ) {

    try {
            return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ssXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid ISO8601", e);
    }


}

Мне нужно было конвертировать в / из JavaScript строки даты в Java. Я нашел выше работы с рекомендацией. Было несколько примеров использования SimpleDateFormat, которые были близки, но они, казалось, не были подмножеством, как рекомендовано:

http://www.w3.org/TR/NOTE-datetime

и поддерживаются PLIST и JavaScript Strings, и вот что мне нужно.

Похоже, что это наиболее распространенная форма строки ISO8601 и хорошее подмножество.

Примеры, которые они приводят:

1994-11-05T08:15:30-05:00 corresponds 
November 5, 1994, 8:15:30 am, US Eastern Standard Time.

 1994-11-05T13:15:30Z corresponds to the same instant.

У меня также есть быстрая версия:

final static int SHORT_ISO_8601_TIME_LENGTH =  "1994-11-05T08:15:30Z".length ();
                                            // 01234567890123456789012
final static int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length ();


public static Date fromISO8601( String string ) {
    if (isISO8601 ( string )) {
        char [] charArray = Reflection.toCharArray ( string );//uses unsafe or string.toCharArray if unsafe is not available
        int year = CharScanner.parseIntFromTo ( charArray, 0, 4 );
        int month = CharScanner.parseIntFromTo ( charArray, 5, 7 );
        int day = CharScanner.parseIntFromTo ( charArray, 8, 10 );
        int hour = CharScanner.parseIntFromTo ( charArray, 11, 13 );

        int minute = CharScanner.parseIntFromTo ( charArray, 14, 16 );

        int second = CharScanner.parseIntFromTo ( charArray, 17, 19 );

        TimeZone tz ;

         if (charArray[19] == 'Z') {

             tz = TimeZone.getTimeZone ( "GMT" );
         } else {

             StringBuilder builder = new StringBuilder ( 9 );
             builder.append ( "GMT" );
             builder.append( charArray, 19, LONG_ISO_8601_TIME_LENGTH - 19);
             String tzStr = builder.toString ();
             tz = TimeZone.getTimeZone ( tzStr ) ;

         }
         return toDate ( tz, year, month, day, hour, minute, second );

    }   else {
        return null;
    }

}

...

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}


public static boolean isISO8601( String string ) {
      boolean valid = true;

      if (string.length () == SHORT_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == 'Z');

      } else if (string.length () == LONG_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == '-' || string.charAt ( 19 )  == '+');
          valid &=  (string.charAt ( 22 )  == ':');

      } else {
          return false;
      }

    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
    // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0

    valid &=  (string.charAt ( 4 )  == '-') &&
                (string.charAt ( 7 )  == '-') &&
                (string.charAt ( 10 ) == 'T') &&
                (string.charAt ( 13 ) == ':') &&
                (string.charAt ( 16 ) == ':');

    return valid;
}

Я не проверял это, но, думаю, это будет довольно быстро. Вроде работает. :)

@Test
public void testIsoShortDate() {
    String test =  "1994-11-05T08:15:30Z";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}

@Test
public void testIsoLongDate() {
    String test =  "1994-11-05T08:11:22-05:00";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}
RickHigh
источник
-2

Я думаю, что многие люди хотят разбирать строки дат JSON. Если вы зайдете на эту страницу, есть большая вероятность, что вы захотите преобразовать дату JSON JavaScript в дату Java.

Чтобы показать, как выглядит строка даты JSON:

    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)

Строка даты 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, но не одинаковые биты.

/*
    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)


 */
@Test
public void jsonJavaScriptDate() {
    String test =  "2013-12-14T01:55:33.412Z";

    Date date = Dates.fromJsonDate ( test );
    Date date2 = Dates.fromJsonDate_ ( test );

    assertEquals(date2.toString (), "" + date);

    puts (date);
}

Я написал два способа сделать это для моего проекта. Один стандарт, один быстрый.

Опять же, строка даты JSON является очень специфической реализацией ISO 8601 ....

(Я разместил другой в другом ответе, который должен работать для дат PLIST, которые являются другим форматом ISO 8601).

Дата JSON выглядит следующим образом:

public static Date fromJsonDate_( String string ) {

    try {

        return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid JSON date", e);
    }


}

Файлы PLIST (ASCII не GNUNext) также используют ISO 8601, но без миллисекунд, поэтому ... не все даты ISO-8601 одинаковы. (По крайней мере, я еще не нашел тот, который использует milis, и анализатор, который я видел, пропускает часовой пояс вообще OMG).

Теперь о быстрой версии (вы можете найти ее в Boon).

public static Date fromJsonDate( String string ) {

    return fromJsonDate ( Reflection.toCharArray ( string ), 0, string.length () );

}

Обратите внимание, что Reflection.toCharArray использует unsafe, если доступно, но по умолчанию - string.toCharArray, если нет.

(Вы можете взять его из примера, заменив Reflection.toCharArray (string) на string.toCharArray ()).

public static Date fromJsonDate( char[] charArray, int from, int to ) {

    if (isJsonDate ( charArray, from, to )) {
        int year = CharScanner.parseIntFromTo ( charArray, from + 0, from + 4 );
        int month = CharScanner.parseIntFromTo ( charArray,  from +5,  from +7 );
        int day = CharScanner.parseIntFromTo ( charArray,  from +8,  from +10 );
        int hour = CharScanner.parseIntFromTo ( charArray,  from +11,  from +13 );

        int minute = CharScanner.parseIntFromTo ( charArray,  from +14,  from +16 );

        int second = CharScanner.parseIntFromTo ( charArray,  from +17,  from +19 );

        int miliseconds = CharScanner.parseIntFromTo ( charArray,  from +20,  from +23 );

        TimeZone tz = TimeZone.getTimeZone ( "GMT" );


        return toDate ( tz, year, month, day, hour, minute, second, miliseconds );

    }   else {
        return null;
    }

}

IsJsonDate реализован следующим образом:

public static boolean isJsonDate( char[] charArray, int start, int to ) {
    boolean valid = true;
    final int length = to -start;

    if (length != JSON_TIME_LENGTH) {
        return false;
    }

    valid &=  (charArray [ start + 19 ]  == '.');

    if (!valid) {
        return false;
    }


    valid &=  (charArray[  start +4 ]  == '-') &&
            (charArray[  start +7 ]  == '-') &&
            (charArray[  start +10 ] == 'T') &&
            (charArray[  start +13 ] == ':') &&
            (charArray[  start +16 ] == ':');

    return valid;
}

В любом случае ... я предполагаю, что довольно много людей, которые приходят сюда ... могут искать строку даты JSON, и хотя это дата ISO-8601, она очень специфическая и требует очень специфического анализа.

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}

Смотрите https://github.com/RichardHightower/boon Boon есть анализатор PLIST (ASCII) и анализатор JSON.

Парсер JSON - самый быстрый из всех известных мне парсеров JSON.

Независимо проверено парнями Gatling Performance.

https://github.com/gatling/json-parsers-benchmark

Benchmark                               Mode Thr     Count  Sec         Mean   Mean error        Units
BoonCharArrayBenchmark.roundRobin      thrpt  16        10    1   724815,875    54339,825    ops/s
JacksonObjectBenchmark.roundRobin      thrpt  16        10    1   580014,875   145097,700    ops/s
JsonSmartBytesBenchmark.roundRobin     thrpt  16        10    1   575548,435    64202,618    ops/s
JsonSmartStringBenchmark.roundRobin    thrpt  16        10    1   541212,220    45144,815    ops/s
GSONStringBenchmark.roundRobin         thrpt  16        10    1   522947,175    65572,427    ops/s
BoonDirectBytesBenchmark.roundRobin    thrpt  16        10    1   521528,912    41366,197    ops/s
JacksonASTBenchmark.roundRobin         thrpt  16        10    1   512564,205   300704,545    ops/s
GSONReaderBenchmark.roundRobin         thrpt  16        10    1   446322,220    41327,496    ops/s
JsonSmartStreamBenchmark.roundRobin    thrpt  16        10    1   276399,298   130055,340    ops/s
JsonSmartReaderBenchmark.roundRobin    thrpt  16        10    1    86789,825    17690,031    ops/s

Он имеет самый быстрый анализатор JSON для потоков, считывателей, bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) и String.

Смотрите другие тесты на:

https://github.com/RichardHightower/json-parsers-benchmark

RickHigh
источник
Этот ответ о JSON не по теме. Кроме того, этот Вопрос неверен, поскольку среди очень немногих типов данных JSON нет такой вещи, как «дата JSON» . И в настоящее время весь этот код можно заменить однострочным вызовом встроенной функции Java:Instant.parse( "2013-12-14T01:55:33.412Z" )
Василий Бурк