Java Time API Locale (week of the year)

Howto pass a localization to the new Java Time API?

In this simple example i try to print current week-of-the-year but the result is always wrong.

import java.text.*;
import java.time.*;
import java.time.format.*;
import java.util.*;

//wrong result
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy ww");
System.out.println(LocalDateTime.now(ZoneId.of("Europe/Berlin")).format(formatter));

//this works
System.out.println(new SimpleDateFormat("yyyy ww",Locale.GERMANY).format(new Date()));

Solution 1:

Pass the Locale to ofPattern method of DateTimeFormatter

 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy ww",Locale.GERMANY);
 System.out.println(LocalDateTime.now().format(formatter));

Solution 2:

tl;dr

Use proper formatting pattern, case-sensitive: "YYYY ww".

LocalDate.now( ZoneId.of( "Europe/Berlin" ) )    // Get the current date (date-only value) as seen in the wall-clock time used by the people of a certain region (a time zone).
.format(                                         // Generate a string representing the week and week-based-year according to a particular locale’s definition of ‘week’.
    DateTimeFormatter.ofPattern( "YYYY ww" ).withLocale( Locale.GERMANY )
)

yyyy ww is invalid

The yyyy coding in java.time means calendar-year. Following that with ww for a week number of a standard ISO 8601 week-based year is misleading and nonsensical.

You should be combining week-number with week-based-year number rather than calendar-year number. The formatting code for that is uppercase YYYY. So you would want YYYY ww.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "YYYY ww" ) ;

Locale affects YYYY not yyyy

Since yyyy lowercase means calendar year, specifying a Locale has no effect. Use YYYY uppercase, as mentioned above, if you want the locale-defined week-based-year.

For more info, see the Question: Java Time's week-of-week-based-year pattern parsing with DateTimeFormatter

Locale locale = Locale.GERMANY ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "YYYY ww" ).withLocale( locale ) ;
LocalDate ld = LocalDate.now( ZoneId.of( "Europe/Berlin" ) ) ; // Or "Africa/Tunis", "Pacific/Auckland" etc. Time zone is unrelated (orthogonal) to locale.
String output = ld.format( f ) ;

Standard week

Perhaps you want the ISO 8601 standard definition of week rather than a locale-defined definition. This is where week # 1 contains the first Thursday of the calendar year, and starts on a Monday, for a total of 52 or 53 weeks per year.

ISO 8601 defines a standard format for week-based year & week. You may want to consider using the standard format rather than your custom format.

Standard format is yyyy-Www for the year-week, and yyyy-Www-d to also display the day-of-week number where 1-7 is Monday-Sunday. For example, 2012-W48-6 is 2012-12-01, a Saturday (day-of-week # 6).

The DateTimeFormatter class comes with a predefined format for this, DateTimeFormatter.ISO_WEEK_DATE.

String input = "2012-W48-6";
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.ISO_WEEK_DATE );
System.out.println( ld );

2012-12-01

You can generate such a string.

String output = ld.format( DateTimeFormatter.ISO_WEEK_DATE );

2012-W48-6

If you want the entire week, without the day-of-week, just truncate the string.

String output = ld.format( DateTimeFormatter.ISO_WEEK_DATE ).substring( 0 , 8 ) ;

2012-W48

YearWeek

If you will be doing much of this work at all, I suggest adding the ThreeTen-Extra library to your project. That library offers many handy classes, one of which is YearWeek to represent the standard ISO 8601 week as a whole.

YearWeek yw = YearWeek.parse( "2012-W48" ) ;

Get the current week.

YearWeek yw = YearWeek.now( ZoneId.of( "Europe/Berlin" ) )     

yw.toString(): 2012-W48


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, and later
  • Built-in.
  • Part of the standard Java API with a bundled implementation.
  • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
  • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
  • Later versions of Android bundle implementations of the java.time classes.
  • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.