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