有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

SONARQUE应该是Unicode而不是java。时间DateTimeFormatter应用于国际日期和时间

关于SonarQube报告的问题的小问题

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

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

我被一件对我来说很奇怪的事情所困扰: i18nJava: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);

我使用的是Java11,希望避免导入这个IBM包。 我很不确定当前的问题是什么(到目前为止代码工作正常)

但我确实对解决这个问题很感兴趣。请问有没有一个“好办法”来实现它

我将理解以下评论: “禁用SonarQube,禁用此规则,不要过多关注那些假阳性,不要过多地重视分析工具等”

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

多谢各位


共 (2) 个答案

  1. # 1 楼答案

    tl;博士

    别担心。只需检查一下^{}生成的典型日期时间格式文本是否满足用户在您支持的任何地区的期望。如果是这样,就不需要让IBM的ICU图书馆参与进来

    让我们来看看java。时间自动本地化表示日期时间值的文本

    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消息指的是UnicodeCLDR在基于Java 9及更高版本的OpenJDK的Java实现中成为默认语言环境资源的时间。见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).

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

    问题是本地化是否适用于区域设置

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

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

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

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

    ➥ 我不会担心的。如果你知道你的应用程序将只用于少数特定的地区,请测试这些地区。从每个地区招募一组用户。查看应用程序的典型输出是否符合他们的期望。如果他们满意,写一些单元测试,今天到此为止

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

    仅供参考,Sonar消息中提到的库是TaligentIBM构建的International Components for Unicode (ICU)的Java实现,现在位于Unicode联盟:http://site.icu-project.org/

  2. # 2 楼答案

    巴兹尔·波尔克已经写下了明智的答案。我谦恭地补充一点

    这是对的,也是错的

    • 你得到的信息是正确的,即DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")不会产生一种能让跨多种语言和文化的用户满意的格式。不知道这是否是你的目标
    • 关于建议dtpg.getBestPattern("MMM dd, YYYY, h:mm A")的消息是错误的,因为代码将因java.lang.IllegalArgumentException: Illegal pattern character 'A'或其他异常而崩溃

    消息称为不符合的代码会产生:

    • ^Java 8上的{}
    • ^Java 11上的{}

    因此,在我不知道比我在Basil Bourque的回答中读到的更多的情况下,我觉得SonarQube规则是一个过时的规则,对Java 8有效,但对Java 11应该忽略它

    我建议

    正确的方式在很大程度上取决于你设置日期和时间的格式

    • 如果要向用户显示,有两个选项:

      • 快捷方式是使用与SonarQube消息所指的Java 8不兼容的代码类似的代码,因为许多程序员都有很好的经验,而且在以后的Java版本中似乎是兼容的
      • 镀金的解决方案是询问你的用户他们喜欢哪种格式,然后告诉他们
    • 如果要与其他系统交换:

      • 最好教育其他系统的开发人员接受ISO 8601格式。然后只需使用Instant.toString()OffsetDateTime.toString),因为这些方法产生ISO8601
      • 如果另一个系统需要现有代码提供的格式,那么您别无选择:坚持使用您已有的格式设置程序
    • 如果用于存储:更喜欢存储数据时间对象,而不是字符串。例如,使用数据库引擎的timestamp with time zonedatetime数据类型和/或让Hibernate 5保存Instant或其他日期时间对象

    代码分析器

    TL;DR:代码分析器当然可以帮助我们发现代码中的错误和其他不足之处。他们当然也有一些误报

    我确实信任代码分析器。我对SonarQube没有任何经验。我是一个快乐的SpotBugs用户。当我确信代码符合我的要求时,我还会有选择地告诉SpotBugs忽略我编写的某些方法中的一些规则。我非常确信我也会用SonarQube做同样的事情