【问题标题】:Java 11 can't convert String To LocalDateTime in some caseJava 11 在某些情况下无法将 String 转换为 LocalDateTime
【发布时间】:2021-10-19 00:33:54
【问题描述】:

我在下面有这些代码:

private void convertStringDatePosted() {
    String stringDatePosted = "20 Janeiro 2021 00:26";
    Locale locale = new Locale("pt", "MZ");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy HH:mm").withLocale(locale);
    LocalDateTime aa = LocalDateTime.parse(stringDatePosted, formatter);
    System.out.println(aa);
}

当我使用 java 8 运行代码时,它可以工作。但是对于 java 11,它会抛出这个异常:java.time.format.DateTimeParseException: Text '20 Janeiro 2021 00:26' could not be parsed at index 3。

我也有类似的情况,就是我要转换的字符串中有一个zone,代码是:

protected LocalDateTime getDatePosted() {
    String dateScraped = "2021-08-15 09:00:28 (UTC+01:00)";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss (z)");
    return LocalDateTime.parse(dateScraped, formatter);
}

如果使用 java 8 运行,它仍然可以工作,但使用 java 11 就不行。例外是: java.time.format.DateTimeParseException:无法在索引 24 处解析文本“20 Janeiro 2021 00:26”。

这个错误发生在 macOS 上,我还没有在其他操作系统上尝试过。

我不知道这个错误是由于java版本还是其他原因。期待你的答复。非常感谢!

【问题讨论】:

  • 从一个快速的谷歌中,你会发现在葡萄牙语中,月份的名称是小写的。例如,请参阅this。所以写日期的预期方式是“20 janeiro 2021 00:26”
  • 非常感谢您的支持,我的代码成功了。但是我不知道java 11和java 8之间的区别,为什么它在一个版本而不是另一个版本中工作?
  • 它在 Java 8 中工作的原因可能是一个错误。通过searching for "portuguese" in the bugs database,有很多类似的错误与不以正确的大小写输出月份名称有关。虽然没有报告这个特定的错误。我想它是由于修复了另一个错误而得到修复的,或者有人直接修复了它而没有报告它。
  • 哦,这太奇怪了。我将尝试在我的笔记本电脑上找出原因。感谢您提供的信息

标签: java java-11


【解决方案1】:

Janeiro 是大写还是小J?

在我看来,有两个错误:一个在您的字符串中,在 janeiro 中应该有一个小 j,另一个在 Java 8 中,它接受您拥有的大写 J。据说几十年前我在葡萄牙时只学了几句葡萄牙语

不同语言的月份名称是区域设置数据的一部分。 Java 最多可以从四个来源获取其语言环境数据。 Java 8 中的默认设置是自 Java 早期版本以来的 Java 内置语言环境数据。从 Java 9 开始,默认值为 CLDR,即 Unicode Common Locale Data Repository。所以在 Java 8 中,Java 自己的语言环境数据有大写的 J。CLDR,在 Java 8 中也可以通过系统属性获得,有一个小的 j。一个有趣的观察是,当我指示 Java 11 使用 Java 自己的语言环境数据时,它也会显示小 j。 Java 8 的错误已得到修复。

有许多可能的解决方案。一种是指示您的格式化程序在解析时不要关心大小写:

    String stringDatePosted = "20 Janeiro 2021 00:26";
    Locale locale = new Locale("pt", "MZ");
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("d MMMM yyyy HH:mm")
            .toFormatter(locale);
    LocalDateTime aa = LocalDateTime.parse(stringDatePosted, formatter);
    System.out.println(aa);

输出是:

2021-01-20T00:26

解析 UTC 偏移量

我无法重现您的其他示例。您的 getDatePosted 方法在我的 Mac 上的 Oracle jdk-11.0.3 上运行良好,并返回 2021-08-15T09:00:28。我不知道为什么它没有在您的计算机上。

不过,您的代码还有另一个问题:您正在解析为 LocalDateTime,因此会丢弃时区信息。不要那样做。例如字符串2021-08-15 09:00:28 (UTC-12:00)2021-08-15 09:00:28 (UTC+14:00)在tome中表示非常不同的点,相隔26小时,但将被解析为相同的LocalDateTime。解析为 ZonedDateTime 以保留时区。如果您需要不同时区的时间(例如您自己的时区),请转换为该时区的ZonedDateTime。如果可以通过任何方式避免,请不要使用LocalDateTime

解决方法:如果您无法将 UTC+01:00 解析为工作时区,则可以使用以下 hack:

protected OffsetDateTime getDatePosted() {
    String dateScraped = "2021-08-15 09:00:28 (UTC+01:00)";
    DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm:ss ('UTC'xxx)", Locale.ROOT);
    return OffsetDateTime.parse(dateScraped, formatter);
}

现在该方法返回2021-08-15T09:00:28+01:00。您还注意到 UTC 偏移量已被保留。

链接

有关不同 Java 版本中区域设置数据的更多信息的相关问题:JDK dateformatter parsing DayOfWeek in German locale, java8 vs java9

【讨论】:

  • 非常感谢。这些都是非常有趣的知识。祝你美好的一天。
猜你喜欢
  • 2018-10-24
  • 2017-05-30
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 2013-07-28
  • 1970-01-01
  • 2019-11-21
相关资源
最近更新 更多