Пример #1
0
        /// <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;
        }
Пример #2
0
        /// <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;
        }
Пример #3
0
        /// <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;
        }
Пример #4
0
        /// <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;
        }
Пример #5
0
 /// <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);
 }
Пример #6
0
        /// <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;
        }
Пример #7
0
        /// <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;
        }
Пример #8
0
        /// <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;
        }
Пример #9
0
 /// <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);
 }
Пример #10
0
        /// <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;
        }
Пример #11
0
 /// <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);
 }
Пример #12
0
 /// <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);
 }
Пример #13
0
 /// <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;
 }
Пример #14
0
        /// <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;
        }
Пример #15
0
 /// <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);
 }
Пример #16
0
        /// <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;
        }
Пример #17
0
 /// <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);
 }
Пример #18
0
        /// <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);
            }
        }
Пример #19
0
        /// <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;
        }
Пример #20
0
        /// <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;
        }