首页 > 解决方案 > Java 11 在某些情况下无法将 String 转换为 LocalDateTime

问题描述

我在下面有这些代码:

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。

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

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版本还是其他原因。期待你的答复。非常感谢!

标签: javajava-11

解决方案


热内卢的大J还是小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. 我不知道为什么它没有在你的电脑上。

但是,您的代码还有另一个问题:您正在解析为 aLocalDateTime从而丢弃了时区信息。不要那样做。例如,字符串2021-08-15 09:00:28 (UTC-12:00)2021-08-15 09:00:28 (UTC+14:00)在 tome 中表示非常不同的点,相隔 26 小时,但将被解析为相同的LocalDateTime. 解析为 aZonedDateTime以保留时区。如果您需要不同时区的时间(例如您自己的时区),请转换ZonedDateTime为该时区的 a。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


推荐阅读