ofLocalizedDate
returns a formatter for the date, so it formats the day, month and year fields, so the object being formatted needs to have all the three fields. MonthDay
doesn't have the year field, that's why it throws a UnsupportedTemporalTypeException
.
If you want to print the whole date (with day, month and year), you must add the year to the MonthDay
object. You can use the atYear
method for that:
System.out.println(monthday.atYear(2017).format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
This will output:
11 серп. 2017
If you want the current year, just use Year.now().getValue()
instead of 2017
.
You can also use datetime.getYear()
, if you want the same year of the LocalDate
- or use the datetime
instead of the monthday
.
If you want to print just the day and month, you'll have to do some workarounds.
As the localized formatters are built-in in the JDK (and there seems to be no way to change them), you don't have a direct way of doing it, though there are some alternatives.
One (ugly) solution is to set a year and then remove it from the formatted String
:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"));
// set year to 2017, then remove "2017" from the formatted string
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").trim());
The output is:
11 серп.
The boring part is to remove all extra characters that might exist in each locale. For the English locale, I also had to remove the ,
:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH);
// remove the year (2017) and the "," from the output
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").replace(",", "").trim());
The output is:
Aug 11
You'll have to check all the extra characters (such as ,
) for all locales, and remove them from the output. Or just use ofPattern
with fixed non-locale specific patterns (as you did in your first 3 tests).
As @BasilBourque's noticed in the comments, I'm assuming that the year is at the beggining or end of the pattern. If the year is in the middle, there will be some extra spaces in the final result, which can be removed with .replaceAll("\\s{2,}", " ")
(2 or more spaces are replaced by just one).
Another alternative (as suggested by @JodaStephen comment) is to use a DateTimeFormatterBuilder
to get the localized date pattern.
Then I remove the year from the pattern, replacing y
and u
(the patterns used for the year), and also remove some other characters (like ,
and extra spaces).
With the resulting pattern (without the year), I create a DateTimeFormatter
with the specified locale and format the MonthDay
:
// get date pattern for the specified locale
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.forLanguageTag("UK"));
pattern = pattern
// remove the year (1 or more occurrences of "y" or "u")
.replaceAll("[yu]+", "")
// replace "," (you can change this to remove any other characters you want)
.replaceAll(",", "")
// replace 2 or more spaces with just one space and trim to remove spaces in the start or end
.replaceAll("\\s{2,}", " ").trim();
// create formatter for the pattern and locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag("UK"));
System.out.println(monthday.format(fmt));
The output will be:
11 серп.
Just reminding that this example might be incomplete, because there are some locales that uses /
, -
and other characters as separators and you must remove them from the final result. Check all the locales you're working with and remove the characters accordingly.
Another corner-case not covered by this is when you have y
or u
as literals (inside '
): in this case they shouldn't be removed. Anyway, you'll have to check the formats for all locales you're working with and handle each case accordingly.