Skip to content

Commit b421d1c

Browse files
authored
Merge pull request #803 from focus-shift/improve-relative-to-weekday-in-month-parser-code
Improve relative to weekday in month parser code
2 parents d217d7d + f5d05c1 commit b421d1c

2 files changed

Lines changed: 46 additions & 11 deletions

File tree

jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/RelativeToWeekdayInMonthParser.java

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,52 @@
66
import de.focus_shift.jollyday.core.parser.functions.FindWeekDayInMonth;
77
import de.focus_shift.jollyday.core.parser.predicates.ValidLimitation;
88
import de.focus_shift.jollyday.core.spi.Holidays;
9-
import de.focus_shift.jollyday.core.spi.Relation;
9+
import de.focus_shift.jollyday.core.spi.RelativeToWeekdayInMonth;
1010

1111
import java.time.LocalDate;
1212
import java.time.Year;
1313
import java.util.List;
1414

15+
import static de.focus_shift.jollyday.core.spi.Relation.BEFORE;
1516
import static java.util.stream.Collectors.toList;
1617

1718
/**
18-
* <p>
1919
* RelativeToWeekdayInMonthParser class.
20-
* </p>
20+
* <p>
21+
* Resolves the holiday date for a given relative-to-weekday-in-month configuration.
22+
* <p>
23+
* This method works as follows:
24+
* <ul>
25+
* <li>Finds the base date in the month using the weekdayInMonth configuration.</li>
26+
* <li>Calculates the difference in days to the target weekday, considering the direction (BEFORE or AFTER).</li>
27+
* <li>Returns a Holiday for the resulting date.</li>
28+
* </ul>
2129
*/
2230
public class RelativeToWeekdayInMonthParser implements HolidayParser {
2331

2432
@Override
2533
public List<Holiday> parse(final Year year, final Holidays holidays) {
2634
return holidays.relativeToWeekdayInMonth().stream()
2735
.filter(new ValidLimitation(year))
28-
.map(rwm -> {
29-
LocalDate date = new FindWeekDayInMonth(year).apply(rwm.weekdayInMonth()).plusDays(1);
30-
int direction = rwm.when() == Relation.BEFORE ? -1 : 1;
31-
while (date.getDayOfWeek() != rwm.weekday()) {
32-
date = date.plusDays(direction);
33-
}
34-
return new CreateHoliday(date).apply(rwm);
35-
})
36+
.map(relativeToWeekdayInMonth -> resolveHolidayForRelativeToWeekdayInMonth(year, relativeToWeekdayInMonth))
3637
.collect(toList());
3738
}
39+
40+
private Holiday resolveHolidayForRelativeToWeekdayInMonth(final Year year, final RelativeToWeekdayInMonth rwm) {
41+
final LocalDate baseDate = new FindWeekDayInMonth(year).apply(rwm.weekdayInMonth());
42+
43+
final int currentDayValue = baseDate.getDayOfWeek().getValue();
44+
final int targetDayValue = rwm.weekday().getValue();
45+
final int direction = (rwm.when() == BEFORE ? -1 : 1);
46+
47+
int daysDifference = targetDayValue - currentDayValue;
48+
if (direction < 0 && daysDifference >= 0) {
49+
daysDifference -= 7;
50+
} else if (direction > 0 && daysDifference <= 0) {
51+
daysDifference += 7;
52+
}
53+
54+
final LocalDate resultDate = baseDate.plusDays(daysDifference);
55+
return new CreateHoliday(resultDate).apply(rwm);
56+
}
3857
}

jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/RelativeToWeekdayInMonthParserTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import static de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY;
2626
import static de.focus_shift.jollyday.core.spi.Limited.YearCycle.EVERY_YEAR;
27+
import static de.focus_shift.jollyday.core.spi.Occurrence.FIRST;
2728
import static de.focus_shift.jollyday.core.spi.Occurrence.LAST;
2829
import static java.time.DayOfWeek.MONDAY;
2930
import static java.time.DayOfWeek.TUESDAY;
@@ -53,6 +54,21 @@ void ensureThatRelativeToWeekdayInMonthWithRelationBeforeIsValid(final Relation
5354
assertThat(calculatedHoliday.get(0).getDate()).isEqualTo(expectedLocalDate);
5455
}
5556

57+
@ParameterizedTest
58+
@CsvSource({"BEFORE,2025-03-31", "AFTER,2025-04-14"})
59+
void ensureThatRelativeToWeekdayInMonthWithRelationBeforeIsValidAndIsOnSameWeekday(final Relation relation, final LocalDate expectedLocalDate) {
60+
61+
final Year year = Year.of(2025);
62+
final FixedWeekdayInMonth fixedWeekdayInMonth = getFixedWeekdayInMonth(APRIL, MONDAY, FIRST);
63+
final RelativeToWeekdayInMonth relativeToWeekdayInMonth = getRelativeToWeekdayInMonth(MONDAY, relation, fixedWeekdayInMonth, year, year);
64+
65+
final RelativeToWeekdayInMonthParser sut = new RelativeToWeekdayInMonthParser();
66+
when(holidays.relativeToWeekdayInMonth()).thenReturn(List.of(relativeToWeekdayInMonth));
67+
68+
final List<Holiday> calculatedHoliday = sut.parse(year, holidays);
69+
assertThat(calculatedHoliday.get(0).getDate()).isEqualTo(expectedLocalDate);
70+
}
71+
5672
@Nested
5773
class LimitedTests {
5874

0 commit comments

Comments
 (0)