Java – Locale-independent year, week, and date format

Locale-independent year, week, and date format… here is a solution to the problem.

Locale-independent year, week, and date format

I want to print Instant in a locale-independent way, with ISO set to the first day of the week (Monday) and the minimum number of days of the week (4).

My current setup is:

private String print(Instant i) {
    DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("YYYY-ww")
            .withZone(UTC);
    return formatter.format(i);
}

@Test
public void test() {
    System.out.format("First day of week      : %s%n",
            WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
    System.out.format("Min days in 1st week   : %s%n",
            WeekFields.of(Locale.getDefault()).getMinimalDaysInFirstWeek());
    Instant instant = Instant.parse("1998-12-31T00:00:00Z");
    System.out.println(print(instant));
}

For the system locale “en_US”, test print:

First day of week      : SUNDAY
Min days in 1st week   : 1
1999-01

For the system locale “de_DE”, test printing:

First day of week      : MONDAY
Min days in 1st week   : 4
1998-53

The “de_DE” locale is consistent with the ISO settings, and I know I can set the formatter to

DateTimeFormatter formatter = DateTimeFormatter
        .ofPattern("YYYY-ww")
        .withZone(UTC)
        .withLocale(Locale.GERMANY);

But can I do this without specifying binds to any locale for a particular country? I found java.time.temporal.WeekFields#ISO:

public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);

This is what I want, but I don’t know how to use it with DateTimeFormatter.

Solution

You can use the corresponding fields for java.time.format.DateTimeFormatterBuilder and WeekFields.ISO

The code is:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
     append week year
    .appendValue(WeekFields.ISO.weekBasedYear(), 4)
     separator
    .appendLiteral('-')
     append week of week year field
    .appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
     create formatter
    .toFormatter().withZone(ZoneOffset.UTC);

Instead of creating a new instance of WeekFields (using WeekFields.of(locale)), just use WeekFields.ISO

System.out.format("First day of week      : %s%n", WeekFields.ISO.getFirstDayOfWeek());
System.out.format("Min days in 1st week   : %s%n", WeekFields.ISO.getMinimalDaysInFirstWeek());
Instant instant = Instant.parse("1998-12-31T00:00:00Z");
System.out.println(formatter.format(instant));

The output is:

First day of week : MONDAY
Min days in 1st week : 4
1998-53


Even if I change the locale of the formatter :

formatter = formatter.withLocale(Locale.GERMANY);

Or:

formatter = formatter.withLocale(Locale.ENGLISH);

The output remains unchanged.

Related Problems and Solutions