isNthDayOfMonthInRange method

  1. @useResult
bool isNthDayOfMonthInRange({
  1. required int n,
  2. required int dayOfWeek,
  3. required int month,
  4. bool isInclusive = true,
})

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;
}