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.FRANCE
或 Locale.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+。
我正在使用 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
啊哈!现在我看到了你的结果。
偏移量错误
顺便提一下,作为"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
地区 = 语言 + 文化
提示:尽量避免在指定语言环境时仅使用“FRENCH”。语言环境是人类语言 加上 代表一组文化规范的国家/地区代码的组合,确定诸如大写、缩写、元素顺序(例如:年-月-日)等问题,等等。虽然 Locale.FRENCH
可能会退回到使用法国等国家/地区,但我建议您明确说明。例如使用 Locale.FRANCE
或 Locale.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+。