使用Java 8 java.time api解析ISO时间戳(仅限标准版)

我在例子中从字符串中获取毫秒数时遇到麻烦。 到目前为止,我已尝试过这三种不同的方式,示例显示了最新的尝试。 似乎总是可以归结为TemporalAccessor不支持ChronoField 。 如果我能成功构建一个Instant实例,我可以使用toEpochMilli() 。

String dateStr = "2014-08-16T05:03:45-05:00" TemporalAccessor creationAccessor = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(dateStr); Instant creationDate = Instant.from(creationAccessor); 

请提供简明的答案(不要从头开始构建格式化程序)并仅使用java 8标准发行版(我可以使用Joda,但希望避免依赖项)。

编辑:上面代码中的java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {OffsetSeconds=-18000},ISO resolved to 2014-08-16T05:03:45 of type java.time.format.Parsed抛出: java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {OffsetSeconds=-18000},ISO resolved to 2014-08-16T05:03:45 of type java.time.format.Parsed

这似乎是我在所有测试版本中发现的错误,包括jdk1.8.0_20b19但不包括在最终的jdk1.8.0_20 。 因此, 下载最新的jdk版本可以解决问题。 它也在最近的jdk1.9中得到了解决。

请注意,旧的Java 7方式适用于所有版本:

 long epochMillis = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX") .parse(dateStr).getTime(); 

它还支持获取Instant

 Instant i=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse(dateStr).toInstant(); long epochMillis = i.toEpochMilli(); 

但是,如上所述,简单的更新使您的Java 8代码正常工作。

你的代码工作,从Java 8更新51

从Mac OS X Mountain Lion上的Java 8 Update 51开始,您的代码现在正在运行。 Holger的答案 ,早期版本的Java中可能存在错误。 可以理解,因为java.time框架在Java 8中是全新的。

以下是代码的修改副本。

 String dateStr = "2014-08-16T05:03:45-05:00"; TemporalAccessor creationAccessor = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse( dateStr ); Instant instant = Instant.from( creationAccessor ); long millisSinceEpoch = instant.toEpochMilli( ); ZonedDateTime zdt = ZonedDateTime.ofInstant( instant, ZoneOffset.of( "-05:00" ) ); 

转储到控制台。

 System.out.println( "dateStr: " + dateStr ); System.out.println( "instant: " + instant ); System.out.println( " millis: " + millisSinceEpoch ); System.out.println( " zdt: " + zdt ); 

跑步的时候。

 dateStr: 2014-08-16T05:03:45-05:00 instant: 2014-08-16T10:03:45Z millis: 1408183425000 zdt: 2014-08-16T05:03:45-05:00 

规范方法:
parse(CharSequence text, TemporalQuery query)

您可能希望使用备用方法完成解析。

DateTimeFormatter的类doc提到通常的解析方法应该是调用DateTimeFormatter::parse(CharSequence text, TemporalQuery query)而不是DateTimeFormatter::parse(CharSequence text)

所以不是这样的:

 String input = "2007-12-03T10:15:30+01:00[Europe/Paris]" ; TemporalAccessor temporalAccessor = DateTimeFormatter.ISO_DATE_TIME.parse( input ) ; 

…这样做,我们添加第二个参数,参数是Java 8语法中的方法引用, from方法调用转换(在本例中, ZonedDateTime :: from ):

 String input = "2007-12-03T10:15:30+01:00[Europe/Paris]" ; ZonedDateTime zdt = DateTimeFormatter.ISO_DATE_TIME.parse( input , ZonedDateTime :: from ) ; 

转储到控制台。

 System.out.println("input: " + input ); System.out.println(" zdt: " + zdt ); 

跑步的时候。

 input: 2007-12-03T10:15:30+01:00[Europe/Paris] zdt: 2007-12-03T10:15:30+01:00[Europe/Paris] 

由于瞬间无法使用long来正确表示(他们设计的API没有Y 2040问题,当长度不再足够时),你必须使用两种方法的组合

getEpochSecond()

getNano()

前者从epoch获得秒数,后者为您提供自同一秒后经过的纳秒数。

Instant.from(creationAccessor).toEpochMili()应该排序你,至少根据TemporalInstant的ThreeTen javadoc 。 ThreeTen是javax.time的参考实现。 通过发表评论,让我知道这是否适合你。