Reputation: 339372
For a given date, such as 2018-03-05, how do I detect that it is the first Monday of that month?
And after determining that fact, how do I calculate the same nth day-of-week in the month for the following six months? For example, Monday 2018-04-02 and Monday 2018-05-03.
Just like this Question but using Java.
I tried this code, but do not get the results I expect. What I expect:
[2018-04-02, 2018-05-07, 2018-06-04, 2018-07-02, 2018-08-06, 2018-09-03]
Perhaps I misunderstand ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH
.
LocalDate ld = LocalDate.parse( "2018-03-05" );
int alignedDayOfWeekInMonth = ld.get( ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH );
DayOfWeek dayOfWeek = ld.getDayOfWeek();
YearMonth ym = YearMonth.from( ld );
int countMonths = 6;
List < LocalDate > localDates = new ArrayList <>( countMonths );
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( alignedDayOfWeekInMonth , dayOfWeek );
for ( int i = 1 ; i <= countMonths ; i++ ) {
LocalDate firstOfMonth = ym.plusMonths( i ).atDay( 1 );
LocalDate localDate = firstOfMonth.with( ta );
localDates.add( localDate );
}
Dump to console.
System.out.println( "ld.toString(): " + ld );
System.out.println( "alignedDayOfWeekInMonth: " + alignedDayOfWeekInMonth );
System.out.println( "dayOfWeek.toString(): " + dayOfWeek );
System.out.println("ym.toString(): " + ym);
System.out.println( "localDates: " + localDates );
When run.
ld.toString(): 2018-03-05
alignedDayOfWeekInMonth: 5
dayOfWeek.toString(): MONDAY
ym.toString(): 2018-03
localDates: [2018-04-30, 2018-06-04, 2018-07-02, 2018-07-30, 2018-09-03, 2018-10-01]
A related Question, but uses the legacy date-time classes rather than the modern java.time classes: Find which nth occurrence of a day in a month for a date in Java
Upvotes: 3
Views: 1236
Reputation: 86324
This simple change fixes your program:
int alignedWeekOfMonth = ld.get(ChronoField.ALIGNED_WEEK_OF_MONTH);
I have renamed your variable alignedDayOfWeekInMonth
, though, so you need to carry the name change through to the two places where you are using it. Then your program prints:
ld.toString(): 2018-03-05
alignedWeekOfMonth: 1
dayOfWeek.toString(): MONDAY
ym.toString(): 2018-03
localDates: [2018-04-02, 2018-05-07, 2018-06-04, 2018-07-02, 2018-08-06, 2018-09-03]
The list agrees with what you said you expected.
It seems you were correct in that you had misunderstood ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH
. With reference to the concept of aligned weeks in month March 5 is the 5th day in the 1st aligned week. The chrono field you used gave you the 5, not the 1. To get the 1, use ChronoField.ALIGNED_WEEK_OF_MONTH
instead. Then everything works.
Upvotes: 2
Reputation:
You used a wrong field for TemporalAdjusters.dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)
since ordinal
is the week within the month but you used ALIGNED_DAY_OF_WEEK_IN_MONTH
¹.
But how to you get the week of month in java.time?:
For this you need WeekFields
, the most common is WeekFields.ISO
.
Now you can create a ChronoField
for week of month with WeekFields.ISO.weekOfMonth();
.
With your code this should look like:
LocalDate ld = LocalDate.parse( "2018-03-05" );
DayOfWeek dayOfWeek = ld.getDayOfWeek();
int ordinal = ld.get(WeekFields.of(dayOfWeek, 7).weekOfMonth());
YearMonth ym = YearMonth.from( ld );
int countMonths = 6;
List < LocalDate > localDates = new ArrayList <>( countMonths );
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( ordinal, dayOfWeek );
for ( int i = 1 ; i <= countMonths ; i++ ) {
LocalDate firstOfMonth = ym.plusMonths( i ).atDay( 1 );
LocalDate localDate = firstOfMonth.with( ta );
localDates.add( localDate );
}
¹: ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH
is the n-th day in a week which doesn't start with a fixed DAY_OF_WEEK like Monday but with the first day of the month.
Upvotes: 1
Reputation: 52003
This code isn't fancy at all but it works :)
public static void main(String[] args) {
LocalDate ld = LocalDate.parse( "2018-03-04" );
DayOfWeek dayOfWeek = DayOfWeek.WEDNESDAY;
LocalDate first = ld.withDayOfMonth(1);
List<LocalDate> firstDays = new ArrayList<>();
//I deliberately included the start date in the loop.
//Easily fixed if it shouldn't be included
for (int i = 0; i <= 6; i++) {
LocalDate firstDay = getFirstDay(first.plusMonths(i), dayOfWeek);
firstDays.add(firstDay);
}
}
static LocalDate getFirstDay(LocalDate date, DayOfWeek searchedDay) {
LocalDate temp = date;
int i = 0;
while (temp.getDayOfWeek() != searchedDay) {
temp = date.plusDays(i++);
}
return temp;
}
Upvotes: 0