Java 8:DateTimeFormatter 未根据区域设置转换时区

Java 8: DateTimeFormatter not translating timezone based on locale

我正在使用 DateTimeFormatter 来格式化日期:

    ZonedDateTime date = ZonedDateTime.parse("2015-12-03T18:15:30+01:00[America/New_York]");

    DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)
                .withLocale(Locale.FRENCH);

    System.out.println(formatter.format(date));

代码输出:

jeudi 3 décembre 2015 18 h 15 EST

如何将时区从 EST 翻译成法语 HNE (Heure Normale de l'Est)?

任何帮助将不胜感激。

您必须在Oracle 公司定义的全局区域中使用合适的区域。 TimeZone.getAvailableIDs() 可用于以 String 数组形式查看所有可用时区。根据您的要求,您可以使用 Europe/Paris 时区。在不更改日期的情况下定义具有新时区的新日期,如下所示,

ZonedDateTime dateParis = 
date.withZoneSameLocal( ZoneId.of( "Europe/Paris" ) );

详情请参考以下链接 https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html#getAvailableIDs%28%29 https://garygregory.wordpress.com/2013/06/18/what-are-the-java-timezone-ids/ https://dzone.com/articles/deeper-look-java-8-date-and

tl;博士

➥ 升级超越 Java 8.

Java 9 及更高版本,使用 CLDR,现在对某些语言环境表现出不同的本地化行为。

运行 您在 Java 8 中的代码显示您观察到的结果 jeudi 3 décembre 2015 18 h 15 EST,而 运行 在 Java 9 和更高版本中显示您想要的结果 jeudi 3 décembre 2015 à 18:15:30 heure normale de l’Est nord-américain.

详情

我按原样尝试了您的代码,除了 var 名称。

System.out.println( System.getProperty( "java.version" ) );

ZonedDateTime zdt = ZonedDateTime.parse( "2015-12-03T18:15:30-05:00[America/New_York]" );

DateTimeFormatter formatter =
        DateTimeFormatter
                .ofLocalizedDateTime( FormatStyle.FULL )
                .withLocale( Locale.FRENCH );

System.out.println( formatter.format( zdt ) );

结果:

10.0.2

jeudi 3 décembre 2015 à 18:15:30 heure normale de l’Est nord-américain

但是你声称看到了这个结果:

jeudi 3 décembre 2015 18 h 15 EST

为什么不同?

Java 10 对比 Java 8

好吧,我是 运行 Java 10。让我们试试 Java 8。

1.8.0_181

jeudi 3 décembre 2015 18 h 15 EST

啊哈!现在我看到了你的结果。

偏移量错误

顺便提一下,作为, your example data "2015-12-03T18:15:30+01:00[America/New_York]" uses an incorrect offset-from-UTC of +01:00 for zone America/New_York. Should have been -05:00. I corrected your string for use in this Answer. See that 进行更多讨论。

CLDR

我怀疑差异是由于 Java 9 中的重大更改造成的,至少在 Java 9 的基于 OpenJDK 的实现中是这样。在 Java 9、OpenJDK从使用自己定义的本地化数据转为从Unicode Consortium the Common Locale Data Repository (CLDR). See JEP 252: Use CLDR Locale Data by Default.

外包

在提供的多种数据中,有“时区翻译和时区示例城市(或类似城市)”。

所以没有错误,没问题。本地化是一个复杂的过程,对于合适的选择往往有不止一种意见。您发现了一个示例,其中与 OpenJDK 8 及更早版本捆绑在一起的本地化数据的作者与 Unicode Consortium 的作者意见不一致。或者,也许随着时间的推移,特定地区的文化规范发生了变化。

除了一组更丰富的语言环境数据外,CLDR 的一大好处是 CLDR 是语言环境数据的事实上的 标准来源。 CLDR 已被许多其他系统采用。所以现在 Java 应用程序将表现出与其他系统相同的行为,或者 几乎 相同,但由于版本控制可能存在一些差异。

说到版本控制,(希望)大多数语言环境的变化可能很少,因为 Unicode 联盟多年来一直在努力解决这个问题。现在的CLDR应该是比较完整和稳定的。虽然一些 Java 应用程序从 Java <=8 跳到 Java >=9 可能会看到一些重大的行为变化,如本问题所示,但今后你应该会看到很少 surprises/changes.

警告: 此处的整个讨论涉及基于 OpenJDK 的 Java 实现。如今,这意味着大多数供应商(Azul、AdoptOpenJDK.net、Amazon Corretto、IBM、Oracle JDK 和 Oracle build of OpenJDK)。但是任何 Java 不是从 OpenJDK 构建的实现都可以免费使用 CLDR 以外的本地化数据和行为的替代来源。

Java 8

的解决方法

CLDR 实际上是 included in OpenJDK 8, per JEP 127, but is not used by default. What changed in OpenJDK 9 and later is that the CLDR was promoted by default to be the first locale data provider consulted, per JEP 252. See 使 CLDR 成为 8 中的主要语言环境数据提供者。

地区 = 语言 + 文化

提示:尽量避免在指定语言环境时仅使用“FRENCH”。语言环境是人类语言 加上 代表一组文化规范的国家/地区代码的组合,确定诸如大写、缩写、元素顺序(例如:年-月-日)等问题,等等。虽然 Locale.FRENCH 可能会退回到使用法国等国家/地区,但我建议您明确说明。例如使用 Locale.FRANCELocale.CANADA_FRENCH

要使用少数 Java 常量中未定义的数百种语言和国家/地区代码,请使用记录的标准字符串代码。例如,fr-FR 表示法国的法语。

此外,请注意 CLDR 更多 更详细和更细微的语言环境信息,因此您现在可以选择使用许多变体和扩展(基本上是民族文化中的亚文化)未在旧的语言环境数据集中定义。有关详细信息,请参阅 Locale 和 Unicode Consortium 网站。

到目前为止给出的问题和其他答案只集中在区域名称翻译的主题上。但是主要问题是解析的时间结果错误。现在让我们进入细节。

  • 固定偏移量 (UTC+01) 和区域标识符 "America/New_York" 的组合有点奇怪,因为 "America/New_York" 标识的区域只知道偏移量 UTC-05 (和夏季的 UTC-04)。

  • 这种矛盾的组合应该优先解析偏移量。所以时间“2015-12-03T18:15:30+01:00”与“2015-12-03T12:15:30-05:00”是同一时刻,但你仍然解析了相同的当地时间“18 :15:30" 在 EST 区(偏移量为 UTC-05),这是一个严重的错误。关联的 JDK-Bug 已解决,但仅针对 Java 9+,尚未针对 Java-8 向后移植。

  • 关于翻译的话题,Basil Bourque 已经说了一些关于引入 CLDR 数据的正确内容,如 standard/default for Java 9。默认存储库的更改可以在 Java-8 中由 setting the system property 到 "java.locale.providers=CLDR,JRE" 完成。 此配置可能会解决 Java-8 的翻译问题,但另一个解析时间错误的问题仍然存在。

  • 所以我最后的建议是升级到 Java 9+。