/// <summary> /// This is used to expand the yearly frequency by month /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>This may generate invalid dates (i.e. June 31st). These will be removed later.</remarks> public int ByMonth(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt, rdtNew; int expIdx, count = dates.Count; UniqueIntegerCollection byMonth = r.ByMonth; // Don't bother if either collection is empty if(count != 0 && byMonth.Count != 0) for(int idx = 0; idx < count; idx++) { rdt = dates[0]; dates.RemoveAt(0); // Expand the date/time by adding a new entry for each month specified for(expIdx = 0; expIdx < byMonth.Count; expIdx++) { rdtNew = new RecurDateTime(rdt); rdtNew.Month = byMonth[expIdx] - 1; dates.Add(rdtNew); } } return dates.Count; }
/// <summary> /// This is used to filter by month /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public static int ByMonth(Recurrence r, RecurDateTimeCollection dates) { int count = dates.Count; // Don't bother if either collection is empty if(count != 0 && r.ByMonth.Count != 0) for(int idx = 0, collIdx = 0; idx < count; idx++) { // Remove the date/time if the month isn't wanted if(!r.isMonthUsed[dates[collIdx].Month]) { dates.RemoveAt(collIdx); count--; idx--; } else collIdx++; } return dates.Count; }
/// <summary> /// This is used to expand by month day /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If an expanded date is invalid, it will be discarded</remarks> public static int ByMonthDay(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt, rdtNew; int expIdx, monthDay, count = dates.Count; UniqueIntegerCollection byMonthDay = r.ByMonthDay; // Don't bother if either collection is empty if(count != 0 && byMonthDay.Count != 0) for(int idx = 0; idx < count; idx++) { rdt = dates[0]; dates.RemoveAt(0); // Expand the date/time by adding a new entry for each month day specified for(expIdx = 0; expIdx < byMonthDay.Count; expIdx++) { monthDay = byMonthDay[expIdx]; rdtNew = new RecurDateTime(rdt); rdtNew.Day = 1; // From start of month or end of month? if(monthDay > 0) rdtNew.AddDays(monthDay - 1); else { rdtNew.AddMonths(1); rdtNew.AddDays(monthDay); } // If not in the month, discard it if(rdtNew.Month != rdt.Month) continue; dates.Add(rdtNew); } } return dates.Count; }
/// <summary> /// This is used to filter by year day /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If a date in the collection is invalid, it will be discarded</remarks> public static int ByYearDay(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt; int days, count = dates.Count; // Don't bother if either collection is empty if(count != 0 && r.ByYearDay.Count != 0) for(int idx = 0, collIdx = 0; idx < count; idx++) { rdt = dates[collIdx]; // If not valid, discard it if(!rdt.IsValidDate()) { dates.RemoveAt(collIdx); count--; idx--; continue; } days = (DateTime.IsLeapYear(rdt.Year)) ? 367 : 366; // Remove the date/time if the year day isn't wanted. Check both from the start of the year // and from the end of the year. if(!r.isYearDayUsed[rdt.DayOfYear] && !r.isNegYearDayUsed[days - rdt.DayOfYear]) { dates.RemoveAt(collIdx); count--; idx--; } else collIdx++; } return dates.Count; }
/// <summary> /// This is used to expand the yearly frequency by month day /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int ByMonthDay(Recurrence r, RecurDateTimeCollection dates) { return Expand.ByMonthDay(r, dates); }
/// <summary> /// This is used to expand the yearly frequency by week number /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If an expanded date is invalid, it will be discarded</remarks> public int ByWeekNo(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt, rdtNew; int expIdx, week, yearWeeks, count = dates.Count; UniqueIntegerCollection byWeekNo = r.ByWeekNo; // Don't bother if either collection is empty if(count != 0 && byWeekNo.Count != 0) for(int idx = 0; idx < count; idx++) { rdt = dates[0]; yearWeeks = DateUtils.WeeksInYear(rdt.Year, r.WeekStart); dates.RemoveAt(0); // Expand the date/time by adding a new entry for each week number specified for(expIdx = 0; expIdx < byWeekNo.Count; expIdx++) { week = byWeekNo[expIdx]; // If not in the year, discard it if((week == 53 || week == -53) && yearWeeks == 52) continue; if(week > 0) { rdtNew = new RecurDateTime(DateUtils.DateFromWeek(rdt.Year, week, r.WeekStart, r.weekdayOffset)); } else rdtNew = new RecurDateTime(DateUtils.DateFromWeek(rdt.Year, yearWeeks + week + 1, r.WeekStart, r.weekdayOffset)); rdtNew.Hour = rdt.Hour; rdtNew.Minute = rdt.Minute; rdtNew.Second = rdt.Second; dates.Add(rdtNew); } } return dates.Count; }
/// <summary> /// This is used to filter by day of the week /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If a date in the collection is invalid, it will be discarded</remarks> public static int ByDay(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt; int count = dates.Count; // Don't bother if either collection is empty if(count != 0 && r.ByDay.Count != 0) for(int idx = 0, collIdx = 0; idx < count; idx++) { rdt = dates[collIdx]; // If not valid, discard it if(!rdt.IsValidDate()) { dates.RemoveAt(collIdx); count--; idx--; continue; } // Remove the date/time if the weekday isn't wanted if(!r.isDayUsed[(int)rdt.DayOfWeek]) { dates.RemoveAt(collIdx); count--; idx--; } else collIdx++; } return dates.Count; }
/// <summary> /// This is used to expand by second /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If a date in the collection is invalid, it will be discarded</remarks> public static int BySecond(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt, rdtNew; int expIdx, count = dates.Count; UniqueIntegerCollection bySecond = r.BySecond; // Don't bother if either collection is empty if(count != 0 && bySecond.Count != 0) for(int idx = 0; idx < count; idx++) { rdt = dates[0]; dates.RemoveAt(0); // If not valid, discard it if(!rdt.IsValidDate()) continue; // Expand the date/time by adding a new entry for each second specified for(expIdx = 0; expIdx < bySecond.Count; expIdx++) { rdtNew = new RecurDateTime(rdt); rdtNew.Second = bySecond[expIdx]; dates.Add(rdtNew); } } return dates.Count; }
/// <summary> /// This is used to expand the yearly frequency by second /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int BySecond(Recurrence r, RecurDateTimeCollection dates) { return Expand.BySecond(r, dates); }
/// <summary> /// This method is used to return all recurring instances between the two specified date/times based on /// the current settings. /// </summary> /// <param name="fromDate">The minimum date/time on or after which instances should occur.</param> /// <param name="toDate">The maximum date/time on or before which instances should occur.</param> /// <returns>Returns a <see cref="DateTimeCollection"/> of <see cref="DateTime" /> objects that represent /// the instances found between the two specified date/times.</returns> private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) { RecurDateTimeCollection rdtc; RecurDateTime rdt; int idx, count, lastYear = -1; DateTimeCollection dcDates = new DateTimeCollection(); // If undefined or if the requested range is outside that of the recurrence, don't bother. Just // return an empty collection. Note that for defined recurrences that use a count, we'll always // have to expand it. if(frequency == RecurFrequency.Undefined || startDate > toDate || untilDate < fromDate) return dcDates; RecurDateTime start = new RecurDateTime(startDate), end = new RecurDateTime(untilDate), from = new RecurDateTime(fromDate), to = new RecurDateTime(toDate); RecurDateTime current = freqRules.FindStart(this, start, end, from, to); // If there's nothing to generate, stop now if(current == null) return dcDates; rdtc = new RecurDateTimeCollection(); // Initialize the filtering arrays. These help speed up the filtering process by letting us do one // look up as opposed to comparing all elements in the collection. Array.Clear(isSecondUsed, 0, isSecondUsed.Length); Array.Clear(isMinuteUsed, 0, isMinuteUsed.Length); Array.Clear(isHourUsed, 0, isHourUsed.Length); Array.Clear(isDayUsed, 0, isDayUsed.Length); Array.Clear(isMonthDayUsed, 0, isMonthDayUsed.Length); Array.Clear(isNegMonthDayUsed, 0, isNegMonthDayUsed.Length); Array.Clear(isYearDayUsed, 0, isYearDayUsed.Length); Array.Clear(isNegYearDayUsed, 0, isNegYearDayUsed.Length); Array.Clear(isMonthUsed, 0, isMonthUsed.Length); if(bySecond.Count != 0) foreach(int second in bySecond) isSecondUsed[second] = true; if(byMinute.Count != 0) foreach(int minute in byMinute) isMinuteUsed[minute] = true; if(byHour.Count != 0) foreach(int hour in byHour) isHourUsed[hour] = true; if(byMonth.Count != 0) foreach(int month in byMonth) isMonthUsed[month - 1] = true; // When filtering, the instance is ignored if(byDay.Count != 0) foreach(DayInstance di in byDay) isDayUsed[(int)di.DayOfWeek] = true; // Negative days are from the end of the month if(byMonthDay.Count != 0) foreach(int monthDay in byMonthDay) if(monthDay > 0) isMonthDayUsed[monthDay] = true; else isNegMonthDayUsed[0 - monthDay] = true; // Negative days are from the end of the year if(byYearDay.Count != 0) foreach(int yearDay in byYearDay) if(yearDay > 0) isYearDayUsed[yearDay] = true; else isNegYearDayUsed[0 - yearDay] = true; do { rdtc.Clear(); rdtc.Add(current); // The spec is rather vague about how some of the rules are used together. For example, it says // that rule parts for a period of time less than the frequency generally expand it. However, // an example for the MONTHLY frequency shows that when BYMONTHDAY and BYDAY are used together, // BYDAY acts as a filter for BYMONTHDAY not an expansion of the frequency. When used by // themselves, the rules in question do act as expansions. There are no examples for the yearly // frequency that show how all of the various combinations interact so I'm making some // assumptions based on an evaluation of what makes the most sense. switch(frequency) { case RecurFrequency.Yearly: // This one gets rather messy so it's separate ExpandYearly(rdtc); break; case RecurFrequency.Monthly: if(freqRules.ByMonth(this, rdtc) != 0) if(freqRules.ByYearDay(this, rdtc) != 0) { // If BYMONTHDAY and BYDAY are specified, expand by month day and filter by day. // If one but not the other or neither is specified, handle them in order as // usual. if(byMonthDay.Count != 0 && byDay.Count != 0) { if(Expand.ByMonthDay(this, rdtc) != 0) if(Filter.ByDay(this, rdtc) != 0) { // These always expand if used Expand.ByHour(this, rdtc); Expand.ByMinute(this, rdtc); Expand.BySecond(this, rdtc); } } else if(Expand.ByMonthDay(this, rdtc) != 0) if(freqRules.ByDay(this, rdtc) != 0) { // These always expand if used Expand.ByHour(this, rdtc); Expand.ByMinute(this, rdtc); Expand.BySecond(this, rdtc); } } break; default: // Everything else is fairly straightforward. We just expand or filter based on the // frequency type and what rules are specified. if(freqRules.ByMonth(this, rdtc) != 0) if(freqRules.ByYearDay(this, rdtc) != 0) if(freqRules.ByMonthDay(this, rdtc) != 0) if(freqRules.ByDay(this, rdtc) != 0) if(freqRules.ByHour(this, rdtc) != 0) if(freqRules.ByMinute(this, rdtc) != 0) freqRules.BySecond(this, rdtc); break; } // Sort the dates and remove invalid and duplicate dates rdtc.Sort(); for(idx = 0, count = rdtc.Count; idx < count; idx++) { rdt = rdtc[idx]; // If not valid, discard it. if(!rdt.IsValidDate()) { rdtc.RemoveAt(idx); idx--; count--; continue; } // Discard it if it falls on a holiday if(!canOccurOnHoliday) { // If this is the first call or the year changes, get the holidays in the date's year // and the next year. if(holDates == null || lastYear != rdt.Year) { holDates = new HashSet<DateTime>(holidays.HolidaysBetween(rdt.Year, rdt.Year + 1)); lastYear = rdt.Year; } // Note that we only compare the date part as the holiday's time probably will not match // the recurrence's time. if(holDates.Contains(rdt.ToDateTime().Date)) { rdtc.RemoveAt(idx); idx--; count--; continue; } } // Discard it if it's a duplicate if(idx != 0 && rdt == rdtc[idx - 1]) { rdtc.RemoveAt(idx); idx--; count--; continue; } } if(rdtc.Count != 0) { // Apply the BYSETPOS rule and remove entries prior to the start or past the end of the // ranges. if(bySetPos.Count != 0) { foreach(int nPos in bySetPos) { // Invert negative values. They'll select elements indexed from the end of the // array. if(nPos < 0) idx = nPos + rdtc.Count; else idx = nPos - 1; if(idx >= 0 && idx < rdtc.Count) if(rdtc[idx] >= start && rdtc[idx] <= end && rdtc[idx] >= from && rdtc[idx] <= to) dcDates.Add(rdtc[idx].ToDateTime()); } } else for(idx = 0; idx < rdtc.Count; idx++) if(rdtc[idx] >= start && rdtc[idx] <= end && rdtc[idx] >= from && rdtc[idx] <= to) dcDates.Add(rdtc[idx].ToDateTime()); // Handle MaxOccurrences property. Note that if it's used, it is assumed that the limiting // range starts at the recurrence start. Otherwise, we have no way of knowing how many // occurred between the recurrence start and the limiting range's start date. if(maxOccur != 0 && dcDates.Count > maxOccur) dcDates.RemoveRange(maxOccur, dcDates.Count - maxOccur); } // Loop until the end of the recurrence or the range } while(freqRules.FindNext(this, end, to, current) && (maxOccur == 0 || dcDates.Count < maxOccur)); // Sort the collection one last time. There's no guaranteed order of selection if BYSETPOS was used. dcDates.Sort(true); return dcDates; }
/// <summary> /// This is used to filter the daily frequency by month /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int ByMonth(Recurrence r, RecurDateTimeCollection dates) { return Filter.ByMonth(r, dates); }
/// <summary> /// This is used to filter the daily frequency by year day /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int ByYearDay(Recurrence r, RecurDateTimeCollection dates) { return Filter.ByYearDay(r, dates); }
/// <summary> /// ByWeekNo is only applicable in the Yearly frequency and is ignored for the Daily frequency /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int ByWeekNo(Recurrence r, RecurDateTimeCollection dates) { return dates.Count; }
/// <summary> /// This is used to filter the secondly frequency by second /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int BySecond(Recurrence r, RecurDateTimeCollection dates) { int count = dates.Count; // Don't bother if either collection is empty if(count != 0 && r.BySecond.Count != 0) for(int idx = 0, nCollIdx = 0; idx < count; idx++) { // Remove the date/time if the second isn't wanted if(!r.isSecondUsed[dates[nCollIdx].Second]) { dates.RemoveAt(nCollIdx); count--; idx--; } else nCollIdx++; } return dates.Count; }
/// <summary> /// This is used to expand the weekly frequency by day of the week /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If an expanded date is invalid, it will be discarded</remarks> public int ByDay(Recurrence r, RecurDateTimeCollection dates) { return Expand.ByDayInWeeks(r, dates); }
/// <summary> /// This is used to expand the yearly frequency by day of the week /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If an expanded date is invalid, it will be discarded</remarks> public int ByDay(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt, rdtNew; DayOfWeek dow; int expIdx, instance, count = dates.Count; DayInstanceCollection byDay = r.ByDay; // Don't bother if either collection is empty if(count != 0 && byDay.Count != 0) for(int idx = 0; idx < count; idx++) { rdt = dates[0]; dates.RemoveAt(0); // Expand the date/time by adding a new entry for each week day instance specified for(expIdx = 0; expIdx < byDay.Count; expIdx++) { instance = byDay[expIdx].Instance; dow = byDay[expIdx].DayOfWeek; if(instance == 0) { // Expand to every specified day of the week in the year rdtNew = new RecurDateTime(rdt); rdtNew.Month = 0; rdtNew.Day = 1; rdtNew.AddDays(((int)dow + 7 - (int)rdtNew.DayOfWeek) % 7); while(rdtNew.Year == rdt.Year) { dates.Add(new RecurDateTime(rdtNew)); rdtNew.AddDays(7); } continue; } if(instance > 0) { // Add the nth instance of the day of the week rdtNew = new RecurDateTime(rdt); rdtNew.Month = 0; rdtNew.Day = 1; rdtNew.AddDays((((int)dow + 7 - (int)rdtNew.DayOfWeek) % 7) + ((instance - 1) * 7)); } else { // Add the nth instance of the day of the week from the end of the year rdtNew = new RecurDateTime(rdt); rdtNew.Month = 11; rdtNew.Day = 31; rdtNew.AddDays(0 - (((int)rdtNew.DayOfWeek + 7 - (int)dow) % 7) + ((instance + 1) * 7)); } // If not in the year, discard it if(rdtNew.Year != rdt.Year) continue; dates.Add(new RecurDateTime(rdtNew)); } } return dates.Count; }
/// <summary> /// This is used to expand the yearly frequency by minute /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> public int ByMinute(Recurrence r, RecurDateTimeCollection dates) { return Expand.ByMinute(r, dates); }
/// <summary> /// This is used to handle the expansion of the yearly frequency /// </summary> /// <param name="dates">The collection in which to put the dates</param> /// <remarks>The spec is rather vague about how all the rules should interact so I'm making some best /// guesses here based on the examples in the spec itself although not all combinations are shown. /// </remarks> private void ExpandYearly(RecurDateTimeCollection dates) { RecurDateTimeCollection rdtcMonth = null, rdtcMoDay = null, rdtcWeek = null, rdtcYrDay = null, rdtcDay = null; bool isExpanded = false; // We'll expand each rule individually and combine the results before applying the time expansions. // The application of the BYMONTHDAY and BYDAY rules varies based on whatever other rule parts are // present as well. if(byMonth.Count != 0) { // Expand by month isExpanded = true; rdtcMonth = new RecurDateTimeCollection(dates); freqRules.ByMonth(this, rdtcMonth); // If BYMONTHDAY and BYDAY are both specified, we need to expand by month day and then filter by // day. If we expand by day alone, note that we do so only in the months specified in the // BYMONTH rule. if(byMonthDay.Count != 0 && byDay.Count != 0) { Expand.ByMonthDay(this, rdtcMonth); Filter.ByDay(this, rdtcMonth); } else if(Expand.ByMonthDay(this, rdtcMonth) != 0) Expand.ByDayInMonths(this, rdtcMonth); } else { if(byMonthDay.Count != 0) { // Expand by month day if specified without any by month rule part isExpanded = true; rdtcMoDay = new RecurDateTimeCollection(dates); freqRules.ByMonthDay(this, rdtcMoDay); } // As long as by week number isn't specified either, we'll expand the by day rule here too if(byWeekNo.Count == 0) { isExpanded = true; rdtcDay = new RecurDateTimeCollection(dates); freqRules.ByDay(this, rdtcDay); } } if(byWeekNo.Count != 0) { // Expand by week number isExpanded = true; rdtcWeek = new RecurDateTimeCollection(dates); freqRules.ByWeekNo(this, rdtcWeek); // Expand by days of the week in those weeks Expand.ByDayInWeeks(this, rdtcWeek); } if(byYearDay.Count != 0) { // Expand by year day isExpanded = true; rdtcYrDay = new RecurDateTimeCollection(dates); freqRules.ByYearDay(this, rdtcYrDay); } // Combine the various expansions. If nothing was done, leave the original date in the collection. if(isExpanded) { dates.Clear(); if(rdtcMonth != null && rdtcMonth.Count != 0) dates.AddRange(rdtcMonth); if(rdtcMoDay != null && rdtcMoDay.Count != 0) dates.AddRange(rdtcMoDay); if(rdtcWeek != null && rdtcWeek.Count != 0) dates.AddRange(rdtcWeek); if(rdtcYrDay != null && rdtcYrDay.Count != 0) dates.AddRange(rdtcYrDay); if(rdtcDay != null && rdtcDay.Count != 0) dates.AddRange(rdtcDay); } // In any case, the time parts are easy. They always expand the instances if there's anything there. if(dates.Count != 0) { Expand.ByHour(this, dates); Expand.ByMinute(this, dates); Expand.BySecond(this, dates); } }
/// <summary> /// This is used to filter by month day /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If a date in the collection is invalid, it will be discarded</remarks> public static int ByMonthDay(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt; int count = dates.Count; // Don't bother if either collection is empty if(count != 0 && r.ByMonthDay.Count != 0) for(int idx = 0, collIdx = 0; idx < count; idx++) { rdt = dates[collIdx]; // If not valid, discard it if(!rdt.IsValidDate()) { dates.RemoveAt(collIdx); count--; idx--; continue; } // Remove the date/time if the month day isn't wanted. Check both from the start of the // month and from the end of the month. if(!r.isMonthDayUsed[rdt.Day] && !r.isNegMonthDayUsed[DateTime.DaysInMonth(rdt.Year, rdt.Month + 1) - rdt.Day + 1]) { dates.RemoveAt(collIdx); count--; idx--; } else collIdx++; } return dates.Count; }
/// <summary> /// This is used to expand one or more weeks by day of the week /// </summary> /// <param name="r">A reference to the recurrence</param> /// <param name="dates">A reference to the collection of current instances that have been generated</param> /// <returns>The number of instances in the collection. If zero, subsequent rules don't have to be /// checked as there's nothing else to do.</returns> /// <remarks>If an expanded date is invalid, it will be discarded</remarks> public static int ByDayInWeeks(Recurrence r, RecurDateTimeCollection dates) { RecurDateTime rdt, rdtNew; int expIdx, count = dates.Count; DayInstanceCollection byDay = r.ByDay; // Don't bother if either collection is empty if(count != 0 && byDay.Count != 0) for(int idx = 0; idx < count; idx++) { rdt = dates[0]; dates.RemoveAt(0); // If not valid, discard it if(!rdt.IsValidDate()) continue; // Expand the date/time by adding a new entry for each day of the week. As with filtering, // the instance number is ignored as it isn't useful here. For this, the "week" is the seven // day period starting on the occurrence date. for(expIdx = 0; expIdx < byDay.Count; expIdx++) { rdtNew = new RecurDateTime(rdt); rdtNew.AddDays((((int)byDay[expIdx].DayOfWeek + 7 - (int)r.WeekStart) % 7) - (((int)rdt.DayOfWeek + 7 - (int)r.WeekStart) % 7)); dates.Add(rdtNew); } } return dates.Count; }