在Java中定制区域设置

2022-04-02 00:00:00 locale java datetime-parsing java-17

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

分析月份名称(带有DateTimeFormatter)时,开始变得棘手。

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

如果您使用Locale.UK,那么在Java 11中,九月也有缩写Sep...但当您尝试Java 17时,它有Sept(因为Unicode CLDR端的变化I asked if this was correct)。

结果是,我的tests在尝试使用Java 17生成时开始失败。

我当前的代码使用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]

所以从Java 17开始,我还找不到能够正常工作的内置区域设置。

在我看来,我必须采用Locale.ENGLISH并将WeekFields更改为Locale.UK,或者采用Locale.UK将9月的短名称更改为我需要的月份。

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

或者是否有更好的方法来解决此问题?


更新1:

  • 我已经从Unicode的人那里得到了反馈,他们表示en_gb使用Sept而不是Sep的更改是一个错误,因为这是它在英国应该被缩写的方式。

因此,我似乎不仅需要一个接受";Sep";的解析器,还需要一个可以接受英语的";Sept";和";Sep";混合使用的解析器。

更新2:

  • 我调整了我的代码,在出现解析异常的情况下,它将尝试将假定为输入的内容(";Sep";)更改为当前选定的Locate喜欢的内容。这并不包括所有的情况,它涵盖了我的特定情况的足够的情况。 对于感兴趣的人:my commit。

解决方案

我找到了使用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}; 
    }
}

和带有

的文件./src/main/resources/META-INF/services/java.util.spi.CalendarDataProvider
nl.basjes.parse.httpdlog.dissectors.locale.CalendarDataProviderISO8601

因为这只是无区域英语和英语的变体,所以它将从英语和英语中提取所有内容,并将上面的类放在上面。

虽然此方法有效,但我无法使用它。

问题是,尽管http://openjdk.java.net/jeps/252描述了The default lookup order will be CLDR, COMPAT, SPI,,但当前的实际情况是,由于deprecating the Extension Mechanism,SPI已从this change中的此列表中删除。

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

鉴于我的库(https://github.com/nielsbasjes/logparser/)也用于以更动态的方式(序列化并传输到已经运行的JVM)将类发送到多台计算机的情况(如Apache Flink/Beam/Drill/Pig),此构造不能使用。

我目前不知道在Java中执行此类操作的dynamic方法。

相关文章