将非 ISO 8601 解析为 ISO_INSTANT

Parse non ISO 8601 to ISO_INSTANT

我正在尝试将此字符串 2020-05-20 14:27:00.943000000 +00:00 和此 Wed May 20 14:27:00 CEST 2020 解析为 ISO_INSTANT,但总是 return 此异常

java.time.format.DateTimeParseException: Text '2020-05-20 14:27:00.943000000 +00:00' could not be parsed at index 10

我的代码是:

protected Instant parseDateTime(String fechaHora) {

        DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
        TemporalAccessor temporalAccessor = formatter.parse(fechaHora);
        LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
        Instant result = Instant.from(zonedDateTime);
        return result; }

如何转换这种类型?

异常的原因是字符串 2020-05-20 14:27:00.943000000 +00:00ISO_INSTANT 之间的格式不同; from DateTimeFormatter ISO_INSTANT 接受像 2011-12-03T10:15:30Z 这样的字符串,这不是你的情况。此问题的可能解决方案是使用自定义 DateTimeFormatter,如下所示:

String fechaHora = "2020-05-20 14:27:00.943000000 +00:00";
DateTimeFormatter formatter =DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS ZZZZZ");
TemporalAccessor temporalAccessor = formatter.parse(fechaHora);
LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
Instant result = Instant.from(zonedDateTime);
System.out.println(result); //<-- it will print 2020-05-20T12:27:00.943Z

tl;博士

OffsetDateTime.parse( 
    "2020-05-20 14:27:00.943000000 +00:00" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSSSSSSSS xxx" )
)
.toInstant()

修复您的代码

您的代码在几个方面存在缺陷。

在这里使用 TemporalAccessor 是不必要和不合适的。引用 its Javadoc

This interface is a framework-level interface that should not be widely used in application code. Instead, applications should create and pass around instances of concrete types

LocalDateTime 在这里不合适,因为它去除了重要信息、时区或与 UTC 的偏移量。

您指定的格式化程序的格式与您的输入不匹配。

解决方案

处理您的输入字符串以符合标准 ISO 8601 格式。将日期和时间之间的 SPACE 替换为 T。删除时间和偏移量之间的SPACE。

String input = "2020-05-20 14:27:00.943000000 +00:00" ;
String[] strings = input.split( " " ) ;
String modifiedInput = strings[0] + "T" + strings[1] + strings[2] ;

解析为 OffsetDateTime,在与 UTC 偏移量的上下文中带有时间的日期。

OffsetDateTime odt = OffsetDateTime.parse( modifiedInput ) ;

或者,定义格式模式以匹配您的输入字符串。使用 DateTimeFormatter class。这已在 Stack Overflow 上多次介绍,因此请搜索以了解更多信息。

您尝试使用的预定义格式化程序 DateTimeFormatter.ISO_INSTANT 与您的输入不匹配。您的输入不符合该格式化程序使用的 ISO 8601 标准。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSSSSSSSS xxx" ) ;
String input = "2020-05-20 14:27:00.943000000 +00:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;

看到这个code run live at IdeOne.com

odt.toString(): 2020-05-20T14:27:00.943Z

如果您需要 return 一个 Instant,请致电 toInstant

Instant instant = odt.toInstant() ;

要在时区上下文中查看同一时刻,请应用 ZoneId 以获得 ZonedDateTime 对象。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

OffsetDateTimeZonedDateTime 对象代表同一时刻,时间轴上的同一点。