isNthDayOfMonthInRange method
Returns true if the nth occurrence of dayOfWeek in the given
month falls within this date range.
This method correctly handles ranges that span year boundaries. For example, a range from Nov 2023 to Feb 2024 will correctly check for occurrences in January 2024.
If isInclusive is true (default), dates at the start/end boundaries
are considered in range. If false, only dates strictly between start
and end are considered.
Example:
// Range: Nov 15, 2023 to Feb 15, 2024
final range = DateTimeRange(
start: DateTime(2023, 11, 15),
end: DateTime(2024, 2, 15),
);
// Check if 2nd Monday of January falls in range
range.isNthDayOfMonthInRange(n: 2, dayOfWeek: DateTime.monday, month: 1); // true (Jan 2024)
Implementation
@useResult
bool isNthDayOfMonthInRange({
required int n,
required int dayOfWeek,
required int month,
bool isInclusive = true,
}) {
// Validate month parameter
if (month < DateConstants.minMonth || month > DateConstants.maxMonth) {
return false;
}
// Iterate through each year within the range.
// We no longer do an early-exit check on months because that fails
// for ranges spanning year boundaries (e.g., Nov 2023 to Feb 2024).
for (int year = start.year; year <= end.year; year++) {
final DateTime monthStart = DateTime(year, month);
final DateTime monthEnd = DateTime(year, month + 1).subtract(_oneDay);
// Skip this year if the entire month is outside the range
if (monthEnd.isBefore(start) || monthStart.isAfter(end)) {
continue;
}
// Use getNthWeekdayOfMonthInYear to get the date
final DateTime? nthOccurrence = DateTime(
year,
month,
).getNthWeekdayOfMonthInYear(n, dayOfWeek);
// Ensure the nth occurrence is within the target month
if (nthOccurrence == null || nthOccurrence.month != month) {
continue;
}
// Check if the nth occurrence is in range using isBetween for consistency
if (nthOccurrence.isBetween(start, end, isInclusive: isInclusive)) {
return true;
}
}
// If we couldn't find the nth occurrence in any year within the range,
return false;
}