【问题标题】:Java 10 DateTimeFormatter pattern symbols for "E" and "MMM" adding periods用于“E”和“MMM”添加句点的 Java 10 DateTimeFormatter 模式符号
【发布时间】:2018-10-15 03:20:52
【问题描述】:

所以在 Java 8 中如下:

DateTimeFormatter df = DateTimeFormatter.ofPattern("E d MMM yyyy");

当以这种方式应用时:

LocalDate date = LocalDate.now();
date.format(df);

会产生这样的东西:

"Available on Thu 30 Aug 2018"

但是,完全相同的代码在 Java 10 中运行时会产生以下结果:

"Available on Thu. 30 Aug. 2018"

注意日和月部分之后的句点...

我很清楚我可以只替换字符串中的句点,但我真的不想这样做。我想知道为什么会发生这种变化以及是否有替代模式?

我在网上找不到有关此更改的任何参考。

编辑:

根据 Basil 在下面的回答,这不是 Java 版本问题。这是一个语言环境问题。带有我的代码的 docker 映像在美国地区运行,而我的机器在澳大利亚地区运行 :)

【问题讨论】:

  • 可能对语言环境的解释发生了变化。尝试DateTimeFormatter.ofPattern("E d MMM yyyy").withLocale(Locale.US) 或其他语言环境,看看是否可行。
  • Zulu 使用HotSpot,基于OpenJDK。您真正使用的 JIT 编译器不应该影响本地化。
  • I'm well aware I can just replace the periods in the string.... 你可能做不到;如果您最终要处理多个语言环境或其他一些因素,您最终可能会遇到不应该删除的嵌入句点。
  • my Answer 所示,运行代码以记录您的JVM 版本和默认语言环境。通过编辑您的问题在此处报告。实际上,在这里显示 all System 属性会很有用。
  • 这里是关于切换到默认使用 CLDR 数据的 JDK 9 发行说明:oracle.com/technetwork/java/javase/…

标签: java date datetime datetime-format java-10


【解决方案1】:

验证Locale

标点符号和相关事项(缩写、拼写、元素顺序)被定义为文化规范的一部分。在 Java 中,这些文化规范由 Locale 指定。

语言环境在运行时变化

一个可能的问题是您在运行代码时没有显式指定 Locale,这意味着您隐式依赖 JVM 当前的默认语言环境。该默认值可能因运行时环境而异。

记录您的默认语言环境以进行验证。

Locale.getDefault().toString()

研究下面的代码示例,了解如何明确指定您的Locale。我建议始终让您的Locale 明确(顺便说一句,时区也是如此)。

定义在运行时变化

请注意,Java 9 的日期时间本地化发生了重大变化:JEP 252: Use CLDR Locale Data by Default。至少对于基于 OpenJDK 的 JVM,有关这些文化规范的信息来源已切换到 Unicode Consortium 提供的 Common Locale Data Repository

对于这里讨论的特殊情况,当使用Locale.US 时,我们看不出有什么区别,如下面的代码示例所示。但是对于某些语言环境,您可能确实会看到 Java 8 及更早版本与 Java 9 及更高版本之间的差异。

所以,我想知道您的问题的第二个示例中是否涉及不同的语言环境。解决方法是明确指定您或您的用户期望的语言环境,而不是隐式依赖 JVM 当前的瞬时默认值(默认值可以随时更改运行时!)。

无法确认问题

System.out.println( System.getProperty( "java.version" ) );
System.out.println( Locale.getDefault().toString() );

LocalDate ld = LocalDate.of( 2018 , Month.AUGUST , 30 );

Locale locale = Locale.US;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E d MMM yyyy" , locale );
String output = ld.format( f );

System.out.println( output );

当在 macOS High Sierra 下的 MacBook Pro Retina 上通过 IntelliJ 2018.3 中基于 OpenJDK 的 Zulu JVM Azul Systems 在 Java 10.0.2 中运行时,我得到:

10.0.2

zh_CN

2018 年 8 月 30 日星期四

对于 Java 8,请参阅相同的 code run live at IdeOne.com。请注意,IdeOne.com 中使用的 JVM 仅固定为单个区域设置,Locale.US

zh_CN

1.8.0_112

输出:2018 年 8 月 30 日星期四

澳大利亚

这是一个示例,说明您的输出在其他一些英语地区(例如澳大利亚)是如何成为常态的。

LocalDate ld = LocalDate.of( 2018 , Month.AUGUST , 30 );

Locale locale = new Locale( "en" , "AU" );  // "en-AU" is English Australia.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E d MMM yyyy" , locale );
String output = ld.format( f );

星期四。 2018 年 8 月 30 日

【讨论】:

  • 嗯,也许是我正在使用的 JVM (HotSpot)
  • 谢谢@BasilBourque 这是我的澳大利亚地区
  • @LeahEramo 很高兴看到诊断。经验教训:始终指定您想要/预期的LocaleZoneId,即使这意味着明确 要求使用Locale.getDefaultZoneId.systemDefault 提供当前默认值。您对LocalDate.now 的调用应该传递一个ZoneId 以避免同样的问题/混乱:LocalDate.now( ZoneId.of( "Australia/Canberra" ) )
  • @BasilBourque 现在更有意义了 :) 另一方面,无论如何我都喜欢你的详细解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 2021-12-08
  • 1970-01-01
  • 2017-01-27
相关资源
最近更新 更多