getRecurrencesForPeriod method

List<DateTime> getRecurrencesForPeriod(
  1. DateTime periodStart,
  2. DateTime periodEnd,
  3. DateTime eventStart,
  4. DateTime eventEnd,
)

Implementation

List<DateTime> getRecurrencesForPeriod(DateTime periodStart,
    DateTime periodEnd, DateTime eventStart, DateTime eventEnd) {
  assert(periodStart.isBefore(periodEnd));
  var recurrences = <DateTime>[];
  if (until != null && until!.isBefore(periodStart)) {
    return recurrences;
  }
  switch (frequency) {
    case Frequency.SECONDLY:
      assert(bySecond != null && bySecond!.isNotEmpty);
      while (eventStart.isBefore(periodEnd.add(Duration(milliseconds: 1))) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        if (eventStart.isAfter(periodStart) || eventStart == periodStart) {
          recurrences.add(eventStart);
        }
        eventStart = eventStart.add(Duration(seconds: interval));
      }
      break;
    case Frequency.MINUTELY:
      assert(byMinute != null && byMinute!.isNotEmpty);
      while (eventStart.isBefore(periodEnd.add(Duration(milliseconds: 1))) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        if (eventStart.isAfter(periodStart) || eventStart == periodStart) {
          recurrences.add(eventStart);
        }
        eventStart = eventStart.add(Duration(minutes: interval));
      }
      break;
    case Frequency.HOURLY:
      assert(byHour != null && byHour!.isNotEmpty);
      while (eventStart.isBefore(periodEnd.add(Duration(milliseconds: 1))) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        if (eventStart.isAfter(periodStart) || eventStart == periodStart) {
          recurrences.add(eventStart);
        }
        eventStart = eventStart.add(Duration(hours: interval));
      }
      break;
    case Frequency.DAILY:
      assert(byDay != null && byDay!.isNotEmpty);
      while (eventStart.isBefore(periodEnd.add(Duration(milliseconds: 1))) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        if (eventStart.isAfter(periodStart) || eventStart == periodStart) {
          recurrences.add(eventStart);
        }
        eventStart = eventStart.add(Duration(days: interval));
      }
      break;

    case Frequency.WEEKLY:
      while (eventStart.isBefore(periodEnd.add(Duration(milliseconds: 1))) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        for (DayOfWeek dayOfWeek in (byDay ?? []).whereType<DayOfWeek>()) {
          var daysUntilRecurrence =
              (dayOfWeek.weekday.index - eventStart.weekday + 7) % 7;
          var nextRecurrence =
              eventStart.add(Duration(days: daysUntilRecurrence));
          if (nextRecurrence.isAfter(periodStart) ||
              nextRecurrence == periodStart) {
            if (nextRecurrence.isBefore(periodEnd) ||
                nextRecurrence == periodEnd) {
              recurrences.add(nextRecurrence);
            }
          }
        }
        eventStart = eventStart.add(Duration(days: interval * 7));
      }
      break;

    case Frequency.MONTHLY:
      assert(byMonth != null && byMonth!.isNotEmpty);
      while (eventStart.isBefore(periodEnd.add(Duration(milliseconds: 1))) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        if (eventStart.isAfter(periodStart) || eventStart == periodStart) {
          recurrences.add(eventStart);
        }
        var nextMonthStart = DateTime(
          eventStart.year + (eventStart.month + interval - 1) ~/ 12,
          (eventStart.month + interval - 1) % 12 + 1,
          eventStart.day,
          eventStart.hour,
          eventStart.minute,
          eventStart.second,
          eventStart.millisecond,
        );

        if (byMonth == null ||
            byMonth!.isEmpty ||
            byMonth!.contains(nextMonthStart.month)) {
          eventStart = nextMonthStart;
        } else {
          var nextValidMonth = byMonth!
              .firstWhere((m) => m > nextMonthStart.month, orElse: () => -1);
          if (nextValidMonth == -1) {
            break; // exit loop if there are no valid months left
          }
          eventStart = DateTime(
            nextMonthStart.year + (nextValidMonth - 1) ~/ 12,
            (nextValidMonth - 1) % 12 + 1,
            nextMonthStart.day,
            nextMonthStart.hour,
            nextMonthStart.minute,
            nextMonthStart.second,
            nextMonthStart.millisecond,
          );
        }

        if (eventStart.month == DateTime.february &&
            eventStart.day == 29 &&
            !isLeapYear(eventStart.year)) {
          eventStart = DateTime(eventStart.year, DateTime.march, 1,
              eventStart.hour, eventStart.minute, eventStart.second);
        }
      }
      break;

    case Frequency.YEARLY:
      assert(byYearDay != null && byYearDay!.isNotEmpty);
      var eventStartYear = eventStart.year;
      var eventStartMonth = eventStart.month;
      var eventStartDay = eventStart.day;
      if (eventStartMonth == DateTime.february &&
          eventStartDay == 29 &&
          !isLeapYear(eventStartYear)) {
        eventStartMonth = DateTime.march;
        eventStartDay = 1;
      }
      while (eventStart.isBefore(periodEnd) &&
          (until == null ||
              eventStart.isBefore(until!.add(Duration(milliseconds: 1))))) {
        if (eventStart.isAfter(periodStart) || eventStart == periodStart) {
          recurrences.add(eventStart);
        }
        eventStart = DateTime(
            eventStartYear + interval,
            eventStartMonth,
            eventStartDay,
            eventStart.hour,
            eventStart.minute,
            eventStart.second,
            eventStart.millisecond);
        if (eventStartMonth == DateTime.february &&
            eventStartDay == 29 &&
            !isLeapYear(eventStartYear)) {
          eventStartMonth = DateTime.march;
          eventStartDay = 1;
        } else {
          eventStartMonth = eventStart.month;
          eventStartDay = eventStart.day;
        }
        eventStartYear = eventStart.year;
      }
      break;
  }
  return recurrences;
}