Search code examples
javacalendardayofweek

Calendar returns wrong Week of the year


I want to get this current week on the day of 9/10/2018 as the 42 week of the year after setting the First Day of the week to Sunday. Still I get the output as 41 from the below snippet

 Calendar c = Calendar.getInstance();
 c.setFirstDayOfWeek(Calendar.SUNDAY);
 System.out.println( c.get(Calendar.WEEK_OF_YEAR)  );

Am I missing something here?

Background: Our week start can be variable. Our configuration has the ability to let users decide the first day of the week.


Solution

  • Sorry if I’m too persistent. I still think you should leave the calculation to a custom WeekFields object. If I understood your comment correctly, you want:

        final int daysPerWeek = DayOfWeek.values().length; // A wordy way of writing 7 :-)
        WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, daysPerWeek);
        int customWeekNumber = date.get(customWeekFields.weekOfWeekBasedYear());
    

    To test whether this agrees with what you are already doing I wrote the following method:

    static void printWeekNumber(DayOfWeek firstDayOfWeek, LocalDate date) {
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("EEE uuuu-MM-dd", Locale.ENGLISH);
        final int daysPerWeek = DayOfWeek.values().length;
    
        // Week number according to your comment: “using the Temporal adjusters
        // I am getting the date on the last day of the week.
        // After that dividing the Day of the Year from the API by 7”
        DayOfWeek lastDayOfWeek = firstDayOfWeek.minus(1);
        int askersCommentWeekNumber = date
                .with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
                .getDayOfYear()
                        / daysPerWeek;
    
        // My suggested way of calculating the same week number
        WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, daysPerWeek);
        int customWeekNumber = date.get(customWeekFields.weekOfWeekBasedYear());
    
        System.out.format(Locale.ENGLISH, "Week begins on %-8s Date is %s. Week %2d or %2d, agree? %s%n", 
                firstDayOfWeek, date.format(dateFormatter), 
                askersCommentWeekNumber, customWeekNumber, 
                askersCommentWeekNumber == customWeekNumber);
    }
    

    To make it easier to check the calculations by hand, I have picked a date in January in different years:

        printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2017, Month.JANUARY, 9));
        printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2017, Month.JANUARY, 9));
        printWeekNumber(DayOfWeek.THURSDAY, LocalDate.of(2017, Month.JANUARY, 9));
        printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2018, Month.JANUARY, 9));
        printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2018, Month.JANUARY, 9));
        printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2019, Month.JANUARY, 9));
        printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2019, Month.JANUARY, 9));
    

    Output:

    Week begins on SUNDAY   Date is Mon 2017-01-09. Week  2 or  2, agree? true
    Week begins on MONDAY   Date is Mon 2017-01-09. Week  2 or  2, agree? true
    Week begins on THURSDAY Date is Mon 2017-01-09. Week  1 or  1, agree? true
    Week begins on SUNDAY   Date is Tue 2018-01-09. Week  1 or  1, agree? true
    Week begins on MONDAY   Date is Tue 2018-01-09. Week  2 or  2, agree? true
    Week begins on SUNDAY   Date is Wed 2019-01-09. Week  1 or  1, agree? true
    Week begins on MONDAY   Date is Wed 2019-01-09. Week  1 or  1, agree? true
    

    Please check whether the results are as you want them, though. For the example in your question, the result is neither 41 nor 42:

        printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2018, Month.OCTOBER, 9));
    
    Week begins on SUNDAY   Date is Tue 2018-10-09. Week 40 or 40, agree? true
    

    Edit: If you want ISO 8601 week numbers, use date.get(WeekFields.ISO.dayOfWeek()). If you want your custom first day of week and 4 days in the first week as in ISO 8601, use:

        WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, 4);