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

3

10

Is there a way to format a day and month (in compact form), but not year, in the locale-correct order in Java/Kotlin? So for English it should be "Sep 20" but for Swedish "20 sep.".

For comparison, on Cocoa platforms, I can do the following (in Swift):

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

This will correctly turn things around. Is there an equivalent thing to do with the Java SDKs? I've been trying various forms with both DateTimeFormatter and the older SimpleTimeFormat APIs, but no success.

Notes: Unlike this question, I don't want the full medium format that includes the year. I also don't want either DateTimeFormatter.ofPattern("MMM d"), since that gives the incorrect result in Swedish, or DateTimeFormatter.ofPattern("d MMM"), since that gives the incorrect result in English.

Plication answered 28/6, 2019 at 6:49 Comment(3)
Possible duplicate of SimpleDateFormat and locale based format stringGerta
@Mark No, that is including the year, i.e. a full date formatPlication
FYI, Java does offer the MonthDay class to represent a month and day without a year. Unfortunately, the automatic localization features of java.time do not currently extend to this particular class, where we call DateTimeFormatter.ofLocalized….Ramonitaramos
R
8

No, sorry. I know of no Java library that will automatically turn "MMM d" around into 20 sep. for a locale that prefers the day of month before the month abbreviation.

You may try modifying the answer by Rowi in this way:

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

However the result is:

20 sep. 2019

It includes the year, which you didn’t ask for.

An advanced solution would use the DateTimeFormatterBuilder class to build DateTimeFormatter objects.

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

This returns d MMM y. Modify this string to delete the y and the space before it. Note that in other languages the y may be yy, yyyy or u and may not come last in the string. Pass your modified format pattern string to DateTimeFormatter.ofPattern.

It may be shaky. Even if you look through the format pattern strings for all available locales, the next version of CLDR (where the strings come from) might still contain a surprise. But I think it’s the best we can do. If it were me, I’d consider throwing an exception in case I can detect that the string from getLocalizedDateTimePattern doesn’t look like one I know how to modify.

Retorsion answered 28/6, 2019 at 7:18 Comment(2)
Thanks! This seems like the right answer, unfortunately. Getting the format string and modifying it does however feel kinda shaky...Plication
Thanks! Superb suggestions, all of them.Plication
T
1

You can do it in Java using 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));
Trailer answered 28/6, 2019 at 6:55 Comment(3)
Thanks, but this doesn't really address the question. It should be "20 sep." in Swedish but "Sep 20" in English, without me having to specify what the order is for each language.Plication
@skagedal, With Locale (new Locale("sv","SE")) It will format to "20 sep" without Locale , It will format to "20 Sep"Trailer
@Trailer That still doesn't answer the question. It's about the order of day & month. With UK locale it should be 'month day', with Swedish it should be 'day month'Metonym
A
1

You could get the DateFormat's pattern and remove the year:

val locale: Locale
val datePattern = (DateFormat.getDateInstance(DateFormat.MEDIUM, locale) as SimpleDateFormat).toPattern()
    .replace("y", "").trim { it < 'A' || it > 'z' }
Anchor answered 24/5, 2022 at 10:32 Comment(1)
Right, that is essentially the same type of solution as Basil wrote above, but using a different API. Thanks for contributing it!Plication

© 2022 - 2024 — McMap. All rights reserved.