AshwinK
AshwinK

Reputation: 1088

Java LocalDate How to get last week of year as 53rd week instead of 1st week of new year?

If you consider that week will start from Jan 01 of every year & week start is SUNDAY then there will be 53 weeks in 2019. Following above Jan 29,30,31 2019 will be into Week-53 of 2019.

As given in documentation of IsoFields for WEEK_OF_WEEK_BASED_YEAR that all three fields are validated against their range of valid values. The week-of-week-based-year field is validated from 1 to 52 or 53 depending on the week-based-year.

So I'm assuming that following code should give the output as: WEEK_OF_WEEK_BASED_YEAR 53 & WEEK_BASED_YEAR 2019.

But it's giving output as: 1 & 2020

import java.time.LocalDate;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.time.temporal.IsoFields;

public class WeekStartDemo {
    public static void main(String args[]) {
        DateTimeFormatter DATE_FORMATTER = DateTimeFormatter
                .ofPattern("uuuu-MM-dd")
                .withChronology(IsoChronology.INSTANCE)
                .withResolverStyle(ResolverStyle.STRICT);

        LocalDate updatedDate = LocalDate.parse("2019-12-30", DATE_FORMATTER);

        System.out.println(updatedDate.toString());

        System.out.println(updatedDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
        System.out.println(updatedDate.get(IsoFields.WEEK_BASED_YEAR));
    }
}

If I pass the date as 2019-12-28 then it's returning WEEK_OF_WEEK_BASED_YEAR 52 & WEEK_BASED_YEAR 2019. But doesn't work for last week of 2019 (which is 53rd week)

Let me know what I'm missing in above code.

Upvotes: 3

Views: 1626

Answers (4)

Anonymous
Anonymous

Reputation: 86276

    LocalDate date = LocalDate.of(2019, Month.DECEMBER, 30);
    int weekOfYear = date.get(WeekFields.SUNDAY_START.weekOfYear());
    System.out.println(weekOfYear);

Output from this snippet is:

53

I believe that this is the exact difference between WeekFields.weekOfWeekBasedYear() and WeekFields.weekOfYear().

It may also be that your main source of confusion is using the wrong week fields, as Elliott Frisch also mentioned. The ISO week fields that you use define Monday as the first day of the week and week one of the year as the first week containing at least 4 days of the year. In contrast you said that you wanted:

If you consider that week will start from Jan 01 of every year & week start is SUNDAY

From your comments:

… will the new week (Week-01) will always start on Jan 01 of every year ?

Yes it will.

How can I perform minus 1 week on this weekOfYear ? As for Jan 01,2020, weekOfYear will be Week-01 2020. What type of minus 1 week I can perform to get weekOfYear as Week-53 2019 ? I tried with date.minusWeeks(1) but it returns Week-52 2019

    LocalDate dateInWeek1 = LocalDate.of(2020, Month.JANUARY, 3);
    int weekOfYear = dateInWeek1.get(wf.weekOfYear());
    System.out.println(weekOfYear);
    LocalDate dateInPreviousWeek;
    if (weekOfYear == 1) {
        dateInPreviousWeek = dateInWeek1.minusWeeks(1)
                .with(TemporalAdjusters.lastDayOfMonth());
    }
    else {
        dateInPreviousWeek = dateInWeek1.minusWeeks(1);
    }
    System.out.format("%s %2d%n", dateInPreviousWeek, dateInPreviousWeek.get(wf.weekOfYear()));

We need to handle the case of week 1 specially. When subtracting 1 week, we know we are getting into December the previous year. Selecting the last day of the month will give us December 31. This will always be in the last week of the year (usually week 53; occasionally week 54 if in a leap year that begins on a Saturday, I think that years 2000 and 2028 are examples of this).

Upvotes: 1

Elliott Frisch
Elliott Frisch

Reputation: 201447

As I mentioned in the comments, and from your Javadoc link for IsoFields, The week-based-year itself is defined relative to the standard ISO proleptic year. It differs from the standard year in that it always starts on a Monday (not a Sunday). It should be easy enough to find the years with 53 weeks using your posted code, iterate from 1900 to 2300 and parse the WEEK_OF_WEEK_BASED_YEAR for the last day of the given year and print the values where it is 53. Like,

DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd")
        .withChronology(IsoChronology.INSTANCE)
        .withResolverStyle(ResolverStyle.STRICT);

for (int i = 1900; i < 2300; i++) {
    LocalDate updatedDate = LocalDate.parse(String.format("%d-12-31", i), DATE_FORMATTER);
    if (updatedDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) == 53) {
        System.out.println(i);
    }
}

The first few values I get are

1903
1908
1914
1920
1925
1931
1936
1942

skipping ahead a bit...

2009
2015
2020
2026

So this year (2020) has 53 weeks, and 2019 does not.

Upvotes: 2

TobiSH
TobiSH

Reputation: 2921

Based on the ISO-8601 (https://www.cl.cam.ac.uk/~mgk25/iso-time.html) this is correct. 2019 has no calendarweek 53. Week 01 of a year is per definition the first week that has the Thursday in this year, which is equivalent to the week that contains the fourth day of January. As far as I know this is done to avoid a cw 1 without a workday.

Upvotes: 0

Tim Biegeleisen
Tim Biegeleisen

Reputation: 521249

The issue here is that a given year has either 365 or 366 days (the latter for a leap year), which means that every year has either 1 or 2 days extra beyond 52 weeks. The ISO system for week years is what handles this, and it means that sometimes the first week of the year might not start of the 1st of January, nor would the last day of a year fall in the 52nd week. One workaround here would be to just calculate the week starting from the beginning of each year, e.g.

LocalDate firstOfYear = LocalDate.of(2019, Month.JANUARY, 1);
LocalDate updatedDate = LocalDate.of(2019, Month.DECEMBER, 30);

int diff = (int)ChronoUnit.DAYS.between(firstOfYear, updatedDate);
int week = 1 + (diff / 7);
System.out.println("The week number is: " + week);

Upvotes: 0

Related Questions