I need to find the next n Fridays but want to exclude 4th and possibly 5th Fridays, i.e I want to get the next n Fridays which are 1st, 2nd or 3rd of each month. I have found a way to stream over the next n Fridays (example next 10 Fridays):
LocalDate now = LocalDate.now();
Stream.iterate(now , localDate -> localDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)))
.skip(1) // skip today
.limit(10)
.forEach(System.out::println);
Output:
2021-10-22
2021-10-29
2021-11-05
2021-11-12
2021-11-19
2021-11-26
2021-12-03
2021-12-10
2021-12-17
2021-12-24
But I need to exclude for example 2021-10-22
& 2021-10-29
because they are 4th and 5th Friday of October. Similarly 2021-11-26
& 2021-12-24
because they are not 1st, 2nd or 3rd Fridays.
I have searched SO and found some ways to calculate nth Friday of a month, for example this one
public static LocalDate nthFridayOfMonth(LocalDate localDate, int week) {
return localDate.with(TemporalAdjusters.dayOfWeekInMonth(week, DayOfWeek.FRIDAY));
}
which returns for a given date the nth Friday.
How to modify this method so that it returns a boolean if a given LocalDate is a first, second or third Friday of a month? Or use this method to implement another method which does what I need?
Ideally I want to use the stream above and use a method, which returns a boolean as a filter:
LocalDate now = LocalDate.now();
Stream.iterate(now , localDate -> localDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)))
.skip(1) // skip today
.filter(d -> is1st2ndOr3rdFriday(d))
.limit(10)
.forEach(System.out::println);
to get
2021-11-05
2021-11-12
2021-11-19
2021-12-03
2021-12-10
2021-12-17
2022-01-07
2022-01-14
2022-01-21
2022-02-04
Appreciate any help on how to implement the filter method boolean is1st2ndOr3rdFriday(LocalDate d) {}
CodePudding user response:
You can get the ALIGNED_WEEK_OF_MONTH
temporal field of the local date, and check if it is ≤ 3.
Stream.iterate(now , localDate -> localDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)))
.skip(1) // skip today
.filter(x -> x.get(ChronoField.ALIGNED_WEEK_OF_MONTH) <= 3)
.limit(10)
.forEach(System.out::println);
CodePudding user response:
Another solution : you can GroupBy month your dates ( to Map<Month, List< LocalDate > > ) , then for every month key if there are more than 3 date , remove it , and return the result :
public static void main(String[] args) {
// initialize your date here:
LocalDate now = LocalDate.now();
// Grouping Dates By Month
Map<Month, List<LocalDate>> map = Stream
.iterate(LocalDate.of(now.getYear(), now.getMonth(), 1),
localDate -> localDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)))
.limit(20).collect(Collectors.groupingBy(element -> element.getMonth()));
// delete the 4 or 5 fridays
map.forEach((k, v) -> {
if (v.size() > 3)
v.removeIf(e -> e.isBefore(now) || v.indexOf(e) > 2);
});
// print results sorted
Stream.of(map.values()).flatMap(e -> e.stream()).flatMap(List::stream).sorted().limit(10)
.forEach(System.out::println);
}
Output
2021-11-05
2021-11-12
2021-11-19
2021-12-03
2021-12-10
2021-12-17
2022-01-07
2022-01-14
2022-01-21
2022-02-04