java - 国际日期和时间应该使用 Unicode ICU 而不是 java.time.DateTimeFormatter

标签 java sonarqube

请就 SonarQube 报告的问题提出小问题。

在一段非常简单的代码上:

Instant.now().atZone(ZoneId.systemDefault()).toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"))

我被标记了一些对我来说很奇怪的东西: i18n-java:V1009

Unicode ICU and not java.time.DateTimeFormatter should be used for international dates and times

Java's DateTimeFormatter is quite error prone prior to Java version 9. Version 9 and greater with Unicode CLDR data is much improved, but still has errors for key locales. For ideal results, use Unicode ICU DateTimePatternGenerator.


Noncompliant Code Example

Locale userPreferredLocale = Locale.forLanguageTag("zh-Hans");
  ...
  DateTimeFormatter mediumFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(userPreferredLocale);

Compliant Solution

import com.ibm.icu.text.DateTimePatternGenerator;
  import com.ibm.icu.text.SimpleDateFormat;
  import com.ibm.icu.util.ULocale;
  ...
  ULocale userPreferredLocale = ULocale.forLanguageTag("zh-Hans");
  ...
  DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(userPreferredLocale);
  //pattern for com.ibm.icu.text.DateFormat.FULL="MMM DD,YYYY,h:mm A"
  SimpleDateFormat sdf = new SimpleDateFormat(dtpg.getBestPattern("MMM dd, YYYY, h:mm A"), uloc);

我正在使用 Java 11,并希望避免导入此 IBM 包。 我非常不确定当前的问题是什么(到目前为止代码工作正常)。

但我确实对解决这个问题很感兴趣。请问有实现它的“好方法”吗?

我会理解像这样的评论: “禁用SonarQube,禁用这个规则,不要太在意那些误报,不要太看重分析工具等等”

但我很感兴趣如何解决这个“Unicode ICU 而不是 java.time.DateTimeFormatter 应该用于国际日期和时间”。

谢谢

最佳答案

tl;dr

别担心。只需检查 DateTimeFormatter 生成的典型日期时间格式的文本在您支持的任何区域设置中满足您的用户的期望。如果是这样,则无需涉及 IBM 的 ICU 库。

java.time 自动本地化表示日期时间值的文本。

ZoneId ZoneId = ZoneId.of( "America/Montreal" ) ;
Locale locale = Locale.CANADA_FRENCH ;
ZonedDateTime zdt = ZonedDateTime.now( zoneId ) ;
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( formatter ) ;

详情

仅供引用, Sonar 消息指的是 Unicode CLDR成为基于 OpenJDK 的 Java 实现中的默认语言环境资源适用于 Java 9 及更高版本。参见 JEP 252: Use CLDR Locale Data by Default . Java 10 带来了 further support .

你说:

I am quite unsure what is the current problem (code working fine so far).

我相信这不是代码工作的问题。

问题是本地化是否符合语言环境。

日期时间值的格式因人类语言、文化和亚文化而异。我们谈论的是翻译的单词,以及标点符号、缩写、元素顺序、大写等规则。跟踪所有这些本地化信息涉及大量数据。最重要的是,他们改变了。文化在变,学术界的理解也在变。

Java 8 及更早版本的 OpenJDK 中默认使用的此类语言环境数据的实现相对有限且肤浅,没有涵盖许多子文化。

相比之下,由 Unicode Consortium 管理的 CLDR 庞大且详细,涵盖许多亚文化。早期版本的 OpenJDK 包含 CLDR 的副本。但只有在 Java 9 中,它才成为默认的语言环境资源,并首先在那里进行查找。

也许 Sonar 消息说 java.time.DateTimeFormatter 在特定亚文化的细微差别方面存在一些问题。但我还没有听说过。如果您担心,可以查看 OpenJDK 问题跟踪器。

➥ 我不会担心。如果您知道您的应用程序将仅用于少数特定区域设置,请测试这些区域设置。从每个地区招募一组用户。查看您的应用程序的典型输出是否符合他们的期望。如果他们满意,请编写一些单元测试,然后收工。

请记住,正如我所说,文化规范会随着时间而改变。 Unicode 联盟跟踪这些变化,根据需要发布新版本的 CLDR。当您更新 Java 实现时,您可能会获得 CLDR 的更新版本。很可能某天在某些语言环境中生成表示日期时间的文本时可能会得到不同的输出。如果您可能关心这些变化,请编写我上面提到的那些单元测试。

仅供引用,Sonar 消息中提到的库是 International Components for Unicode (ICU) 的 Java 实现由 Taligent build 和 IBM ,现在位于 Unicode 联盟:http://site.icu-project.org/

关于java - 国际日期和时间应该使用 Unicode ICU 而不是 java.time.DateTimeFormatter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65514207/

相关文章:

java - 衡量一些排序算法的时间复杂度

java - 在 Android 中使用 Apache POI 时的兼容性问题

java - 为什么当传递 * 作为主方法参数时会给出意想不到的结果?

msbuild - SonarQube、Cake 和 TeamCity 集成问题

java - Android Room 插入所有问题

java - 是否可以在 java 中传递结果集?

java - 即使设置了路径变量,SonarQube 也不会在 Windows 上启动

postgresql - sonar V.4.3.1 不启动postgresql

android - 是否可以使用 Sonar 扫描仪禁用特定 java 项目的 Findbugs Sensor

css - 如何可视化定制SonarQube?