Converting ISO 8601-compliant String to java.util.Date
我正试图将一个iso 8601格式的字符串转换为一个
我发现模式
但是,使用
所以,目前的解决方案是
1 2 3 | 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时代的魔力,这里也描述了它。
所以,解决办法是
1 2 3 |
或者更简单地说,通过构造函数使用默认的解析器:
1 | DateTime dt = new DateTime("2010-01-01T12:00:00+01:00" ) ; |
对我来说,这很好。
不幸的是,SimuleDead格式(Java 6和更早版本)可用的时区格式不是ISO 8601兼容的。SimpleDateFormat理解时区字符串,如"GMT+01:00"或"+0100",后者根据RFC_822。
即使Java 7根据ISO 8601增加了对时区描述符的支持,SimuleDead格式仍然无法正确解析完整的日期字符串,因为它不支持可选的部分。
当然,可以使用regexp重新格式化输入字符串,但替换规则并不像问题中那样简单:
- 某些时区不是离开UTC的整小时,因此字符串不一定以":00"结尾。
- ISO8601只允许时区包含小时数,因此"+01"等于"+01:00"
- ISO8601允许使用"Z"来表示UTC,而不是"+00:00"。
更简单的解决方案可能是在JAXB中使用数据类型转换器,因为JAXB必须能够根据XML模式规范解析ISO8601日期字符串。
也许你也可以利用乔达时间,但我不知道你为什么要为此而烦恼。
好的,这个问题已经回答了,但我还是放弃我的答案。它可能对某人有帮助。
我一直在寻找Android(API 7)的解决方案。
- 乔达是不可能的-它是巨大的,并遭受缓慢的初始化。对于那个特定的目的来说,这似乎也是一个重大的过度杀伤力。
- 涉及
javax.xml 的答案在android api 7上不起作用。
最后实现了这个简单的类。它只涵盖最常见的ISO 8601字符串形式,但在某些情况下(当您确信输入将采用这种格式时)这就足够了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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,以避免Android2.1中出现错误。如果你和我一样惊讶,看看这个谜语。对于其他Java引擎,可以将实例缓存在专用静态字段中(使用THeLead本地,以线程安全)。
被Java 7文档所支持的方式:
1 2 3 4 5 6 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的部分示例中找到更多示例。
Java.时间
JavaTimeAPI(内置到Java 8和更高版本中)使得这更容易一些。
如果您知道输入是在UTC中的,例如末尾的
如果您的输入可能是另一个与UTC值的偏移量,而不是由末尾的EDOCX1(zulu)指示的UTC,请使用
1 | OffsetDateTime odt = OffsetDateTime.parse("2010-01-01T12:00:00+01:00" ); |
然后提取一个
1 2 |
Jackson数据绑定库还具有这样做的iso8601dateformat类(iso8601utils中的实际实现)。
1 2 |
DR
1 | OffsetDateTime.parse ("2010-01-01T12:00:00+01:00" ) |
使用JavaTimes
Java 8和以后的新JavaTime包是由JoDA时间启发的。
1 | OffsetDateTime odt = OffsetDateTime.parse ("2010-01-01T12:00:00+01:00" ); |
调用
2010-01-01T12:00+01:00
要通过UTC透镜看到相同的值,请提取一个
1 | Instant instant = odt.toInstant(); |
…或…
1 | OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ); |
如果需要,调整到时区。时区是一个区域相对于UTC值的偏移历史,具有一组处理异常的规则,例如夏令时(DST)。因此,只要有可能,就应用时区,而不仅仅是偏移。
1 | ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of("America/Montreal" ) ); |
关于JavaTimes
JavaTimeFr框架是在Java 8和之后构建的。这些类取代了麻烦的旧遗留日期时间类,如
现在处于维护模式的joda time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle教程。以及搜索堆栈溢出以获得许多示例和解释。规格为JSR 310。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,不需要
在哪里获取java.time类?
- Java SE 8、Java SE 9、Java SE 10以及以后
- 内置的。
- 标准JAVA API的一部分与捆绑实现。
- Java 9添加了一些小的特性和修复。
- Java SE 6和Java SE 7
- 大部分JavaTimeActudio都被移植到TealEnter后端的Java 6和7中。
- 安卓
- java.time类的Android包实现的更高版本。
- 对于早期的Android(<26),threetenabp项目适应threeten backport(如上所述)。看看如何使用三连珠……
threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如
对于Java版本7
您可以遵循Oracle文档:http://docs.oracle.com/javase/7/docs/api/java/text/simpledateformat.html
X-用于ISO 8601时区
1 2 3 4 5 6 7 8 9 10 11 12 | 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); |
数据类型转换器解决方案不适用于所有虚拟机。以下对我有效:
1 | javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime() |
我发现Joda不是开箱即用的(特别是我在上面给出的例子中,时区是在一个日期,它应该是有效的)
我想我们应该用
1 |
日期:
解析iso8601时间戳的另一个非常简单的方法是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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中,可以使用JavaTime.ZONDATDeTimeType及其静态EDCOX1引用0方法。
Java 7 +的解决方案是使用SimuleDead格式:
此代码可以解析如下ISO8601格式:
2017-05-17T06:01:43.785Z 2017-05-13T02:58:21.391+01:00
但是在java6上,
1 2 3 4 5 6 7 8 9 10 11 12 | 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); } } |
上面的方法在Java 6中发生错误时,用EDCOX1〔14〕〕或[EDCOX1〔15〕用EDCOX1〔16〕〕代替(当您可以检测Java版本并用IF语句替换TIV/catch)时。
也可以使用以下类-
1 2 3 4 | org.springframework.extensions.surf.util.ISO8601DateFormat Date date = ISO8601DateFormat.parse("date in iso8601"); |
链接到JavaDOC层次结构的包Or.SrrgFrasWork.ExtExx.Surf.Mav.PuxiN.UTL
我也遇到了同样的问题,用下面的代码解决了它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; } |
我以前用过
但后来我发现造成这一例外的主要原因是
所以我用过
对我来说很管用。
ApacheJackrabbit使用iso8601格式来持久化日期,并且有一个助手类来解析它们:
org.apache.jackrabbit.util.iso8601(英文)
与jackrabbit jcr commons一起提供。
正如其他人提到的,Android没有一个好的方法来支持使用包含在SDK中的类解析/格式化ISO 8601日期。我已经多次编写了这段代码,所以我最终创建了一个gist,其中包含一个支持格式化和解析i so 8601和rfc 1123日期的dateutils类。GIST还包括一个显示它支持什么的测试用例。
https://gist.github.com/mraccola/702330625fad8eebe7d3
Java 1.7的SimuleDead格式对于ISO 8601格式有一个很酷的模式。
类simpledateformat
以下是我所做的:
1 2 | Date d = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ENGLISH).format(System.currentTimeMillis()); |
Java有十几种不同的方法来解析日期时间,正如这里的优秀答案所证明的那样。但有点令人惊讶的是,Java的时间类没有一个完全实现ISO 8601!
用Java 8,我建议:
这将处理UTC和带偏移量的示例,如"2017-09-13t10:36:40z"或"2017-09-13t10:36:40+01:00"。它适用于大多数用例。
但它不会处理"2017-09-13T10:36:40+01"这样的例子,这是一个有效的ISO 8601日期时间。它也不会只处理日期,例如"2017-09-13"。
如果必须处理这些问题,我建议首先使用regex来嗅探语法。
这里有一个很好的ISO 8601示例列表,其中有很多角落的例子:HTTPS://www. MyTalvals/COM/Bug/09/05/20/ISO-8601-DAT-ValueTest-To-Dunn-Sukk/我不知道任何Java类可以应付所有这些Java类。
使用字符串类
这样做:
1 2 3 4 5 6 7 8 | 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); } |
以下是输出:
星期三10月19日15:15:36 CST 2016
为了格式化这样的日期,下面的工作在Java 6应用程序中为我工作。胸腺素项目中有一个
https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b301add6098b3/src/main/java/org/thymeleaf/standard/serializer/standardjavascriptserializer.java
我用它来实现ecmascript日期格式的兼容性。
我有一个类似的需求:我需要能够在不预先知道确切格式的情况下解析任何符合ISO8601的日期,并且我想要一个轻量级的解决方案,它也可以在Android上工作。
当我在谷歌上搜索我的需求时,我偶然发现了这个问题,并注意到阿法乌没有完全符合我需求的答案。所以我开发了jiso8601并把它推到Maven Central上。
再加上你的
1 2 3 4 5 | <dependency> <groupId>fr.turri</groupId> jISO8601</artifactId> <version>0.2</version> </dependency> |
然后你就可以走了:
1 2 3 4 |
希望能有所帮助。
这似乎对我最好:
1 2 3 4 5 6 7 8 9 10 | 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字符串形式,是一个很好的子集。
他们给出的例子有:
1 2 3 4 | 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. |
我还有一个快速版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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; } } |
…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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; } |
我没有把它作为基准,但我想它会很快。它似乎起作用了。:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @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); } |
基本功能礼节:@wrygiel.
这个函数可以将ISO8601格式转换为可以处理偏移值的Java日期。根据ISO 8601的定义,可以用不同的格式提及偏移量。
1 2 3 4 5 | ±[hh]:[mm] ±[hh][mm] ±[hh] Eg: "18:30Z","22:30+04","1130-0700", and"15:00-03:30" all mean the same time. - 06:30PM UTC |
此类具有要转换的静态方法
- ISO8601字符串结束日期(本地时区)对象
- 日期到ISO8601字符串
- 夏令时自动计算
示例ISO8601字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | /* "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; } |
}
我认为很多人想要做的是解析JSON日期字符串。如果您希望将JavaScript JSON日期转换为Java日期,则有一个很好的机会。
要显示JSON日期字符串的外观,请执行以下操作:
1 2 3 4 5 6 7 8 9 | 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_要大得多,这只是一个子集,尽管它非常重要。
见http://www.json.org参见http://en.wikipedia.org/wiki/iso_请参阅http://www.w3.org/tr/note-datetime
碰巧,我编写了一个JSON解析器和一个plist解析器,两者都使用ISO-8601,但位不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /* 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的一个非常具体的实现。
(我在另一个答案中发布了另一个答案,该答案适用于不同的ISO 8601格式的plist日期)。
JSON日期如下:
1 2 3 4 5 6 7 8 9 10 11 | public static Date fromJsonDate_( String string ) { try { return new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse ( string ); } catch ( ParseException e ) { return Exceptions.handle (Date.class,"Not a valid JSON date", e); } } |
plist文件(ascii非gnunext)也使用iso 8601,但没有毫秒,所以…并非所有的ISO-8601日期都相同。(至少我还没有找到一个使用milis的解析器,我看到的解析器完全跳过时区OMG)。
现在,对于快速版本(您可以在Boon中找到它)。
1 2 3 4 5 |
请注意,reflection.tochararray使用不安全(如果可用),但如果不安全,则默认为string.tochararray。
(您可以通过将reflection.tochararray(string)替换为string.tochararray()将其从示例中去掉)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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日期,但它是一个非常具体的日期,需要非常具体的分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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/richardhighttower/boonBoon有一个plist解析器(ascii)和一个json解析器。
JSON解析器是我所知道的最快的JavaJSON解析器。
由加特林表演队独立验证。
https://github.com/gatling/json-parsers-benchmark
1 2 3 4 5 6 7 8 9 10 11 | 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 |
对于流、读卡器、bytes[]、char[]、charsequence(stringbuilder、characterbuffer)和string,它有最快的JSON解析器。
更多基准见:
https://github.com/richardhighttower/json-parsers-benchmark