Difference between year-of-era and week-based-year?

Solution 1:

That's year value for "year-week" style dates, as in 2006-W52. It may be off the year-of-era value by +1 or -1 if the week in question straddles year boundary.

See http://en.wikipedia.org/wiki/ISO_8601#Week_dates

Solution 2:

tl;dr

table showing the calendar year of 2019-12-30 is 2019 while the week-based year is 2020

Table showing the length in days and weeks for a calendar year and a week-based year, 365 or 366 days versus 364 or 371, and 52 partial weeks versus 52 or 53 whole weeks.

Details

Some other Answers are quite interesting, but complicated. Here is a hopefully simpler Answer to get your oriented.

y and u (lowercase)

The y character for year-of-era is simply the calendar year, the regular year used across the West and much of the world, based on the Gregorian calendar.

The DateTimeFormatter class also uses a u for the nearly the same thing. For contemporary dates, there is no difference. For the nitty-gritty details, see uuuu versus yyyy in DateTimeFormatter formatting pattern codes in Java?.

For the regular dates we use in quotidian life, you would parse or generate text representing date values using a formatting pattern such as:

DateTimeFormatter.ofPattern( "dd/MM/yyyy" ) ;

…or…

DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) ;

In either case, Monday, December 30, 2019 would be parsed like this:

LocalDate localDate = LocalDate.parse( "30/12/2019" ) ;

localDate.toString(): 2019-12-30

Y (uppercase)

Many people in various industries find it useful to track time by week, assigning a number to each week of the year.

There are various ways to define a week, such as starting on a Sunday or on a Monday. So there are various ways to define a week of the year. Does week # 1 have the January 1st? Or does week # 1 have the first Sunday of the year?

The ISO 8601 standard defines a week as starting on a Monday. Week number 1 has the first Thursday of the new calendar year.

This definition means week-based year has either 52 or 53 whole weeks, always 7-days long (Monday-Sunday),for a year length of either 364 days or 371 days. In contrast, a calendar year has either 365 or 366 days crossing 52 partial weeks.

So the date 2019-12-30 (Monday, December 30, 2019) is actually in the first week of week-based year of 2020.

calendar showing week # 1 of 2020, starting with December 30, 2019.

  • If you need to generate or parse the week-based year value of 2020, use uppercase YYYY for that date of 2019-12-30 in your formatting pattern.
  • If you want the calendar year of 2019-12-30, that is 2019, use lowercase yyyy.

ISO 8601 format

The ISO 8601 standard defines a specific format for representing a date within a week of a week-based year: YYYY-Www-d where the YYYY is the week-based year, the -W is fixed, the ww represents the week number 1-52 or 1-53, and the d represents a day-of-week running 1-7 for Monday-Sunday.

So Monday, December 30, 2019 is: 2020-W01-1 meaning week-based year 2020, first week of the year, and first day of the week (Monday).

To parse the ISO 8601 week with day-of-week number, we can use DateTimeFormatter. No need to define a formatting pattern with YYYY, as this work has already been done for you. Use the builtin DateTimeFormatter.ISO_WEEK_DATE.

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

2020-W01-1

Likewise, parsing.

LocalDate localDate = 
    LocalDate.parse( 
        "2020-W01-1" , 
        DateTimeFormatter.ISO_WEEK_DATE
    )
;

localDate.toString(): 2019-12-30

ThreeTen-Extra

The ThreeTen-Extra library adds functionality to the java.time classes built into Java.

org.threeten.extra.YearWeek

That library provides the YearWeek class. Just what you need if you are working with weeks of week-based year according to the ISO 8601 definition of a week and week-based year.

This class can translate back and forth between the regular date format and the week-oriented format.

LocalDate localDate = LocalDate.of( 2019 , Month.DECEMBER , 30 ) ;  // Monday 2019-12-30. Its week-based year is 2020. 
YearWeek yearWeek = YearWeek.from( localDate ) ;
String wFormatted = yearWeek.toString() ;

2020-W01

Get a date from that.

LocalDate localDate = yearWeek.atDay( DayOfWeek.MONDAY ) ;

localDate.toString(): 2019-12-30