如何在 Java 中以正确的语言环境顺序格式化日期和月份?

How can I format day and month in the locale-correct order in Java?

有没有办法按照 Java/Kotlin 中正确的语言环境顺序来格式化日和月(以紧凑形式),而不是年?所以对于英语它应该是 "Sep 20" 但对于瑞典语“20 sep.”。

为了比较,在 Cocoa 平台上,我可以执行以下操作(在 Swift 中):

let formatter = DateFormatter()
formatter.locale = Locale(identifier: "sv_SE")
formatter.setLocalizedDateFormatFromTemplate("MMM d")
print(formatter.string(from: Date()))

这将正确地扭转局面。 Java SDK 有类似的功能吗?我一直在尝试使用 DateTimeFormatter 和较旧的 SimpleTimeFormat API 的各种形式,但没有成功。

注意:this question 不同,我不想要包含年份的完整媒体格式。我也不想要 DateTimeFormatter.ofPattern("MMM d"),因为它在瑞典语中给出了错误的结果,或者 DateTimeFormatter.ofPattern("d MMM"),因为它在英语中给出了错误的结果。

您可以在 Java 中使用 LocalDate:

LocalDate dt = LocalDate.parse("2019-09-20"); 
System.out.println(dt);   
DateTimeFormatter ft = DateTimeFormatter.ofPattern("dd MMM", new Locale("sv","SE")); 
System.out.println(ft.format(dt));

不,对不起。我知道没有 Java 库会自动将 "MMM d" 转换为 20 sep.,因为语言环境更喜欢月份缩写前的日期。

您可以尝试这样修改

DateTimeFormatter ft = 
    DateTimeFormatter
    .ofLocalizedDate(FormatStyle.MEDIUM)
    .withLocale(Locale.forLanguageTag("sv-SE"))
;

然而结果是:

20 sep. 2019

它包括你没有要求的年份。

高级解决方案将使用 DateTimeFormatterBuilder class to build DateTimeFormatter 个对象。

DateTimeFormatterBuilder
.getLocalizedDateTimePattern(
    FormatStyle.MEDIUM, 
    null, 
    IsoChronology.INSTANCE, 
    Locale.forLanguageTag("sv-SE")
)

这个returnsd MMM y。修改此字符串以删除它之前的 y 和 space。请注意,在其他语言中,y 可能是 yyyyyyu,并且可能不会出现在字符串的最后。将修改后的格式模式字符串传递给 DateTimeFormatter.ofPattern.

可能摇摇欲坠。即使您查看了所有可用语言环境的格式模式字符串,CLDR(字符串的来源)的下一个版本可能仍然包含惊喜。但我认为这是我们能做的最好的。如果是我,我会考虑抛出一个异常,以防我检测到来自 getLocalizedDateTimePattern 的字符串看起来不像我知道如何修改的字符串。

您可以获得 DateFormat 的模式并删除年份:

val locale: Locale
val datePattern = (DateFormat.getDateInstance(DateFormat.MEDIUM, locale) as SimpleDateFormat).toPattern()
    .replace("y", "").trim { it < 'A' || it > 'z' }