将非ISO 8601格式解析为ISO_INSTANT

3

我正在尝试解析这个字符串 2020-05-20 14:27:00.943000000 +00:00 和这个 Wed May 20 14:27:00 CEST 2020 到一个 ISO_INSTANT,但总是返回这个异常。

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; }

我该如何转换这些类型?
2个回答

4

简述

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

修复你的代码

你的代码存在几个缺陷。

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

该接口是一个框架级别的接口,不应在应用程序代码中广泛使用。相反,应用程序应创建并传递具体类型的实例。

LocalDateTime在这里不合适,因为它剥夺了重要信息,即时区或偏移量。

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

解决方案

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

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,即带有偏移量的日期和时间。
OffsetDateTime odt = OffsetDateTime.parse( modifiedInput ) ;

或者,定义一个格式化模式以匹配您的输入字符串。使用DateTimeFormatter类。这已经在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 ) ;

点击此处查看代码在IdeOne.com上的实时运行情况。

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

如果需要返回一个Instant,请调用toInstant方法。

Instant instant = odt.toInstant() ;

要在时区上下文中查看相同的时刻,请应用 ZoneId 来获取一个 ZonedDateTime 对象。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
OffsetDateTimeZonedDateTime 对象代表相同的时刻,时间轴上的同一点。

感谢解释,有很多有用的信息。 - undefined
@BasilBourque 非常感谢,这个完美地运行了。我会尝试按照你的建议将数据源更改为符合ISO 8601标准的格式。 最好的祝福。 - undefined
@BasilBourque 这段代码完美运行:"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 ) ;"除非出现像 "2020-05-20 14:27:00.000000000 +00:00" 或 "2020-05-20 14:27:00.000000001 +00:00" 这样的日期。如果毫秒为 "00000000",转换的结果会变成 "2020-05-20T14:27:00Z"。如何将其格式化为 "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"? - undefined
根据文档,默认格式化程序会抑制分数秒中不必要的零,并以每三位数字为一组打印数字。如果您想使用其他格式,请使用另一个DateTimeFormatter,或者使用DateTimeFormatterBuilder。这些类已经被覆盖了很多次,搜索以获取更多信息。从这里开始。 - undefined
@rolling 并且,请明白将字符串解析为日期-时间对象的结果是一个日期-时间对象,而不是一个String,也不是文本。像OffsetDateTime这样的日期-时间对象没有“格式”。 - undefined

1
您的异常原因是您的字符串 2020-05-20 14:27:00.943000000 +00:00ISO_INSTANT 之间的不同格式;从 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


LocalDateTime 在这里不合适,因为它剥离了重要信息——偏移自协调世界时的时区。 - undefined
еңЁиҝҷйҮҢдҪҝз”ЁTemporalAccessorжҳҜдёҚеҝ…иҰҒдё”дёҚеҗҲйҖӮзҡ„гҖӮеј•з”Ёе…¶JavadocдёӯжүҖиҝ°пјҡиҜҘжҺҘеҸЈжҳҜдёҖдёӘжЎҶжһ¶зә§еҲ«зҡ„жҺҘеҸЈпјҢдёҚеә”еңЁеә”з”ЁзЁӢеәҸд»Јз Ғдёӯе№ҝжіӣдҪҝз”ЁгҖӮзӣёеҸҚпјҢеә”з”ЁзЁӢеәҸеә”еҲӣе»ә并传йҖ’е…·дҪ“зұ»еһӢзҡ„е®һдҫӢгҖӮ - undefined
@BasilBourque 你好,我只是从原始帖子中复制了代码,这就是为什么我在使用它的原因。 - undefined
嗨,谢谢,但我遇到了另一种格式的相同异常。java.time.format.DateTimeParseException: 在索引0处无法解析文本'Wed May 20 14:27:00 CEST 2020'。 - undefined
@BasilBourque在这种情况下,只保留自定义格式化程序的定义并删除OP代码行是否可以作为答案接受? - undefined
@rolling 你需要为每种字符串输入定义一个格式化模式。你的另一种格式已经在Stack Overflow上被讨论过很多次了。搜索一下找到一些示例,或者直接阅读DateTimeFormatter的Javadoc并进行实验。此外,你的另一种格式对于以文本形式交换日期时间值来说是一个非常糟糕的选择。我建议你向数据发布者介绍ISO 8601标准。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接