用Java自定义区域设置



在Java中,Locale定义了与人们希望如何看待事物相关的事物(如货币格式、月份名称和一周开始的时间(。

当解析一个月的名称(使用DateTimeFormatter(时,它开始变得棘手。

如果使用Locale.USLocale.ENGLISH,则September的缩写为Sep

如果您使用Locale.UK,那么September在Java 11中也有缩写Sep。。。但当您尝试Java17时,它有Sept(因为我问它是否正确的Unicode CLDR端的更改(。

结果是,在尝试使用Java17进行构建时,我的测试开始失败。

我当前的代码使用Locale.UK而不是Locale.ENGLISH的原因是,在Java中,Locale.ENGLISH实际上不仅是英语,而且是非ISO美国人定义一周的方式(他们使用周日作为一周的第一天(。我想要ISO的方式。

简单地说:

  • WeekFields.ISO=WeekFields.of(Locale.UK)=WeekFields[MONDAY,4]
  • WeekFields.of(Locale.ENGLISH)=WeekFields.of(Locale.US)=WeekFields[SUNDAY,1]

所以从Java17开始,我还没能找到一个正确工作的内置Locale。

在我看来,我必须选择Locale.ENGLISH并更改WeekFields,或者选择Locale.UK并更改九月的简称以满足我的需要。

我的问题是如何做到这一点(在Java 17中(?

或者有更好的方法来解决这个问题吗?


更新1:

  • 我已经收到Unicode人员的反馈,他们表示en_GB改为使用Sept而不是Sep是一个错误,因为这是它在英国应该缩写的方式

所以我似乎不仅需要一个接受";9月;而是一个将接受";9月";以及";9月;英语。

更新2:

  • 我调整了我的代码,在出现解析异常的情况下,它将尝试将假设的输入("Sep"(更改为当前选择的位置喜欢的内容。这并不是涵盖所有的案例,而是针对我的具体情况涵盖了足够多的案例。对于那些感兴趣的人:我的承诺

我找到了一种使用SPI处理此问题的方法。

我在这里记录了一种可能对其他人有效的可能性(它不适用于我的上下文(。

作为一个实验,我创建了一个类:

package nl.basjes.parse.httpdlog.dissectors.locale;
import java.util.Locale;
import java.util.spi.CalendarDataProvider;
import static java.util.Calendar.MONDAY;
public class CalendarDataProviderISO8601 extends CalendarDataProvider {
public static final Locale ENGLISH_ISO = new Locale("en", "", "ISO");
@Override 
public int getFirstDayOfWeek(Locale locale) {
return MONDAY; 
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) { 
return 4; 
}
@Override
public Locale[] getAvailableLocales() {
return new Locale[]{ENGLISH_ISO}; 
}
}

和带有的文件CCD_ 21

nl.basjes.parse.httpdlog.dissectors.locale.CalendarDataProviderISO8601

因为这只是"无区域"的变体;英语";它将从";英语";并把上面的类放在上面。

虽然这是有效的,我不能使用它。

问题是尽管http://openjdk.java.net/jeps/252描述了CCD_ 22,当前的现实是由于CCD_。

因此,要使用此构造,类必须在启动时位于类路径中,并且必须将命令行选项-Djava.locale.providers=CLDR,COMPAT,SPI传递给JVM。

鉴于我的图书馆(https://github.com/nielsbasjes/logparser/(也用于这样的情况(如ApacheFlink/Beam/Drill/Pig(,即类以更动态的方式(序列化并传输到已经运行的JVM(传输到无法使用此构造的多台机器。

我目前还不知道在Java中有什么dynamic方法可以做这样的事情。

最新更新