Internationalization with Dates in Java

Naveen AnamaneniUpdated · 5 min read

The same date is written differently around the world. 4 March 2026 is 3/4/26 in the United States, 04/03/2026 in Britain and 04.03.26 in Germany. A reader who sees 03/04/2026 can't know whether it means March or April without knowing where it was written. Java solves this with DateTimeFormatter used together with a Locale: you choose how detailed the date should be, and Java supplies the order, the separators and the month names for the reader's region. In this lesson, you will learn the four format styles, how names are translated, how patterns and locales combine, and how to parse a localized date.

"DateTimeFormatter in Java" covers formatters in general; this lesson is about making them follow a locale.

Methods

MethodDescription
DateTimeFormatter.ofLocalizedDate(style)It is used to create a formatter for dates in a given style.
formatter.withLocale(locale)It returns a copy of the formatter that uses the given locale.
DateTimeFormatter.ofPattern(pattern, locale)It creates a fixed-layout formatter whose names follow the locale.
Month.getDisplayName(textStyle, locale), DayOfWeek.getDisplayName(...)They return a translated month or day name.
WeekFields.of(locale).getFirstDayOfWeek()It returns the day a week starts on in that region.

The Four Styles

FormatStyleDetailUS example
FULLWeekday, day, full month, yearWednesday, March 4, 2026
LONGDay, full month, yearMarch 4, 2026
MEDIUMShortened month or numbersMar 4, 2026
SHORTNumbers only3/4/26

Example: One Date, Six Locales

Dates.java▶ Try it
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.format.TextStyle;
import java.time.temporal.WeekFields;
import java.util.Locale;
 
public class Dates {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2026, 3, 4);
        Locale[] locales = {Locale.US, Locale.UK, Locale.GERMANY,
            Locale.FRANCE, Locale.of("hi", "IN"), Locale.JAPAN};
 
        for (FormatStyle style : FormatStyle.values()) {
            System.out.println(style + ":");
            for (Locale locale : locales) {
                DateTimeFormatter f = DateTimeFormatter
                    .ofLocalizedDate(style).withLocale(locale);
                System.out.println("  " + locale.toLanguageTag()
                    + "  " + date.format(f));
            }
        }
 
        System.out.println("Names:");
        for (Locale locale : locales) {
            System.out.println("  " + locale.toLanguageTag() + "  "
                + Month.MARCH.getDisplayName(TextStyle.FULL, locale) + ", "
                + DayOfWeek.WEDNESDAY.getDisplayName(TextStyle.FULL, locale)
                + ", week starts on "
                + WeekFields.of(locale).getFirstDayOfWeek());
        }
 
        // A pattern fixes the layout but still translates the names.
        DateTimeFormatter pattern =
            DateTimeFormatter.ofPattern("EEEE, d MMMM uuuu");
        System.out.println(date.format(pattern.withLocale(Locale.FRANCE)));
 
        // Parsing needs the same locale that wrote the text.
        DateTimeFormatter german = DateTimeFormatter
            .ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMANY);
        System.out.println(LocalDate.parse("04.03.2026", german));
    }
}
Output
FULL:
  en-US  Wednesday, March 4, 2026
  en-GB  Wednesday, 4 March 2026
  de-DE  Mittwoch, 4. März 2026
  fr-FR  mercredi 4 mars 2026
  hi-IN  बुधवार, 4 मार्च 2026
  ja-JP  2026年3月4日水曜日
LONG:
  en-US  March 4, 2026
  en-GB  4 March 2026
  de-DE  4. März 2026
  fr-FR  4 mars 2026
  hi-IN  4 मार्च 2026
  ja-JP  2026年3月4日
MEDIUM:
  en-US  Mar 4, 2026
  en-GB  4 Mar 2026
  de-DE  04.03.2026
  fr-FR  4 mars 2026
  hi-IN  4 मार्च 2026
  ja-JP  2026/03/04
SHORT:
  en-US  3/4/26
  en-GB  04/03/2026
  de-DE  04.03.26
  fr-FR  04/03/2026
  hi-IN  4/3/26
  ja-JP  2026/03/04
Names:
  en-US  March, Wednesday, week starts on SUNDAY
  en-GB  March, Wednesday, week starts on MONDAY
  de-DE  März, Mittwoch, week starts on MONDAY
  fr-FR  mars, mercredi, week starts on MONDAY
  hi-IN  मार्च, बुधवार, week starts on SUNDAY
  ja-JP  3月, 水曜日, week starts on SUNDAY
mercredi, 4 mars 2026
2026-03-04

Explanation:

  1. Each style is printed for six locales. The program never mentions an order or a separator: ofLocalizedDate(style).withLocale(locale) does it all.
  2. SHORT shows the danger of fixed formats. The US prints 3/4/26 and India 4/3/26 for the same day.
  3. Names come from getDisplayName: March is "März" in German and "mars" in French, which doesn't capitalize month names.
  4. The week starts on Sunday in the US, India and Japan, and on Monday in Britain, Germany and France. A calendar screen needs this.
  5. A pattern with a locale keeps your layout (EEEE, d MMMM uuuu) but still translates the names: "mercredi, 4 mars 2026".
  6. Parsing uses the same formatter and locale that produced the text, turning 04.03.2026 back into a LocalDate.

Style or Pattern?

UseWhen
ofLocalizedDate(style)Text shown to people. The layout follows each region's custom.
ofPattern(...) with a localeYou need a specific layout but want translated names.
DateTimeFormatter.ISO_LOCAL_DATE (2026-03-04)Data for programs: files, JSON, databases, URLs. It never depends on a locale.

Common Mistakes

Forgetting withLocale. The formatter uses the JVM's default locale, which on a server is the server's, not the reader's.

Parsing user input with the wrong locale. 04/03/2026 is 4 March in Britain and April 3 in the US.

Using localized dates in file names or data. They change with the locale and don't sort correctly.

Comparing output across JDK versions character by character. The locale data (CLDR) is updated, and details such as punctuation can change.

Practice

  1. Easy: Print today's date in FULL style for Locale.ITALY, Locale.KOREA and Locale.of("te", "IN").
  2. Harder: Print the seven day names of a week for a given locale, starting with that locale's first day of the week.

Quick check: Dates and locales

4 questions
1What does 3/4/26 mean in the US short format?
2Which call makes a formatter follow a locale?
3Which format should be used to store dates in a file?
4What does FormatStyle.FULL add that LONG doesn't?

Key Takeaways

Was this tutorial helpful?

Lesson 505 of 578