The java.time classes built into Java 8 and later offer the MonthDay
and YearMonth
classes. Their toString
and parse
methods use standard ISO 8601 formats (--MM-DD
& YYYY-MM
), which is wise.
For presentation to humans, the standard formats may not be suitable. Is there anyway to generate an automatically localized string to represent the values in objects of either MonthDay
or YearMonth
?
For example, in the United States users might typically want MM/DD for month-day and MM/YY for year-month. While in the UK users might want DD/MM for month-day.
Anyway to automate such variations by Locale
rather than explicitly define formatting patterns?
I tried the following code, using a date-oriented localizing formatter.
Locale l = Locale.US;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate ( FormatStyle.SHORT ).withLocale ( l );
YearMonth ym = YearMonth.of ( 2017 , Month.JANUARY );
MonthDay md = MonthDay.of ( Month.JANUARY , 29 );
String outputYm = ym.format ( f );
String outputMd = md.format ( f );
That code fails, throwing an exception when used for either YearMonth
or MonthDay
.
For YearMonth
:
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfMonth
at java.time.YearMonth.getLong(YearMonth.java:494)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2540)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)
at java.time.format.DateTimeFormatterBuilder$LocalizedPrinterParser.format(DateTimeFormatterBuilder.java:4347)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720)
at java.time.YearMonth.format(YearMonth.java:1073)
at javatimestuff.App.doIt(App.java:56)
at javatimestuff.App.main(App.java:45)
For MonthDay
:
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
at java.time.MonthDay.getLong(MonthDay.java:451)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2540)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)
at java.time.format.DateTimeFormatterBuilder$LocalizedPrinterParser.format(DateTimeFormatterBuilder.java:4347)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720)
at java.time.MonthDay.format(MonthDay.java:646)
at javatimestuff.App.doIt(App.java:57)
at javatimestuff.App.main(App.java:45)
See JDK-8168532. There needs an enhancement in the JDK to make this easy.
It is possible to do the work outside the JDK, but it is a lot of work. You have to parse the CLDR XML files (which are interlinked and have many references). Then you extract the relevant localized patterns for MonthYear
and YearMonth
, Then those patterns can be used to create a DateTimeFormatter
.
Alternatively, you can hard code a map - Map<Locale, DateTimeFormatter>
- based on your business needs.