【问题标题】:Parse non ISO 8601 to ISO_INSTANT将非 ISO 8601 解析为 ISO_INSTANT
【发布时间】:2020-09-08 04:48:12
【问题描述】:

我正在尝试将这个字符串 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; }

如何转换这些类型?

【问题讨论】:

    标签: java date parsing time instant


    【解决方案1】:

    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

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

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

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

    解决方案

    处理您的输入字符串以符合标准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,在与UTC 偏移的上下文中具有时间的日期。

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

    看到这个code run live at 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 对象代表时间轴上的同一时刻、同一点。

    【讨论】:

    • 感谢您的解释,很多有用的信息。
    • @BasilBourque 非常感谢你,这很完美。我会按照您的建议尝试更改数据的来源以满足 ISO 8601 的要求。最好的问候。
    • @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( 输入 , 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'”?
    • @rolling 与documented 一样,默认格式化程序会抑制小数秒中不必要的零,以便以三个一组的形式打印数字。如果您想要另一种格式,请使用另一个DateTimeFormatter,也许使用DateTimeFormatterBuilder。这些课程已被多次介绍,搜索以了解更多信息。开始here
    • @rolling 并且,请理解将字符串解析为日期时间对象的结果是日期时间对象,而不是String,而不是文本。像OffsetDateTime 这样的日期时间对象没有“格式”。
    【解决方案2】:

    您的异常的原因是您的 String 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 在这里不合适,因为它剥离了重要信息,即从 UTC 偏移的时区。
    • 在这里使用TemporalAccessor 是不必要且不合适的。引用its Javadoc:这个接口是框架级接口,不应该在应用程序代码中广泛使用。相反,应用程序应该创建并传递具体类型的实例
    • @BasilBourque 你好,我刚刚从 OP 复制代码,这就是我使用它的原因。
    • 嗨,谢谢,但我对另一种格式也有同样的例外。 java.time.format.DateTimeParseException:文本“Wed May 20 14:27:00 CEST 2020”无法在索引 0 处解析
    • @BasilBourque 在这种情况下可以接受作为答案,只保留自定义格式化程序的定义并删除 OP 代码行?
    猜你喜欢
    • 2019-08-26
    • 2013-05-14
    • 2016-08-30
    • 2012-04-20
    • 1970-01-01
    • 2014-07-16
    • 2011-06-17
    • 2021-01-17
    • 2020-11-24
    相关资源
    最近更新 更多