Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
507 views
in Technique[技术] by (71.8m points)

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

Small question on an issue reported by SonarQube please.

On a very simple piece of code:

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

I got flagged with something very strange to me: 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);

I am using Java 11, and would like to avoid importing this IBM package. I am quite unsure what is the current problem (code working fine so far).

But I am indeed quite interested in solving this. Is there a “good way” to achieve it please?

I will understand comments like: “Disable SonarQube, disable this rule, don’t pay attention too much at those false positive, don't put too much weight on analysis tools etc”

But I am quite interested how to solve this "Unicode ICU and not java.time.DateTimeFormatter should be used for international dates and times" please.

Thank you


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

tl;dr

Do not be concerned. Just perform a check that your typical date-time formatted text generated by DateTimeFormatter meets the expectations of your users in whatever locales you support. If so, no need to involve that ICU library from IBM.

Let java.time automatically localize text representing date-time values.

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 ) ;

Details

FYI, that Sonar message refers to when Unicode CLDR became the default locale resource in Java implementations based on OpenJDK for Java 9 and later. See JEP 252: Use CLDR Locale Data by Default. Java 10 brought further support.

You said:

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

I believe this is not a question of code working.

The issue is localization being true to a locale.

Formatting of date-time values vary greatly by human language, culture, and sub-cultures. We are talking about translated words, and rules for punctuation, abbreviation, ordering of elements, capitalization, and so on. Tracking all this localization information involves much data. And on top of that, they change. Cultures change, and academics’ understanding changes.

The implementation of such locale data used by default in OpenJDK for Java 8 and earlier was relatively limited and shallow, without coverage of many sub-cultures.

In contrast, the CLDR managed by the Unicode Consortium is vast and detailed, covering many sub-cultures. Earlier version of OpenJDK contained a copy of the CLDR. But only in Java 9 did it become the default locale resource, with lookups done there first.

Perhaps the Sonar message is saying that java.time.DateTimeFormatter has some problems with particular sub-cultures’ nuances. But I have not heard of any. You could check the OpenJDK issue tracker, if you are concerned.

? I would not be worried. If you know your app will be used for only a few specific locales, test those locales. Recruit a panel of users from each of those locales. See if typical output from your app meets their expectations. If they are satisfied, write some unit tests, and call it a day.

Keep in mind that, as I said, the cultural norms change over time. The Unicode consortium tracks those changes, emitting new versions of the CLDR as needed. When you update your Java implementation, you may be getting an updated version of the CLDR. It is quite possible that some day in some locale you may get a different output when generating text representing a date-time. If you might care about such variations, write those unit tests I mentioned above.

FYI, the library mentioned by the Sonar message is a Java implementation of International Components for Unicode (ICU) built by Taligent and IBM, now housed at the Unicode Consortium: http://site.icu-project.org/


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...