Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I iterate over every week in a year in Java 8?

Tags:

java

java-time

Apologies in advance if I confuse any ISO date related terms here.

I would like to be able to iterate over every week in a given year (say, 2015). I realize that you can calculate the number of weeks between 1/1/2015 and 12/31/2015, but that doesn't conform to the ISO standard of a week. Rather, it gives the number of 7 day periods between two dates. The first ISO week of the year doesn't necessarily start on 1/1/2015.

If I can get the first date of the first week, I believe I can simply iterate via ZonedDateTime.plusWeeks(1) for 52 weeks. You can get the week number of an arbitrary date via the field accessor:

ZonedDateTime date = ZonedDateTime.now();
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int weekNumber = date.get(weekFields.weekOfWeekBasedYear());

Given this, I think it must be possible to get the date of the first day of the first week of a specific year in the Java8 Time API, but I have not found a way to do it yet.

like image 844
monitorjbl Avatar asked Mar 22 '16 15:03

monitorjbl


1 Answers

You can construct a date and adjust it to the first day of week for the first week of the year with the following:

int year = 2016;
WeekFields weekFields = WeekFields.ISO;
LocalDate date = LocalDate.now().with(weekFields.weekBasedYear(), year)
                                .with(weekFields.weekOfWeekBasedYear(), 1)
                                .with(ChronoField.DAY_OF_WEEK, 1);

Thanks to JodaStephen's comment, another way to put it would be to use the IsoFields class.

LocalDate date = LocalDate.now().with(IsoFields.WEEK_BASED_YEAR, year)
                                .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 1)
                                .with(ChronoField.DAY_OF_WEEK, 1);

WeekFields.ISO represents the ISO definition of the week:

The ISO-8601 definition, where a week starts on Monday and the first week has a minimum of 4 days.

The ISO-8601 standard defines a calendar system based on weeks. It uses the week-based-year and week-of-week-based-year concepts to split up the passage of days instead of the standard year/month/day.

Note that the first week may start in the previous calendar year. Note also that the first few days of a calendar year may be in the week-based-year corresponding to the previous calendar year.

From that definition, you can get:

  • weekBasedYear() represents the week-based-year field:

    This represents the concept of the year where weeks start on a fixed day-of-week, such as Monday and each week belongs to exactly one year.

    In this case, we want to set it to the wanted year.

  • weekOfWeekBasedYear() represents the week of week-based-year

    This represents the concept of the count of weeks within the year where weeks start on a fixed day-of-week, such as Monday and each week belongs to exactly one year.

    In this case, we want the first week of the week-based-year so we set it to 1.

  • ChronoField.DAY_OF_WEEK which represents the day of the week. In this case, we want the first day of the week so we set to 1.

Then, with such a date, you can indeed iterate over all weeks of the year by calling LocalDate.plusWeeks(1). The question is: how many times do you need to iterate? There can be more than 52 weeks in a year. There are either 52 or 53 weeks in a week-based-year.

You can retrieve the number of weeks with the following. This call rangeRefinedBy(date) to retrieve the valid values of the week of year field for the given date, and get its maximum.

long maxWeekOfYear = weekFields.weekOfWeekBasedYear().rangeRefinedBy(date).getMaximum();
like image 65
Tunaki Avatar answered Oct 24 '22 10:10

Tunaki