我正在使用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)?
任何帮助都将不胜感激。
tl;dr
➥升级到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
2015年3月3日18:15:30,北美东部正常运行
但你声称已经看到了这个结果:
jeudi 3 décembre 2015东部时间18小时15
为什么会有差异?
Java 10与Java 8
嗯,我在运行Java 10。让我们试试Java 8。
1.8.0_181
jeudi 3 décembre 2015东部时间18小时15分
啊哈!现在我看到你的结果了。
偏移量错误
顺便说一句,正如Meno Hochschild所发现的那样,您的示例数据"2015-12-03T18:15:30+01:00[America/New_York]"
对区域America/New_York
使用了+01:00
的UTC偏移量。应该是-05:00
。我更正了你的字符串,以便在这个答案中使用。请参阅霍克希尔德的《答案》,了解更多讨论。
CLDR
我怀疑这种差异是由于Java 9中的一个重大更改造成的,至少在基于OpenJDK的Java 9实现中是这样。在Java 9中,OpenJDK从使用自己的本地化数据定义转变为从Unicode联盟外包公共区域设置数据库(CLDR)。请参阅JEP 252:默认情况下使用CLDR区域设置数据。
提供的多种数据包括"时区翻译和时区示例城市(或类似城市)"。
所以没有bug,没有问题。本地化是一个复杂的过程,对于适当的选择,通常有不止一种意见。您发现了一个例子,其中与OpenJDK 8及更早版本捆绑的本地化数据的作者与Unicode联盟的作者意见相左。或者,文化规范可能会随着时间的推移而改变。
CLDR的一个巨大好处是,除了一组更丰富的区域设置数据外,CLDR是事实上的区域设置数据的标准源。CLDR已被许多其他系统采用。因此,现在Java应用程序将表现出与其他系统相同的行为,或者几乎相同,但由于版本控制,可能存在一些差异。
说到版本控制,(希望)大多数地区的变化可能很少,因为Unicode联盟已经在这方面努力了很多年。CLDR现在应该是相对完整和稳定的。而一些Java应用程序从Java<8到Java>9可能会看到一些行为上的重大变化,如本问题所示,今后你应该不会看到什么惊喜/变化。
注意事项:这里的整个讨论涉及基于OpenJDK的Java实现。如今,这意味着大多数供应商(Azul、AdoptOpenJDK.net、Amazon Corretto、IBM、Oracle JDK和Oracle构建的OpenJDK)。但是,任何不是从OpenJDK构建的Java实现都可以自由使用除CLDR之外的其他本地化数据和行为源。
Java 8的变通方法
根据JEP 127,CLDR实际上包含在OpenJDK 8中,但默认情况下不使用。OpenJDK 9及更高版本中发生的变化是,根据JEP 252,默认情况下,CLDR被提升为咨询的第一个区域设置数据提供程序。请参阅Meno Hochschild的Answer,使CLDR成为8中的主要区域设置数据提供商。
区域设置=语言+文化
提示:在指定区域设置时,尽量避免只使用"FRENCH"。区域设置是人类语言加上代表一组文化规范的国家代码的组合,这些文化规范决定了诸如大写、缩写、元素排序(例如:年月日)等问题。虽然Locale.FRENCH
可能会回到使用法国这样的国家,但我建议你明确一点。例如,使用Locale.FRANCE
或Locale.CANADA_FRENCH
。
要使用少数Java常量中未定义的数百种语言和国家代码,请使用文档中的标准字符串代码。例如,fr-FR
表示法国的法语。
此外,请注意,CLDR有更多更详细和细致的区域设置信息,因此您现在可以选择使用许多变体和扩展(基本上是国家文化中的亚文化),这些变体和扩展在旧的区域设置数据集中没有定义。有关更多信息,请参阅Locale
和Unicode联盟网站。
到目前为止给出的问题和其他答案仅集中在区域名称翻译的主题上。但是主要问题是解析的错误时间结果。现在让我们进入细节。
-
固定偏移量(UTC+01)和区域标识符"America/New_York"的组合在某种程度上很奇怪,因为由"America/NNew_York"标识的区域只知道偏移量UTC-05(夏季为UTC-04)。
-
这种矛盾和矛盾的组合应该在分析时优先考虑偏移量。因此,时间"2015-12-03T18:15:30+01:00"与"2015-12-038T12:15:30-05:00"是同一时刻,但您仍然在EST区域解析了相同的本地时间"18:15:30"(偏移量为UTC-05),这是一个严重错误。相关的JDK Bug已经解决,但仅适用于Java 9+,而不适用于Java-8后台端口。
-
关于翻译的主题,Basil Bourque说了一些关于引入CLDR数据作为Java 9以后的标准/默认数据的正确的话。通过将系统属性设置为"Java.locale.providers=CLDR,JRE",可以在Java-8中更改默认存储库。此配置可能会解决Java-8的翻译问题,但解析时间错误的其他问题仍然存在
- 因此,我最后的建议是升级到Java 9+
您必须在Oracle公司定义的全局区域中使用合适的区域。CCD_ 12可用于作为CCD_ 13阵列来查看所有可用时区。根据您的要求,您可以使用Europe/Paris
时区。定义具有新时区的新日期,不更改日期,如下所示,
ZonedDateTime dateParis =
date.withZoneSameLocal( ZoneId.of( "Europe/Paris" ) );
有关详细信息,请参阅以下链接https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html#getAvailableIDs%28%29https://garygregory.wordpress.com/2013/06/18/what-are-the-java-timezone-ids/https://dzone.com/articles/deeper-look-java-8-date-and