Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Formatting MonthDay using DateTimeFormatter.ofLocalizedDate [duplicate]

I am trying to format a MonthDay object in a way that I do not have to specify the order. I am trying to use a localized DateTimeFormatter.

I have this code:

LocalDate datetime = LocalDate.parse("2017-08-11", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
MonthDay monthday = MonthDay.from(datetime);
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.ENGLISH)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.GERMANY)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.forLanguageTag("UK"))));

System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH)));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
// next line throws exception for java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
System.out.println(monthday.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));

The first 3 prints will print as expected the translated Month and day, but it is always month and then day. It does not change the order because I am explicitly telling it the order.

The next two (before the exception) would print respectively:

Aug 11, 2017
11 серп. 2017

Notice how the day is either before or after the month depending on the locale passed to the function. How do I do this with a MonthDay object as the last line throws an exception when done in this way.

like image 862
KadeYuy Avatar asked Aug 31 '25 05:08

KadeYuy


1 Answers

The other answers given so far describe the limitations of the standard DateTimeFormatter, see also the unsolved related JDK-issue. The suggested workaround to edit the localized date pattern by removing "y" etc. is tricky and might not work for all locales due to the existence of other localized literals inside the pattern.

However, you might also consider using external libraries which have a stronger focus on internationalization issues and have the capability to format a month-day-object using just the locale information. So the locale determines the order of field components and also dots, spaces or other special literals (like in Chinese).

Here two options with the necessary type conversions related to your system timezone:

ICU4J

MonthDay md = MonthDay.now();

GregorianCalendar gcal =
    new GregorianCalendar(
        2000, // avoids possible leap year problems
        md.getMonthValue() - 1,
        md.getDayOfMonth()
    );

DateFormat df =
    DateFormat.getInstanceForSkeleton(
        DateFormat.ABBR_MONTH_DAY,
        Locale.forLanguageTag("en")
    );
System.out.println(df.format(gcal.getTime())); // Aug 15

DateFormat df2 =
    DateFormat.getInstanceForSkeleton(
        DateFormat.ABBR_MONTH_DAY,
        Locale.forLanguageTag("de")
    );
System.out.println(df2.format(gcal.getTime())); // 15. Aug.

DateFormat df3 =
    DateFormat.getInstanceForSkeleton(DateFormat.MONTH_DAY, Locale.forLanguageTag("zh"));
System.out.println(df3.format(gcal.getTime())); // 8月15日

Time4J

MonthDay md = MonthDay.now();

ChronoFormatter<AnnualDate> cf1 =
    ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf1.format(AnnualDate.from(md))); // 15.8.

ChronoFormatter<AnnualDate> cf2 =
    ChronoFormatter.ofStyle(DisplayMode.MEDIUM, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf2.format(AnnualDate.from(md))); // 15.08.

ChronoFormatter<AnnualDate> cf3 =
    ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.ENGLISH, AnnualDate.chronology());
System.out.println(cf3.format(AnnualDate.from(md))); // Aug 15

ChronoFormatter<AnnualDate> cf4 =
    ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf4.format(AnnualDate.from(md))); // 15. August

ChronoFormatter<AnnualDate> cf5 =
    ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.CHINESE, AnnualDate.chronology());
System.out.println(cf5.format(AnnualDate.from(md))); // 8月15日

Disclaimer: Time4J has been written by myself to fill gaps or to improve other features of JSR-310 (java.time-package).

like image 125
Meno Hochschild Avatar answered Sep 02 '25 18:09

Meno Hochschild