Перетворення рядка, сумісного з 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" ) ;

Мені це приємно.


243
Будьте готові отримати багато відповідей на "Використовуйте JodaTime" ...
JuanZe

3
@ Ice09: Якщо документація API для DateTimeFormat правильна (хоча документація JoDa може бути оманливою, помилковою або неповною, проте, шаблон, який ви використовували у власній "відповіді", не сумісний з ISO8601.
jarnbjo

21
Я не впевнений, коли це було додано, але, як видається, "X" вирішує цю проблему в SimpleDateFormat. Шаблон "yyyy-MM-dd'T'HH: mm: ssX" успішно аналізує приклад у питанні.
mlohbihler

12
"X" доступний з Java 7.
Lars Grammel

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 все ще не в змозі належним чином проаналізувати повний рядок дати, оскільки він не підтримує додаткові частини.

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

  • Деякі часові пояси не є повноцінними годинами поза 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 , але я не знаю, чому ви повинні це турбувати.


18
Рішення JAXB - це дійсно творчий підхід! Це добре працює, я тестував його на своєму зразку. Однак для тих, хто стикається з проблемою і дозволено використовувати JodaTime, я б радив використовувати її, оскільки вона відчуває себе більш природно. Але ваше рішення не потребує додаткових бібліотек (принаймні, з Java 6).
Ice09

36
Ось зворотне: Календар c = GregorianCalendar.getInstance (); c.setTime (aDate); return javax.xml.bind.DatatypeConverter.printDateTime (c);
Олександр Люнгберг

4
Насправді це не так просто b / c, вам доведеться ініціалізувати jaxb datatypeConverter. Я в кінцевому підсумку використовував DatatypeFactory як DataTypeConverterImpl внутрішньо. Який головний біль.
gtrak

3
@Simon: Ні, часові зони, звичайно, не ігноруються. Ви повинні робити щось не так. Якщо ви введете більше кількох символів і скажете нам, що ви насправді робите, хтось може пояснити вам, що.
jarnbjo

4
@jarnbjo Ви - перша і єдина людина, з якою я стикався, хто віддає перевагу стандартним, попереднім, 1.8-класовим датам класам, ніж час joda. Я вважаю час joda буквальною радістю від використання, особливо в порівнянні зі стандартним api, який є гидотою.
NimChimpsky

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

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

UPD 13.02.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" має бути в лапках
kervin

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, щоб бути безпечним для потоків).


2
Можливо, це повинно було бути перетворене на власне питання, з власною відповіддю?
Thorbear

5
Це була перша сторінка, на яку я натрапив, коли шукав відповідь, тому здавався придатним. Для більшості розробників Java Android не є точно Java. Однак у більшості випадків одна працює так само, як і інші, тому багато розробників Android шукатимуть "java", шукаючи цього.
wrygiel

1
Зауважте, що це не враховує мілісекундну роздільну здатність. Це легко додати.
Sky Kelsey

6
Мені довелося додати .SSS для дробових секунд, але працює чудово THX. Чому ви це робите 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
Ця відповідь працює надто важко. Ява.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");

Він не може розібрати цю дату: 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 . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - 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);

Це означає, що потрібен часовий пояс . Відповідно до ISO 8601, це необов'язково. Як і секунди, і т. Д. Отже, це аналізує лише певний підмножина ISO 8601.
Timmmm

1
Чудово працює з Java 1.8
Thiago Pereira

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).
Оле ВВ

2
@ OleV.V. Ви можете використовувати ISO_OFFSET_DATE_TIMEдля форматування дат із зрушеннями , наприклад +01:00( docs.oracle.com/javase/8/docs/api/java/time/format/… )
Лукас Баскротто

1
Це правда, @LucasBasquerotto. Хоча не згадуючи про цей формат чітко, відповіді Адама та Василя Бурка вже роблять щось подібне.
Оле ВВ

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());
  }
}

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

Вищенаведений спосіб замінити [ Zна +0000] або [ +01:00з +0100], коли в Java 6 виникає помилка (ви можете виявити версію Java і замінити спробувати / 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-часу, XML-api чи будь-чого іншого. Просто правильна схема.
Філіп Джозеффі

4

Також ви можете використовувати наступний клас -

org.springframework.extensions.surf.util.ISO8601DateFormat


Date date = ISO8601DateFormat.parse("date in iso8601");

Посилання на Java Doc - Ієрархія для пакету org.springframework.extensions.surf.maven.plugin.util


засуджується: Використовуйте com.fasterxml.jackson.databind.util.StdDateFormat замість
Vesion

4

У Java є десяток різних способів розбору дати-дати, як показують чудові відповіді. Але дещо дивовижно, жоден з часових класів Java повністю не реалізує ISO 8601!

Я рекомендую:

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/ Я не знає жодного класу 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());

2
Zу форматі рядка не є часовим поясом ISO 8601, ви повинні використовувати X(або XXабо XXX), якщо хочете часовий пояс ISO 8601
Vojta

d типу String
Tim Child

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


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
	};
}


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

    }

3
FYI, жахливі класи, які датують час, такі як 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");

Сподіваємось, це допоможе.


0

Щоб просто відформатувати дату, подібну цій, мені працювало наступне в додатку на базі Java 6. Є 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 до об'єкта Date (Local TimeZone)
  • Дата в рядку 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, коли це потрібно. Це забезпечить, що кожен об’єкт використовується лише одним потоком.
Тео

Краще виправлення безпеки потоку - це замість того, щоб використовувати бібліотеку дат-час, побудовану для безпеки потоку. На Яві цей світ буде або 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, і таке, що мені потрібно.

Здається, це найпоширеніша форма струни 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);
}

-2

Я думаю, що багато людей хочуть зробити розбір рядків дати JSON. Існує хороший шанс, якщо ви перейдете на цю сторінку, що ви, можливо, захочете перетворити дату JavaScript JSON в дату 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 non GNUNext) також використовується ISO 8601, але немає мілісекунд, тому ... не всі дати ISO-8601 однакові. (Принаймні, я ще не знайшов такого, який використовує міліс, і аналізатор, який я бачив, зовсім пропускає часовий пояс OMG).

Тепер про швидку версію (ви можете знайти її в Boon).

public static Date fromJsonDate( String string ) {

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

}

Зауважте, що Reflection.toCharArray використовує небезпечні, якщо вони доступні, але за замовчуванням до 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 - це найшвидший синтаксичний аналізатор Java 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 для потоків, читачів, байтів [], char [], CharSequence (StringBuilder, CharacterBuffer) та String.

Дивіться більше орієнтирів на:

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


Ця відповідь про JSON є поза темою питання. Крім того, це запитання є невірним, оскільки серед дуже небагатьох типів даних JSON немає такого поняття, як "дата JSON" . І в наш час весь цей код можна замінити однолінійним викликом до вбудованої функції Java:Instant.parse( "2013-12-14T01:55:33.412Z" )
Василь Бурк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.