什么是解析日期/时间到OffsetDateTime Java中的最快方法是什么?是否有比标准库快库?
EG
OffsetDatetime x = Something.parse("2018-01-02T12:34:56+00:00");
据我所知的答案是否定的,有对于解析字符串像2018-01-02T12:34:56+00:00"
(ISO 8601格式)转换成OffsetDateTime
对象没有其他库。我没有料想到会听到或读到它,已经存在一个。
我如履薄冰下一个点,但我也印象中的标准库(AKA java.time)是足够的效率,并可能一样快,你可以期望得到之下。
编辑:我得到了好奇,写我自己的解析方法,看看我是否能够跑赢单ARG OffsetDateTime.parse
。我曾是。我自己的方法(来源以下)还没有得到内置方法的灵活性,它接受只有一个出大量的标准格式的变体,这可能是其强大的运算性能,明智的。解析你的字符串一百万次了:
OffsetDateTime.parse
这不是一个推荐!我可能永远不会用我自己的方法。对于绝大多数目的的维护负担不会是值得的。如果有一天,ISO 8601的不同变种轮番上涨,你将有一个昂贵的支持问题和bug修复。
我的方法很简单:
private static final OffsetDateTime parse(String s) {
char offsetSign;
if (s.length() != 25
|| s.charAt(4) != '-'
|| s.charAt(7) != '-'
|| s.charAt(10) != 'T'
|| s.charAt(13) != ':'
|| s.charAt(16) != ':'
|| ((offsetSign = s.charAt(19)) != '+' && offsetSign != '-')
|| s.charAt(22) != ':') {
throw new IllegalArgumentException();
}
int offsetHours = Integer.parseInt(s.substring(20, 22));
int offsetMinutes = Integer.parseInt(s.substring(23, 25));
if (offsetSign == '-') {
offsetHours = -offsetHours;
offsetMinutes = -offsetMinutes;
}
return OffsetDateTime.of(Integer.parseInt(s.substring(0, 4)),
Integer.parseInt(s.substring(5, 7)),
Integer.parseInt(s.substring(8, 10)),
Integer.parseInt(s.substring(11, 13)),
Integer.parseInt(s.substring(14, 16)),
Integer.parseInt(s.substring(17, 19)),
0,
ZoneOffset.ofHoursMinutes(offsetHours, offsetMinutes));
}
我知道在代码中的bug。我不认为这是值得进行彻底的测试和修复bug的这个答案,因为它不可能太大影响性能。
在每解析不到一毫秒,你不必担心被OffsetDateTime
优化分析。当然,你必须有更大的鱼鱼苗。
让我们尝试一个小的基准测试。
警告:微基准测试是非常不可靠。但希望这会让我们接近真实的认识。
警告:我冲到此代码,这个帖子。请仔细检查我的工作。
在我无力的尝试由JVM避免运行时优化,我用31倍不同的值,一个用于月份的每一天。我重复这些一千倍的31,000名单。然后,我拖着列表。
然而我的研究结果表明有在运行时优化大剂量的。每解析纳秒内循环的数量而变化*很大。
我用Java的JVM 11祖鲁产品由Azul系统,基于OpenJDK的实现,11.0.2版。然在MacBook Pro上(视网膜,15英寸,2013晚期),2.3 GHz的英特尔酷睿i7,16 GB 1600 MHz的DDR3。
结果总结:
我的结论:
OffsetDateTime
字符串。码。
System.out.println( "INFO - Starting the OffsetDateTime parsing benchmark." );
List < String > inputsShort = new ArrayList <>( 31 );
inputsShort.add( "2018-01-01T12:34:56+00:00" );
inputsShort.add( "2018-01-02T12:34:56+00:00" );
inputsShort.add( "2018-01-03T12:34:56+00:00" );
inputsShort.add( "2018-01-04T12:34:56+00:00" );
inputsShort.add( "2018-01-05T12:34:56+00:00" );
inputsShort.add( "2018-01-06T12:34:56+00:00" );
inputsShort.add( "2018-01-07T12:34:56+00:00" );
inputsShort.add( "2018-01-08T12:34:56+00:00" );
inputsShort.add( "2018-01-09T12:34:56+00:00" );
inputsShort.add( "2018-01-10T12:34:56+00:00" );
inputsShort.add( "2018-01-11T12:34:56+00:00" );
inputsShort.add( "2018-01-12T12:34:56+00:00" );
inputsShort.add( "2018-01-13T12:34:56+00:00" );
inputsShort.add( "2018-01-14T12:34:56+00:00" );
inputsShort.add( "2018-01-15T12:34:56+00:00" );
inputsShort.add( "2018-01-16T12:34:56+00:00" );
inputsShort.add( "2018-01-17T12:34:56+00:00" );
inputsShort.add( "2018-01-18T12:34:56+00:00" );
inputsShort.add( "2018-01-19T12:34:56+00:00" );
inputsShort.add( "2018-01-20T12:34:56+00:00" );
inputsShort.add( "2018-01-21T12:34:56+00:00" );
inputsShort.add( "2018-01-22T12:34:56+00:00" );
inputsShort.add( "2018-01-23T12:34:56+00:00" );
inputsShort.add( "2018-01-24T12:34:56+00:00" );
inputsShort.add( "2018-01-25T12:34:56+00:00" );
inputsShort.add( "2018-01-26T12:34:56+00:00" );
inputsShort.add( "2018-01-27T12:34:56+00:00" );
inputsShort.add( "2018-01-28T12:34:56+00:00" );
inputsShort.add( "2018-01-29T12:34:56+00:00" );
inputsShort.add( "2018-01-30T12:34:56+00:00" );
inputsShort.add( "2018-01-31T12:34:56+00:00" );
int loops = 100; // 100_000=1,573 nanos each parse. 10_000=4,243. 1_000=10,177. 100=31,125. 1=693,687 nanos each parse.
List < String > inputs = new ArrayList <>( inputsShort.size() * loops );
for ( int i = 1 ; i <= loops ; i++ ) {
inputs.addAll( inputsShort );
}
Collections.shuffle( inputs );
//System.out.println( inputs );
long start = System.nanoTime();
for ( String input : inputs ) {
OffsetDateTime odt = OffsetDateTime.parse( input );
}
long stop = System.nanoTime();
long nanosPerParse = ( ( stop - start ) / inputs.size() );
System.out.println( "INFO: nanosPerParse: " + nanosPerParse + " for a count of: " + inputs.size() + "." );