在 Java 中自定义区域设置

Nie*_*jes 9 java locale datetime-parsing java-17

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

当解析月份的名称(带有DateTimeFormatter)时,它开始变得棘手。

如果您使用Locale.USLocale.ENGLISH则九月有缩写形式Sep

如果您使用Locale.UK,那么 September 在 Java 11 中也有缩写形式Sep……但是当您尝试 Java 17 时,它就会有Sept(因为 Unicode CLDR 端发生了变化,我询问这是否正确)。

结果是,当我尝试使用 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并将9 月的简称更改为我需要的WeekFieldsLocale.UK

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

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


更新1:

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

所以看来我不仅需要一个接受“Sep”的解析器,而且需要一个接受英语“Sept”和“Sep”混合的解析器。

更新2:

  • 我已经调整了我的代码,在出现解析异常的情况下,它将尝试将假设的输入(“Sep”)更改为当前选定的位置喜欢的内容。这并没有涵盖所有情况,但它涵盖了适合我的具体情况的足够案例。对于那些感兴趣的人:我的承诺

Nie*_*jes 4

我找到了一种使用 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}; 
    }
}
Run Code Online (Sandbox Code Playgroud)

和一个./src/main/resources/META-INF/services/java.util.spi.CalendarDataProvider文件

nl.basjes.parse.httpdlog.dissectors.locale.CalendarDataProviderISO8601
Run Code Online (Sandbox Code Playgroud)

因为这只是无区域“英语”的一个变体,所以它将获取“英语”中的所有内容,并将上面的类放在上面。

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

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

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

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

我目前不知道dynamic在 Java 中做这样的事情的方法。