如何根据区域设置格式化YearMonth和MonthDay?

使用特定的Locale在Java 8中格式化LocalDate可以这样实现:

 DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(myLocale).format(value); DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(myLocale).format(value); DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(myLocale).format(value); DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(myLocale).format(value); 

假设value = LocalDate.now()这将导致:

 // myLocale = Locale.ENGLISH 6/30/16 Jun 30, 2016 June 30, 2016 Thursday, June 30, 2016 // myLocale = Locale.GERMAN 30.06.16 30.06.2016 30. Juni 2016 Donnerstag, 30. Juni 2016 // myLocale = new Locale("es", "ES") 30/06/16 30-jun-2016 30 de junio de 2016 jueves 30 de junio de 2016 

正如您所看到的,Java决定使用哪个分隔符(“ – ”,“。”,“/”,“”等)以及如何对日期元素进行排序(例如,前一个月,反之亦然等) – 在某些语言环境中它可能是那一年第一,等等。

我的问题是:如何根据上面的示例中的Locale格式化java.time.YearMonthjava.time.MonthDay

基于这个例子,我希望这样的结果……

…对于YearMonth

 // myLocale = Locale.ENGLISH 6/16 Jun, 2016 June, 2016 June, 2016 // myLocale = Locale.GERMAN 06.16 06.2016 Juni 2016 Juni 2016 // myLocale = new Locale("es", "ES") 06/16 jun-2016 de junio de 2016 de junio de 2016 

…对于MonthDay

 // myLocale = Locale.ENGLISH 6/30 Jun 30 June 30 June 30 // myLocale = Locale.GERMAN 30.06. 30.06. 30. Juni 30. Juni // myLocale = new Locale("es", "ES") 30/06 30-jun 30 de junio de 30 de junio de 

当然可能还有其他Locale使用完全不同的分隔符和排序。

谢谢!

似乎这个Java-8-bug无法在Java-9中修复,因为即使是function扩展完成日期已经结束了。 让我们看看它是否会在Java-10中修复,这仍然需要很长时间……

当然,正如这里的一个答案所示,您可以尝试处理给定的本地化日期模式,以便删除不相关的部分。 但我仍然认为这种方法是错误的,因为周围仍有很多语言环境。 事实上,接受的答案对中国人来说是有缺陷的。 本地化的文字是这里的主要问题。 也许接受的答案至少可以修复这个重要的语言,但您也可以考虑另外两个具有良好国际化function的库,它们可以更可靠的方式解决您的问题

a) ICU4J

 DateFormat df = DateFormat.getInstanceForSkeleton(DateFormat.YEAR_MONTH, Locale.CHINESE); String output = df.format(new Date()); System.out.println("ICU4J=" + output); // 2017年1月 

但是,一个问题是缺乏与Java-8类型的互操作性,尤其是MonthDayYearMonth 。 解决方案需要Date.from(YearMonth.now().atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); 可能,但很麻烦。

b)我的库Time4J (与ICU4J具有相同的数据库)

 ChronoFormatter cf = ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.CHINESE, CalendarMonth.chronology()); CalendarMonth cm = CalendarMonth.from(YearMonth.now()); // or: CalendarMonth.nowInSystemTime() System.out.println("Time4J=" + cf.format(cm)); // 2017年1月 

与Java-8的互操作性也存在相反的方向。 MonthDay的Time4J对应的是AnnualDate类。


旁注:@Julian收到的中文答案:2017年1(需要修复)

您需要使用DateTimeFormatter#ofPattern

对于YearMonth

 YearMonth source = YearMonth.now(); DateTimeFormatter english = DateTimeFormatter.ofPattern("MMMM, yyyy", Locale.ENGLISH); DateTimeFormatter german = DateTimeFormatter.ofPattern("MMMM yyyy", Locale.GERMAN); System.out.println(source.format(english)); System.out.println(source.format(german)); 

对于MonthDay

 MonthDay source = MonthDay.now(); DateTimeFormatter english = DateTimeFormatter.ofPattern("MMMM dd", Locale.ENGLISH); DateTimeFormatter german = DateTimeFormatter.ofPattern("dd. MMMM", Locale.GERMAN); System.out.println(source.format(english)); System.out.println(source.format(german)); 

如果您使用有限的Locale列表,gevorg提供的解决方案可能是最简单的解决方案。

如果你想让它适用于任何Locale我会建议获得一个语言环境模式然后删除你不感兴趣的部分,一旦你有这个模式你应该删除你不感兴趣的部分并使用生成的模式创建自己的DateTimeFormatter。

这是上面针对MonthDay解释的想法的完整示例。 为了将它用于YearMonthkeep.add('y')替换keep.add('d') keep.add('y') 。 (当然还有MonthDayYearMonth

 ArrayList locales = new ArrayList(); locales.add(Locale.ENGLISH); locales.add(Locale.GERMAN); locales.add(new Locale("es", "ES")); locales.add(Locale.US); ArrayList styles = new ArrayList(); styles.add(FormatStyle.SHORT); styles.add(FormatStyle.MEDIUM); styles.add(FormatStyle.LONG); styles.add(FormatStyle.FULL); ArrayList keep = new ArrayList(); keep.add('d'); keep.add('M'); for (FormatStyle style : styles) { for (Locale myLocale : locales) { String myPattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(style, null, IsoChronology.INSTANCE, myLocale); boolean separator = false; boolean copy = true; String newPattern = ""; for (char c : myPattern.toCharArray()) { if (c == '\'') { separator = !separator; } if (!separator) { if (Character.isAlphabetic(c)) { if (keep.contains(c)) { copy = true; } else { copy = false; } } } if (copy) { newPattern = newPattern + c; } } char lastChar = newPattern.charAt(newPattern.length() - 1); while (!keep.contains(lastChar)) { if (lastChar == '\'') { newPattern = newPattern.substring(0, newPattern.length() - 1); newPattern = newPattern.substring(0, newPattern.lastIndexOf('\'')); } else { newPattern = newPattern.substring(0, newPattern.length() - 1); } lastChar = newPattern.charAt(newPattern.length() - 1); } System.out.println(DateTimeFormatter.ofPattern(newPattern, myLocale).format(YearMonth.now())); } System.out.println(); } 

输出将是:

 6/30 Jun 30 June 30 June 30 30.06 30.06 30. Juni 30. Juni 30/06 30-jun 30 de junio 30 de junio 6/30 Jun 30 June 30 June 30 

而对于YearMonth:

 6/16 Jun 2016 June 2016 June 2016 06.16 06.2016 Juni 2016 Juni 2016 06/16 jun-2016 junio de 2016 junio de 2016 6/16 Jun 2016 June 2016 June 2016