JSR310如何内部化一个月日模式?

问题描述 投票:2回答:2

我正在尝试格式化不带年份的日期(仅是日期和月份,例如12.10

[DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)仍然对我来说是屈服的年份(12.10.20)。

所以我尝试了DateTimeFormatter.ofPattern("dd. MM"),但显然硬编码顺序和点,这不会使美国用户满意。(谁期望斜杠和月份优先)

我如何使图案国际化?分隔符等是否有一些抽象语法?

java localization date-formatting java-time jsr310
2个回答
0
投票

我不认为可以提供一种在所有语言环境下都能获得100%满意结果的解决方案。让我们继续尝试吧。

    Locale formattingLocale = Locale.getDefault(Locale.Category.FORMAT);
    String formatPattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
            FormatStyle.SHORT, null, IsoChronology.INSTANCE, formattingLocale);

    // If year comes first, remove it and all punctuation and space before and after it
    formatPattern = formatPattern.replaceFirst("^\\W*[yu]+\\W*", "")
            // If year comes last and is preceded by a space somewhere, break at the space
            // (preserve any punctuation before the space)
            .replaceFirst("\\s\\W*[yu]+\\W*$", "")
            // Otherwise if year comes last, remove it and all punctuation and space before and after it
            .replaceFirst("\\W*[yu]+\\W*$", "");
    DateTimeFormatter monthDayFormatter
            = DateTimeFormatter.ofPattern(formatPattern, formattingLocale);

为了进行比较,我同时使用带您问题年份的普通格式器和准备好的格式器打印日期。

    LocalDate exampleDate = LocalDate.of(2020, Month.DECEMBER, 31);
    System.out.format(formattingLocale, "%-11s %s%n",
            exampleDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)),
            exampleDate.format(monthDayFormatter));     

以法语语言环境(Locale.FRENCH)输出:

31/12/2020  31/12

Locale.GERMAN中:

31.12.20    31.12

Locale.US中:

12/31/20    12/31

这可能会使美国用户感到高兴。瑞典文(Locale.forLanguageTag("sv")):

2020-12-31  12-31

在评论中,我提到了保加利亚语(bg):

31.12.20 г. 31.12

据我所知,“г”。 (西里尔字母g和一个点)是表示year的单词的缩写,因此,在省略年份时,我们也应该也将其省略。我不确定我们是否应该在12之后加上点号。

最后匈牙利语(hr):

31. 12. 2020. 31. 12.

[代码的工作方式:我们首先向DateTimeFormatterBuilder查询有关语言环境的短日期格式模式。我认为这是您的格式化程序也在后台使用的模式(尚未检查)。然后,我使用不同的表达式从不同的变体中删除年份,请参见代码中的注释。年份可以用yu表示,因此我将两者都考虑在内(实际上使用了y)。现在,从修改后的模式中构建新的格式化程序很简单。对于保加利亚语:从我的角度来看,Java正则表达式有一个错误,他们无法将西里尔字母识别为单词字符,这就是为什么г也被删除的原因(错误也在文档中,它声称单词字符是[a-zA-Z_0-9])。不过,我们很幸运,就我们而言,它产生了我想要的结果。

如果您对90%的解决方案感到满意,这是我的建议,希望您可以对其进行修改,以使其在某些语言环境中的用户有任何需要。

链接: Documentation of Java regular expressions (regex)


0
投票

好吧,正如Ole指出的那样,仅使用java.time并没有100%令人满意的解决方案。但是我的库Time4J找到了一种基于CLDR存储库数据的解决方案(ICU4J也提供了支持),使用的类型为AnnualDate(替代MonthDay):

LocalDate yourLocalDate = ...;
MonthDay md = MonthDay.from(yourLocalDate);
AnnualDate ad = AnnualDate.from(md);

ChronoFormatter<AnnualDate> usStyle =
  ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.US, AnnualDate.chronology());
ChronoFormatter<AnnualDate> germanStyle =
  ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMANY, AnnualDate.chronology());
System.out.println("US-format: " + usStyle.format(ad)); // US-format: 31/12
System.out.println("German: " + germanStyle.format(ad)); // German: 12.31.
© www.soinside.com 2019 - 2024. All rights reserved.