【问题标题】:DateTimeFormatter doesn't work as expectedDateTimeFormatter 无法按预期工作
【发布时间】:2020-06-25 07:57:13
【问题描述】:

我必须将日期时间字符串转换为分区日期时间对象。我使用 DateTimeFormatter 来读取模式。根据documentation,模式中的"Z"可以接受如下格式:

  • +/- 0000
  • +/- 00:00

ZonedDateTime.parse(myDate, formatter) 仅适用于第一种情况;相反,在第二种情况下,代码会生成异常。

Execution exception[[DateTimeParseException: Text '2020-06-22T16:00:00.000+00:00' could not be parsed at index 23]]

我正在使用 Java 8。示例和代码:

"2020-06-08T12:59:10.288+0000" **work**
"2020-06-08T12:59:10.288+00:00" **doesn't work**

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

ZonedDateTime dateConvertedUTC = ZonedDateTime.parse(dateTime, formatter);
LocalDateTime dateConverted = dateConvertedUTC.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalDateTime();

我做错了什么? 谢谢!

【问题讨论】:

    标签: java spring-boot datetime java-8 zoneddatetime


    【解决方案1】:

    您为时区指定了 Z,这就是 2020-06-08T12:59:10.288+0000 有效的原因。

    但如果你想解析 2020-06-08T12:59:10.288+00:00 你的格式必须是。

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");
    

    您可以在 JavaDoc 中找到它:

    偏移 Z:这会根据图案的数量格式化偏移 字母。一个、两个或三个字母输出小时和分钟, 没有冒号,例如“+0130”。输出将是“+0000”时 偏移量为零。四个字母输出本地化的完整形式 offset,相当于四个字母的Offset-O。输出将是 如果偏移量为零,则对应的本地化偏移量文本。 五个 字母输出小时、分钟,如果非零,则可选秒, 带冒号。 如果偏移量为零,则输出“Z”。六个或更多字母 抛出 IllegalArgumentException。

    【讨论】:

    • 是否可以解析可选的冒号?使用 1 模式解析两种格式(带和不带冒号)
    • 你可以试试 "yyyy-MM-dd'T'HH:mm:ss.SSSZ[ZZZZ]" 但我没有测试
    【解决方案2】:

    您确实需要为日期时间字符串定义格式2020-06-08T12:59:10.288+00:00。它已经在default format of OffsetDateTime 中。

    import java.time.LocalDateTime;
    import java.time.OffsetDateTime;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    
    public class Main {
        public static void main(String[] args) {
            OffsetDateTime odt = OffsetDateTime.parse("2020-06-08T12:59:10.288+00:00");
            System.out.println(odt);
    
            // Get ZonedDateTime in the desired time-zone from OffsetDateTime
            ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("Europe/Rome"));
    
            // Get LocalDateTime from ZonedDateTime
            LocalDateTime ldt = zdt.toLocalDateTime();
            System.out.println(ldt);
        }
    }
    

    输出:

    2020-06-08T12:59:10.288Z
    2020-06-08T14:59:10.288
    

    注意:ZonedDateTimeLocalDateTime 的转换丢弃了有价值的信息,即时区。因此,只有当您确定您的业务逻辑不需要时区信息时,您才应该执行此转换。

    【讨论】:

    • 他执行“LocalDateTime dateConverted = dateConvertedUTC.withZoneSameInstant(ZoneId.of("Europe/Rome")).toLocalDateTime();”所以这是有道理的,因为他将其转换为区域
    • @SimonMartinelli - 我答案末尾的注释很重要。在处理时区或偏移量时应使用ZonedDateTimeOffsetDateTime,而不是将日期时间转换为LocalDateTime,这会丢失时区和偏移量的有价值信息。
    • 但在他的示例中,他似乎收到了带有时区的日期,但希望将其转换为当地时间。如果您不需要时区部分,为什么要保留它。在我的应用程序中经常出现这种情况,我们将日期存储在本地时区中。所以没有时区
    • @SimonMartinelli - 似乎我们俩都在同一页面上,但只是在谈论不同的要求。当我们不需要时区和偏移信息时,将日期时间转换为 LocalDateTime 是绝对正确的。我提到的是,如果我们处理时区和偏移量,我们应该使用OffsetDateTimeZonedDateTime 而不是LocalDateTime。 :)
    • 是的,这就是他使用的“ZonedDateTime dateConvertedUTC = ZonedDateTime.parse(dateTime, formatter);” :-)
    猜你喜欢
    • 2013-12-23
    • 2014-12-09
    • 2016-01-13
    • 2020-09-21
    • 2011-08-17
    • 2012-04-29
    • 2021-08-12
    • 2019-02-04
    • 2014-12-02
    相关资源
    最近更新 更多