Stephen C. has written an answer that covers your options really well. As a supplement, since I agree that options 2 and 5 are the most correct, I would like to spell those two out.
Option 2: Use a different format
Localized date formats for most available locales are built into Java. These are generally under-used. We can save ourselves a lot if trouble by relying on Java to know how to format dates for our audience and their locale. I am using German as an example because it’s one of those locales that consistently includes dots both between the parts of the date and for abbreviation. The following should work for your locale too even if it’s not German (if you substitute Locale.getDefault(Locale.Category.FORMAT)
or your users’ locale).
private static final Locale LOCALE = Locale.GERMAN;
private static final DateTimeFormatter DATE_FORMATTER
= DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(LOCALE);
For demonstration I am formatting a day of each month of the current year:
LocalDate date = LocalDate.of(2021, Month.JANUARY, 16);
for (int i = 0; i < 12; i++) {
System.out.println(date.format(DATE_FORMATTER));
date = date.plusMonths(1).minusDays(1);
}
Output is:
16.01.2021
15.02.2021
14.03.2021
13.04.2021
12.05.2021
11.06.2021
10.07.2021
09.08.2021
08.09.2021
07.10.2021
06.11.2021
05.12.2021
For German locale we got numeric months here. Other locales may give other results, for example month abbreviations.
If you want a longer format that doesn’t use numeric months, specify for example FormatStyle.LONG
instead of FormatStyle.MEDIUM
:
private static final DateTimeFormatter DATE_FORMATTER
= DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)
.withLocale(LOCALE);
16. Januar 2021
15. Februar 2021
14. März 2021
13. April 2021
12. Mai 2021
11. Juni 2021
10. Juli 2021
9. August 2021
8. September 2021
7. Oktober 2021
6. November 2021
5. Dezember 2021
I suggest that your users would be happy with one of the above.
Option 5: DateTimeFormatterBuilder.appendText(TemporalField, Map<Long, String>)
If your users tell you that they don’t want the localized formats above and they do want your format with month abbreviations and single dots — it’s getting longer, but the result is beautiful and everyone will be happy.
private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("dd.")
.appendText(ChronoField.MONTH_OF_YEAR, getMonthAbbreviations())
.appendPattern(".uuuu")
.toFormatter(LOCALE);
private static Map<Long, String> getMonthAbbreviations() {
return Arrays.stream(Month.values())
.collect(Collectors.toMap(m -> Long.valueOf(m.getValue()),
MyClass::getDisplayNameWithoutDot));
}
private static String getDisplayNameWithoutDot(Month m) {
return m.getDisplayName(TextStyle.SHORT, LOCALE)
.replaceFirst("\\.$", "");
}
Output from the same loop as above:
16.Jan.2021
15.Feb.2021
14.März.2021
13.Apr.2021
12.Mai.2021
11.Juni.2021
10.Juli.2021
09.Aug.2021
08.Sep.2021
07.Okt.2021
06.Nov.2021
05.Dez.2021
One dot each time. The central trick is to use Java’s month abbreviation and remove the dot from it if there is one (Jan.
becomes Jan
) and use it as-is if there is no dot (Mai
stays Mai
). My getDisplayNameWithoutDot
method does this. I am in turn using this method to build the map that the two-arg appendText(TemporalField, Map<Long, String>)
method requires and uses for formatting.
LocalDate
has not format associated with, so "They are all in the format dd-MM-yyyy" is actually a invalid statement. You're getting..
because theMMM
format is usingJan.
, which is probably coming from the localisation – GeminiusSystem.out.println(DateTimeFormatter.ofPattern("dd.MMM.yyyy").format(LocalDate.now()));
prints06.Nov.2021
so I suspect that it's coming from the default localisation – GeminiusDateTimeFormatter.ofPattern("dd.MMM.yyyy", Locale.CANADA).format(LocalDate.now())
will print06.Nov..2021
is it's coming from the localisation been used by the JVM. I found that usingLocale.ENGLISH
will print06.Nov.2021
, but this might not be desirable depending what you're trying to achieve, as you're locking yourself into – Geminius