我正在尝试格式化不带年份的日期(仅是日期和月份,例如12.10)
[DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
仍然对我来说是屈服的年份(12.10.20)。
所以我尝试了DateTimeFormatter.ofPattern("dd. MM")
,但显然硬编码顺序和点,这不会使美国用户满意。(谁期望斜杠和月份优先)
我如何使图案国际化?分隔符等是否有一些抽象语法?
我不认为可以提供一种在所有语言环境下都能获得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
查询有关语言环境的短日期格式模式。我认为这是您的格式化程序也在后台使用的模式(尚未检查)。然后,我使用不同的表达式从不同的变体中删除年份,请参见代码中的注释。年份可以用y
或u
表示,因此我将两者都考虑在内(实际上使用了y
)。现在,从修改后的模式中构建新的格式化程序很简单。对于保加利亚语:从我的角度来看,Java正则表达式有一个错误,他们无法将西里尔字母识别为单词字符,这就是为什么г也被删除的原因(错误也在文档中,它声称单词字符是[a-zA-Z_0-9]
)。不过,我们很幸运,就我们而言,它产生了我想要的结果。
如果您对90%的解决方案感到满意,这是我的建议,希望您可以对其进行修改,以使其在某些语言环境中的用户有任何需要。
好吧,正如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.