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

Raj*_*Raj 5 java timezone locale java-time dateformatter

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

\n\n
    ZonedDateTime date = ZonedDateTime.parse("2015-12-03T18:15:30+01:00[America/New_York]");\n\n    DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)\n                .withLocale(Locale.FRENCH);\n\n    System.out.println(formatter.format(date));\n
Run Code Online (Sandbox Code Playgroud)\n\n

代码输出:

\n\n
jeudi 3 d\xc3\xa9cembre 2015 18 h 15 EST\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

任何帮助将不胜感激。

\n

Bas*_*que 4

太长了;博士

\n

\xe2\x9e\xa5 升级到 Java 8 以上。

\n

Java 9 及更高版本,使用CLDR,现在对某些区域设置表现出不同的本地化行为。

\n

在 Java 8 中运行代码会显示您观察到的结果jeudi 3 d\xc3\xa9cembre 2015 18 h 15 EST,而在 Java 9 及更高版本中运行会显示您期望的结果jeudi 3 d\xc3\xa9cembre 2015 \xc3\xa0 18:15:30 heure normale de l\xe2\x80\x99Est nord-am\xc3\xa9ricain

\n

细节

\n

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

\n
System.out.println( System.getProperty( "java.version" ) );\n\nZonedDateTime zdt = ZonedDateTime.parse( "2015-12-03T18:15:30-05:00[America/New_York]" );\n\nDateTimeFormatter formatter =\n        DateTimeFormatter\n                .ofLocalizedDateTime( FormatStyle.FULL )\n                .withLocale( Locale.FRENCH );\n\nSystem.out.println( formatter.format( zdt ) );\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n
\n

10.0.2

\n

jeudi 3 d\xc3\xa9cembre 2015 \xc3\xa0 18:15:30 正常时间 de l\xe2\x80\x99Est Nord-am\xc3\xa9ricain

\n
\n

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

\n
\n

jeudi 3 d\xc3\xa9cembre 2015 年 18 点 15 分(美国东部时间)

\n
\n

为什么有区别?

\n

Java 10 与 Java 8

\n

好吧,我运行的是 Java 10。让我们尝试一下 Java 8。

\n
\n

1.8.0_181

\n

jeudi 3 d\xc3\xa9cembre 2015 年 18 点 15 分(美国东部时间)

\n
\n

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

\n

偏移错误

\n

顺便说一句,正如Meno Hochschild 发现的那样,您的示例数据使用了不正确的for zone"2015-12-03T18:15:30+01:00[America/New_York]"相对于 UTC 的偏移量。本来应该。我更正了您在此答案中使用的字符串。有关更多讨论,请参阅Hochschild 的回答。+01:00America/New_York-05:00

\n

CLDR

\n

我怀疑这种差异是由于 Java 9 中所做的重大更改造成的,至少在 Java 9 的基于 OpenJDK 的实现中是这样。在 Java 9 中,OpenJDK 从使用自己的本地化数据定义转向从 Unicode 联盟外包Common Locale数据存储库 (CLDR)。请参阅JEP 252:默认使用 CLDR 区域设置数据

\n

提供的多种数据包括 \xe2\x80\x9c 时区的翻译和时区\xe2\x80\x9d 的示例城市(或类似数据)。

\n

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

\n

除了提供更丰富的区域设置数据之外,CLDR 的一大好处是 CLDR 是区域设置数据事实上的标准源。CLDR 已被许多其他系统采用。因此,现在 Java 应用程序将表现出与其他系统相同的行为,或者几乎相同,但由于版本控制而可能存在一些差异。

\n

说到版本控制,(希望)大多数语言环境的更改可能不会有太大变化,因为 Unicode 联盟多年来一直在这方面努力工作。现在的CLDR应该是比较完整和稳定的。虽然一些 Java 应用程序从 Java <=8 跳转到 Java >=9 可能会看到一些重大的行为变化,如本问题所示,但展望未来,您应该会看到很少的惊喜/变化。

\n

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

\n

Java 8 的解决方法

\n

根据 JEP 127, CLDR 实际上包含在 OpenJDK 8 中,但默认情况下不使用。OpenJDK 9 及更高版本中的变化是,根据 JEP 252,默认情况下将 CLDR 提升为第一个咨询的语言环境数据提供程序。请参阅Meno Hochschild 的回答,使 CLDR 成为 8 中的主要语言环境数据提供者。

\n

语言环境 = 语言 + 文化

\n

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

\n

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

\n

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

\n