10
votes

I would like to get the number of weeks in any given year. Even though 52 is accepted as a generalised worldwide answer, the calendars for 2015, 2020 and 2026 actually have 53 weeks.

Is there any way that I can calculate this, or any functions that will help me out?

10
General comment for all which doesn't exactly answer the question above but is useful to know: To understand why the Calendar class returns 53 for "number of weeks in a year" you have to understand how the getFirstDayOfWeek() and getMinimalDaysInFirstWeek() methods are used in the calculation. If the "first day of the week" is specified as Monday for example and the "minimal days in first week" is 4 and the first Monday of the year is on 5th January, then the week preceding 5th January is classed as part of that year. - Adil Hussain

10 Answers

15
votes

Quick one liner:

Integer weeksOfYear = Calendar.getInstance().getActualMaximum(Calendar.WEEK_OF_YEAR);
13
votes

According to the wikipedia article on ISO week date format, You can calculate it using following code.

    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, 2015);
    cal.set(Calendar.MONTH, Calendar.DECEMBER);
    cal.set(Calendar.DAY_OF_MONTH, 31);

    int ordinalDay = cal.get(Calendar.DAY_OF_YEAR);
    int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1; // Sunday = 0
    int numberOfWeeks = (ordinalDay - weekDay + 10) / 7;
    System.out.println(numberOfWeeks);

Update:

Seems the answer from @Samuel https://stackoverflow.com/a/40174287/201986 is better and free from the bug mentioned by Luca

10
votes

You can code yourself with the following information from ISO week date.

On average, a year has 53 weeks every 5.6 years.

The following 71 years in a 400-year cycle (add 2000 for current years) have 53 weeks. Years not listed have 52 weeks.

004, 009, 015, 020, 026, 032, 037, 043, 048, 054, 060, 065, 071, 076, 082, 088, 093, 099, 105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167, 172, 178, 184, 189, 195, 201, 207, 212, 218, 224, 229, 235, 240, 246, 252, 257, 263, 268, 274, 280, 285, 291, 296, 303, 308, 314, 320, 325, 331, 336, 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398.

You can use the above information to return 52 or 53 accordingly :)

6
votes

I would like to give my take on usage of the new Date API in Java 8 with the following ready to run code:

private static long getNumberOfWeeksInYear(LocalDate date) {
    LocalDate middleOfYear = date.withDayOfMonth(1).withMonth(6);
    return middleOfYear.range(WeekFields.ISO.weekOfWeekBasedYear()).getMaximum();
}

public static void main(String[] args) {
    for (int year = 2000; year < 2400; year++) {
        long numberOfWeeks = getNumberOfWeeksInYear(LocalDate.of(year, 1, 1));
        if (numberOfWeeks != 52) {
            System.out.println(year + " has " + numberOfWeeks + " weeks");
        }
    }
}

The output is:

2004 has 53 weeks
2009 has 53 weeks
2015 has 53 weeks
2020 has 53 weeks
2026 has 53 weeks
2032 has 53 weeks
...

And so on...

The date.withDayOfMonth(1).withMonth(6); trick is because omitting this results in slightly different output if LocalDate.of(year, 1, 1) is passed:

2004 has 53 weeks
2005 has 53 weeks
...

I am still new to the Java 8 date API, but my I am pretty sure this behaviour is becuase 2005-01-01 is part of week 53 of 2014. This makes date.range(WeekFields.ISO.weekOfWeekBasedYear()).getMaximum() return the number of weeks for the week based year of 2014.

4
votes
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, 2015);
    cal.set(Calendar.MONTH, Calendar.DECEMBER);
    cal.set(Calendar.DAY_OF_MONTH, 31);
    System.out.println(cal.get(Calendar.WEEK_OF_YEAR));
2
votes

Link to answer

gregorianCalendar.set(year, 12, 31);
int totalWeeks = gregorianCalendar.getMaximum(Calendar.WEEK_OF_YEAR);
2
votes

@Manjula Weerasinge answer actually introduce a bug for 2016. Here's a better solution.

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
GregorianCalendar gregorianCalendar = new GregorianCalendar();

int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (gregorianCalendar.isLeapYear(year)){
   if (weekDay == Calendar.THURSDAY || weekDay == Calendar.WEDNESDAY)
      return 53;
   else
      return 52;
} else {
   if (weekDay == Calendar.THURSDAY)
      return 53;
   else
      return 52;
}
1
votes

This method calculates the number of weeks a ISO year using the Joda time library.

    import org.joda.time.DateTime;
    import org.joda.time.DateTimeZone;

    public static int weeksInYear(int year) {
        return new DateTime(DateTimeZone.forID("America/Los_Angeles"))
            .withWeekyear(year + 1)
            .withWeekOfWeekyear(1)
            .minusWeeks(1)
            .getWeekOfWeekyear();
    }
0
votes

For ISO date format, we can calculate number of weeks as follows:

int getNoOfWeeks(int year) {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    cal.setMinimalDaysInFirstWeek(4);
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    return cal.getActualMaximum(Calendar.WEEK_OF_YEAR);
}

So, for year = 2018, it will return 52, for 2019, it will also return 52, but for 2020 it will return 53 as ISO year has 52 or 53 weeks.

0
votes

According to ISO standards, a week starts on a Monday and the first week of the year is the week with the first Thursday of the year.

Following this logic, 28th of December always lies in the last week of the year.

int maxWeekInYear(int year) {
    return LocalDate.of(year, 12, 28).get(WeekFields.ISO.weekOfWeekBasedYear());
}