Преобразование строки, совместимой с ISO 8601, в java.утиль.Дата


Я пытаюсь преобразовать 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", "+00");
System.out.println(ISO8601DATEFORMAT.parse(date));

что, очевидно, не так приятно. Я скучаю? что-то или есть лучшее решение?


ответ

благодаря комментарию JuanZe, я нашел Joda Времени магия, это тоже описано здесь.

Итак, решение

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

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

25 555

25 ответов:

к сожалению, форматы часовых поясов доступны для 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", чтобы указать, мирового вместо "+00:00".

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

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

Я ищу решение для 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 вы можете кэшировать экземпляр в a частное статическое поле (используя ThreadLocal, чтобы быть потокобезопасным).

так это благословленный Java 7 documentation:

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

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

java.время

The java.время API (встроенный в Java 8 и более поздние версии), делает это немного проще.

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

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

если ваш вход может быть другим смещение от UTC ценностей, а не UTC указано Z (зулу) на конце, используйте 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 );

на Jackson-databind library также ISO8601DateFormat class что делает это (фактическая реализация в ISO8601Utils.

ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");

tl; dr

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

использование java.время

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

The 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.время

The java.время фреймворк встроен в Java 8 и более поздние версии. Эти классы вытесняют беспокойных старых наследие классы даты и времени, такие как java.util.Date,Calendar,& SimpleDateFormat.

The Joda Времени, теперь режим обслуживания, советует миграцию в java.время занятия.

чтобы узнать больше, смотрите Oracle Tutorial. Поиск переполнения стека для многих примеров и объяснений. Спецификация является JSR 310.

вы можете обменять java.время объекты непосредственно с вашей базой данных. Используйте - драйвера соответствуют JDBC 4.2 или позже. Нет необходимости в строках, нет необходимости в java.sql.* классы.

где получить Ява.время занятий?

  • 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 bundle реализации java.время занятий.
    • для более ранних Android ( ThreeTenABP адаптируется ThreeTen-Backport (упоминалось выше). Смотрите как использовать ThreeTenABP....

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


для 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);

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

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

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

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

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

на дату 2010-01-01T12:00:00Z

еще один очень простой способ разбора временных меток 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());
  }
}

java.время

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

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

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

он отлично работал для меня .

также вы можете использовать следующий класс -

org.springframework.extensions.surf.util.ISO8601DateFormat


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

ссылка на Java Doc -иерархия для организации пакета.springframework.увеличение.прибой.знаток.плагин.утиль

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

орг.апаш.заяц.утиль.В формате iso8601

входит jackrabbit-jcr-commons.

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

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

обходной путь для 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*$", "");
        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 и заменить try/catch с помощью оператора if).

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

Класс SimpleDateFormat

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

Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
         Locale.ENGLISH).format(System.currentTimeMillis());

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/ я не знаю ни одного класса Java, который мог бы справиться со всеми из них.

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

у меня была аналогичная потребность: мне нужно было иметь возможность анализировать любую дату, совместимую с 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");

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

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

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

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

делай так:

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

базовая функция любезность: @wrygiel.

эта функция может конвертировать формат ISO8601 в дату Java, которая может обрабатывать значения смещения. В соответствии с определение 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 строку
  • переход на летнее время происходит автоматически calc

образца в формате 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;
}

}

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

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

Я думаю, что многие люди хотят сделать, это разобрать строки даты 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.412 Z.

даты не покрываются спецификациями 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 одинаковы. (По крайней мере, я еще не нашел тот, который использует milis, и парсер, который я видел, полностью пропускает часовой пояс OMG).

теперь быстрая версия (вы можете найти его в дар).

public static Date fromJsonDate( String string ) {

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

}

обратите внимание на это отражение.toCharArray использует небезопасно, если доступно, но по умолчанию строка.toCharArray если не.

(вы можете взять его, например, заменив отражение.toCharArray (строка) со строкой.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, который я знаю.

независимая проверка производительности Гатлинга чуваки.

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