Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 LocalDate: Determine What Monday of the Month its (1st, 2nd, 3rd, etc)

I'm trying to figure out how to determine whether a particular Monday is the first, second, third or fourth Monday of a given month. I've figured out how to get the next Monday and the Week of the of month that resides in using the LocalDate class.

LocalDate now = LocalDate.of(2018, 2, 1);
LocalDate nextMonday = now.with(next(DayOfWeek.MONDAY));
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int week = nextMonday.get(weekFields.weekOfMonth());

Case in the example above, the code gets the next Monday and the week it resides in. Week is the second week of Feb, but that Monday is not the second Monday, it's the first. Any help with this would be greatly appreciated.

like image 413
Joseph Freeman Avatar asked Dec 19 '22 01:12

Joseph Freeman


2 Answers

You should not use your own arithmetic for this. Use the built-in functionality:

    int week = nextMonday.get(ChronoField.ALIGNED_WEEK_OF_MONTH);

With the date from your code this yields:

1

Which means that the Monday you got (February 5) is the 1st Monday of the month. Also you don’t need any WeekFields because the first Monday of the month is the first Monday of the month no matter which day is the first day of week, or how weeks of the year are numbered.

Date arithmetic is often complicated and easy to get wrong. Which also means that even if you finally get your calculation right, it is hard for a reader to convince herself/himself that your code is correct. So it is always better to use the built-in functionality that we trust to be tested and which uses explanatory names rather than numbers like 1 and 7.

You may be surprised that the field to use is called ALIGNED_WEEK_OF_MONTH. Think of aligned weeks as a week that begins on the 1st of the month no matter the day-of-week, and the following weeks right after each other. In February 2018, the first aligned week goes from Thursday, Feb 1 to Wednesday, Feb 7. The following aligned weeks begin on Thursdays Feb 8, Feb 15 and Feb 22. Obviously the first Monday of the month falls in aligned week 1, the 2nd Monday in aligned week 2, etc. Therefore it works to use ALIGNED_WEEK_OF_MONTH.

like image 74
Ole V.V. Avatar answered Apr 09 '23 21:04

Ole V.V.


Edit: You should take Ole V. V's answer (ChronoField.ALIGNED_WEEK_OF_MONTH) instead of this answer.

You could figure out what day of the month it is, divide by 7, and add 1:

LocalDate nextMonday = now.with(next(DayOfWeek.MONDAY));
int weekNo = ((nextMonday.getDayOfMonth()-1) / 7) +1;

For example, this code:

LocalDate now = LocalDate.of(2018, 2, 1);
for(int i = 0; i < 10; i++) {
    now = now.with(next(DayOfWeek.MONDAY));
    int weekNo = ((now.getDayOfMonth()-1) / 7) +1;
    System.out.println("Date : " + now + " == " + weekNo);
}

Prints out the following, which is what I believe you want...

Date : 2018-02-05 == 1
Date : 2018-02-12 == 2
Date : 2018-02-19 == 3
Date : 2018-02-26 == 4
Date : 2018-03-05 == 1
Date : 2018-03-12 == 2
Date : 2018-03-19 == 3
Date : 2018-03-26 == 4
Date : 2018-04-02 == 1
Date : 2018-04-09 == 2
like image 35
Todd Avatar answered Apr 09 '23 20:04

Todd