isNthDayOfMonthInRange method

bool isNthDayOfMonthInRange(
  1. int n,
  2. int dayOfWeek,
  3. int month, {
  4. bool inclusive = true,
})

Determines if the nth occurrence of a specific day of the week in a given month falls within the specified 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.

Args: n (int): The occurrence number (1st, 2nd, 3rd, etc.) dayOfWeek (int): The day of the week (e.g., DateTime.monday) month (int): The month to check (1-12) inclusive (bool): If true (default), dates at the start/end boundaries are considered in range. If false, only dates strictly between start and end are considered.

Returns: bool: true if the nth occurrence of the specified weekday in the given month falls within the range, false otherwise.

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(2, DateTime.monday, 1); // true (Jan 2024)

Implementation

bool isNthDayOfMonthInRange(int n, int dayOfWeek, int month, {bool inclusive = true}) {
  // Validate month parameter
  if (month < 1 || month > 12) {
    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++) {
    // Optimization: Only proceed if the month is within the range for the
    // current year. This correctly handles year boundaries.
    final DateTime monthStart = DateTime(year, month);
    final DateTime monthEnd = DateTime(year, month + 1).subtract(const Duration(days: 1));

    // 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, inclusive: inclusive)) {
      return true;
    }
  }

  // If we couldn't find the nth occurrence in any year within the range,
  // return false
  return false;
}