使用 Java 8 java.time api 解析 ISO 时间戳(仅限标准版)您的代码有效,从 Java 8 更新 51 开始规范方法:parse(CharSequence text, TemporalQuery<T> query)

我在示例中的字符串中获取纪元的毫秒时遇到了麻烦。到目前为止,我已经尝试了三种不同的方法,该示例显示了最新的尝试。它似乎总是归结为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做到这一点,但想避免依赖)。

编辑:Instant.from 在上面的代码中抛出: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


答案 1

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

请注意,旧的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代码正常工作。


答案 2

您的代码有效,从 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<T> query)

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

类文档提到,通常的解析方法应该是调用DateTimeFormatter::p arse(CharSequence text,TemporalQuery<T> query),而不是DateTimeFormatter::p arse(CharSequence text)DateTimeFormatter

所以不是这个:

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

...这样做,我们添加第二个参数,该参数是Java 8语法中的方法引用,以调用转换方法(在本例中为):fromZonedDateTime :: 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]