The Answer by Jon Skeet is correct and should be accepted. You are confusing week-of-year with a calendar-year versus a week-based-year.
Week-based Year
If we are talking about the standard ISO 8601 definition of a week, that means:
- Week runs Monday-Sunday.
- Week # 1 is the week containing the first Thursday of the calendar year.
Say that first Thursday is January 2, which means Wednesday the day before is the 1st, and the prior Monday & Tuesday are the last days of the prior calendar year but are in the following week-based year. So you cannot mix up calendar year numbers with week-based year numbers.
Avoid legacy date-time classes
Also, you are using troublesome old date-time classes such as Calendar
which are now legacy, supplanted by the java.time classes.
LocalDate
First get the current date. The LocalDate
class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 3-4 letter abbreviation such as EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
IsoFields
Get the ISO 8601 week number by using the IsoFields
class. And get the year number of the week-based year calendar.
int weekNumber = today.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int yearNumberOfWeekBasedYear = today.get( IsoFields.WEEK_BASED_YEAR ); // Around end/beginning of year, may be different than calendar-year number.
Let's take another specific example, the first day of 2017. Notice how its calendar-year is of course 2017 but because it lands on a Sunday it is in the last week (# 52) of the week-based year 2016 (not 2017!).
LocalDate firstOf2017 = LocalDate.of ( 2017 , Month.JANUARY , 1 );
DayOfWeek firstOf2017DayOfWeek = firstOf2017.getDayOfWeek ();
int weekNumber = firstOf2017.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int yearNumberOfWeekBasedYear = firstOf2017.get ( IsoFields.WEEK_BASED_YEAR ); // Around end/beginning of year, may be different than calendar-year number.
int yearNumberOfCalendarYear = firstOf2017.getYear ();
Dump to console.
System.out.println ( "firstOf2017.toString(): " + firstOf2017 );
System.out.println ( "firstOf2017DayOfWeek.toString(): " + firstOf2017DayOfWeek );
System.out.println ( "weekNumber: " + weekNumber );
System.out.println ( "yearNumberOfWeekBasedYear: " + yearNumberOfWeekBasedYear );
System.out.println ( "yearNumberOfCalendarYear: " + yearNumberOfCalendarYear );
firstOf2017.toString(): 2017-01-01
firstOf2017DayOfWeek.toString(): SUNDAY
weekNumber: 52
yearNumberOfWeekBasedYear: 2016
yearNumberOfCalendarYear: 2017
Week math
You can subtract weeks with the LocalDate
class.
LocalDate ld = firstOf2017.minusWeeks( 3 );
YearWeek
You will probably want to add the ThreeTen-Extra library to your project to access the YearWeek
class.
YearWeek yearWeek = YearWeek.of( 2016 , 3 ); // Week # 3 of week-based year 2016.
Get one of the days of that week by specifying a DayOfWeek
enum object.
LocalDate ld = yearWeek.atDay( DayOfWeek.MONDAY );
2016-01-18
Add three weeks.
LocalDate threeWeeksLater = ld.plusWeeks( 3 );
2016-02-08
Get that new date’s week number.
YearWeek yearWeek2 = YearWeek.from( threeWeeksLater );
int weekNumber = yearWeek2.getWeek();
int yearNumberOfWeekBasedYear = yearWeek2.getYear();
Generate standard ISO 8601 string representation.
String output = yearWeek2.toString();
2016-W06
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.
Where to obtain the java.time classes?
- Java SE 8 and SE 9 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 SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
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.