Esempio n. 1
0
 /// <summary>
 /// Creates the specified pattern.
 /// </summary>
 /// <param name="pattern">The pattern.</param>
 /// <param name="windowStart">The window start.</param>
 /// <returns></returns>
 /// <exception cref="System.ArgumentException">pattern.Frequency</exception>
 public static IRecurrence Create(IRecurrencePattern pattern, DateTime windowStart)
 {
     AsyncServiceException.ThrowIfNull(pattern, "pattern");
     switch (pattern.Frequency)
     {
         case RecurrenceFrequency.Minutely:
             return new ConstantPeriodRecurrence(TimeSpan.FromMinutes(1.0), pattern.Interval,
                                                 pattern.PatternStart, windowStart);
         case RecurrenceFrequency.Hourly:
             return new ConstantPeriodRecurrence(TimeSpan.FromHours(1.0), pattern.Interval, pattern.PatternStart,
                                                 windowStart);
         case RecurrenceFrequency.Daily:
             return new ConstantPeriodRecurrence(TimeSpan.FromDays(1.0), pattern.Interval, pattern.PatternStart,
                                                 windowStart);
         case RecurrenceFrequency.Weekly:
             if (pattern.ByDay.Length == 0)
             {
                 return new ConstantPeriodRecurrence(TimeSpan.FromDays(7.0), pattern.Interval,
                                                     pattern.PatternStart, windowStart);
             }
             IModifier modifier = new ByDayWeeklyModifier(pattern.ByDay, pattern.WeekStartDay);
             IRecurrence recurrence = new WeeklyRecurrence(pattern.Interval, pattern.PatternStart,
                                                           pattern.WeekStartDay, windowStart);
             return new ModifiedRecurrence(recurrence, modifier, windowStart);
         case RecurrenceFrequency.Yearly:
             return new YearlyRecurrence(pattern.Interval, pattern.ByMonth, pattern.ByMonthDay, pattern.PatternStart, windowStart);
         case RecurrenceFrequency.Secondly:
             return new ConstantPeriodRecurrence(TimeSpan.FromSeconds(1.0), pattern.Interval,
                                                 pattern.PatternStart, windowStart);
         default:
             throw new ArgumentException(string.Format("不合法的重复频率{0}。", pattern.Frequency), "pattern.Frequency");
     }
 }
Esempio n. 2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RecurrenceInstances"/> class.
 /// </summary>
 /// <param name="pattern">The pattern.</param>
 /// <param name="scope">The scope.</param>
 /// <param name="maxInstances">The maximum instances.</param>
 public RecurrenceInstances(IRecurrencePattern pattern, TimeInterval scope, int maxInstances)
 {
     AsyncServiceException.ThrowIfNull(pattern, "pattern");
     AsyncServiceException.ThrowIfNotPositive(maxInstances, "maxInstances");
     this._pattern = pattern;
     this._scope = scope;
     this._maxInstances = maxInstances;
 }
Esempio n. 3
0
 public void DetermineStartingRecurrence(IRecurrencePattern recur, ref IDateTime dt)
 {
     if (recur.Count != int.MinValue)
         dt = Todo.Start.Copy<IDateTime>();
     else
     {
         DateTime dtVal = dt.Value;
         IncrementDate(ref dtVal, recur, -recur.Interval);
         dt.Value = dtVal;
     }
 }
Esempio n. 4
0
 protected void IncrementDate(ref DateTime dt, IRecurrencePattern pattern, int interval)
 {
     DateTime old = dt;
     switch (pattern.Frequency)
     {
         case FrequencyType.Secondly: dt = old.AddSeconds(interval); break;
         case FrequencyType.Minutely: dt = old.AddMinutes(interval); break;
         case FrequencyType.Hourly: dt = old.AddHours(interval); break;
         case FrequencyType.Daily: dt = old.AddDays(interval); break;
         case FrequencyType.Weekly: dt = DateUtil.AddWeeks(Calendar, old, interval, pattern.FirstDayOfWeek); break;
         case FrequencyType.Monthly: dt = old.AddDays(-old.Day + 1).AddMonths(interval); break;
         case FrequencyType.Yearly: dt = old.AddDays(-old.DayOfYear + 1).AddYears(interval); break;
         default: throw new Exception("FrequencyType.NONE cannot be evaluated. Please specify a FrequencyType before evaluating the recurrence.");
     }
 }
Esempio n. 5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RecurrenceExpander"/> class.
 /// </summary>
 /// <param name="pattern">The pattern.</param>
 /// <param name="scope">The scope.</param>
 /// <param name="maxInstances">The maximum instances.</param>
 public RecurrenceExpander(IRecurrencePattern pattern, TimeInterval scope, int maxInstances)
 {
     AsyncServiceException.ThrowIfNull(pattern, "pattern");
     AsyncServiceException.ThrowIfNegative(maxInstances, "maxInstances");
     this._pattern = pattern;
     // 取消多时区支持
     //this._scope = new TimeInterval(pattern.TimeZone.ToLocalTime(scope.Start), scope.IsStartInclusive, pattern.TimeZone.ToLocalTime(scope.End), scope.IsEndInclusive);
     this._scope = new TimeInterval(scope.Start, scope.IsStartInclusive, scope.End, scope.IsEndInclusive);
     this._maxInstances = maxInstances;
     DateTime windowStart = this._pattern.PatternStart;
     if (this._pattern.Count == 0 && this._scope.Start - this._pattern.Duration > this._pattern.PatternStart)
     {
         windowStart = this._scope.Start - this._pattern.Duration;
     }
     this._generator = RecurrenceFactory.Create(this._pattern, windowStart);
     this._expandedInstances = 0;
 }
Esempio n. 6
0
        protected void IncrementDate(ref DateTime dt, IRecurrencePattern pattern, int interval)
        {
            // FIXME: use a more specific exception.
            if (interval == 0)
                throw new Exception("Cannot evaluate with an interval of zero.  Please use an interval other than zero.");

            DateTime old = dt;
            switch (pattern.Frequency)
            {
                case FrequencyType.Secondly: dt = old.AddSeconds(interval); break;
                case FrequencyType.Minutely: dt = old.AddMinutes(interval); break;
                case FrequencyType.Hourly: dt = old.AddHours(interval); break;
                case FrequencyType.Daily: dt = old.AddDays(interval); break;
                case FrequencyType.Weekly: dt = DateUtil.AddWeeks(old, interval, pattern.FirstDayOfWeek); break;
                case FrequencyType.Monthly: dt = old.AddDays(-old.Day + 1).AddMonths(interval); break;
                case FrequencyType.Yearly: dt = old.AddDays(-old.DayOfYear + 1).AddYears(interval); break;
                // FIXME: use a more specific exception.
                default: throw new Exception("FrequencyType.NONE cannot be evaluated. Please specify a FrequencyType before evaluating the recurrence.");
            }
        }
Esempio n. 7
0
        static public bool?[] GetExpandBehaviorList(IRecurrencePattern p)
        {
            // See the table in RFC 5545 Section 3.3.10 (Page 43).
            switch (p.Frequency)
            {                
                case FrequencyType.Minutely: return new bool?[] { false, null, false, false, false, false, false, true, false };
                case FrequencyType.Hourly:   return new bool?[] { false, null, false, false, false, false, true, true, false };
                case FrequencyType.Daily:    return new bool?[] { false, null, null, false, false, true, true, true, false };
                case FrequencyType.Weekly:   return new bool?[] { false, null, null, null, true, true, true, true, false };
                case FrequencyType.Monthly:
                    {
                        bool?[] row = new bool?[] { false, null, null, true, true, true, true, true, false };

                        // Limit if BYMONTHDAY is present; otherwise, special expand for MONTHLY.
                        if (p.ByMonthDay.Count > 0)
                            row[4] = false;

                        return row;
                    }
                case FrequencyType.Yearly:
                    {
                        bool?[] row = new bool?[] { true, true, true, true, true, true, true, true, false };

                        // Limit if BYYEARDAY or BYMONTHDAY is present; otherwise,
                        // special expand for WEEKLY if BYWEEKNO present; otherwise,
                        // special expand for MONTHLY if BYMONTH present; otherwise,
                        // special expand for YEARLY.
                        if (p.ByYearDay.Count > 0 || p.ByMonthDay.Count > 0)
                            row[4] = false;

                        return row;
                    }
                default:
                    return new bool?[] { false, null, false, false, false, false, false, false, false };
            }
        }
Esempio n. 8
0
        /**
         * Applies BYWEEKNO rules specified in this Recur instance to the specified date list. If no BYWEEKNO rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List <DateTime> GetWeekNoVariants(List <DateTime> dates, IRecurrencePattern pattern, bool?expand)
        {
            if (expand == null || pattern.ByWeekNo.Count == 0)
            {
                return(dates);
            }

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List <DateTime> weekNoDates = new List <DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByWeekNo.Count; j++)
                    {
                        // Determine our target week number
                        int weekNo = pattern.ByWeekNo[j];

                        // Determine our current week number
                        int currWeekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
                        while (currWeekNo > weekNo)
                        {
                            // If currWeekNo > weekNo, then we're likely at the start of a year
                            // where currWeekNo could be 52 or 53.  If we simply step ahead 7 days
                            // we should be back to week 1, where we can easily make the calculation
                            // to move to weekNo.
                            date       = date.AddDays(7);
                            currWeekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
                        }

                        // Move ahead to the correct week of the year
                        date = date.AddDays((weekNo - currWeekNo) * 7);

                        // Step backward single days until we're at the correct DayOfWeek
                        while (date.DayOfWeek != pattern.FirstDayOfWeek)
                        {
                            date = date.AddDays(-1);
                        }

                        for (int k = 0; k < 7; k++)
                        {
                            weekNoDates.Add(date);
                            date = date.AddDays(1);
                        }
                    }
                }
                return(weekNoDates);
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByWeekNo.Count; j++)
                    {
                        // Determine our target week number
                        int weekNo = pattern.ByWeekNo[j];

                        // Determine our current week number
                        int currWeekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);

                        if (weekNo == currWeekNo)
                        {
                            goto Next;
                        }
                    }

                    dates.RemoveAt(i);
                    Next :;
                }
                return(dates);
            }
        }
        public override string SerializeToString(object obj)
        {
            IRecurrencePattern recur   = obj as IRecurrencePattern;
            ISerializerFactory factory = GetService <ISerializerFactory>();

            if (recur != null && factory != null)
            {
                // Push the recurrence pattern onto the serialization stack
                SerializationContext.Push(recur);

                List <string> values = new List <string>();

                values.Add("FREQ=" + Enum.GetName(typeof(FrequencyType), recur.Frequency).ToUpper());

                //-- FROM RFC2445 --
                //The INTERVAL rule part contains a positive integer representing how
                //often the recurrence rule repeats. The default value is "1", meaning
                //every second for a SECONDLY rule, or every minute for a MINUTELY
                //rule, every hour for an HOURLY rule, every day for a DAILY rule,
                //every week for a WEEKLY rule, every month for a MONTHLY rule and
                //every year for a YEARLY rule.
                int interval = recur.Interval;
                if (interval == int.MinValue)
                {
                    interval = 1;
                }

                if (interval != 1)
                {
                    values.Add("INTERVAL=" + interval);
                }

                if (recur.Until != DateTime.MinValue)
                {
                    IStringSerializer serializer = factory.Build(typeof(IDateTime), SerializationContext) as IStringSerializer;
                    if (serializer != null)
                    {
                        IDateTime until = new iCalDateTime(recur.Until);
                        until.HasTime = true;
                        values.Add("UNTIL=" + serializer.SerializeToString(until));
                    }
                }

                if (recur.FirstDayOfWeek != DayOfWeek.Monday)
                {
                    values.Add("WKST=" + Enum.GetName(typeof(DayOfWeek), recur.FirstDayOfWeek).ToUpper().Substring(0, 2));
                }

                if (recur.Count != int.MinValue)
                {
                    values.Add("COUNT=" + recur.Count);
                }

                if (recur.ByDay.Count > 0)
                {
                    List <string> bydayValues = new List <string>();

                    IStringSerializer serializer = factory.Build(typeof(IWeekDay), SerializationContext) as IStringSerializer;
                    if (serializer != null)
                    {
                        foreach (WeekDay byday in recur.ByDay)
                        {
                            bydayValues.Add(serializer.SerializeToString(byday));
                        }
                    }

                    values.Add("BYDAY=" + string.Join(",", bydayValues.ToArray()));
                }

                SerializeByValue(values, recur.ByHour, "BYHOUR");
                SerializeByValue(values, recur.ByMinute, "BYMINUTE");
                SerializeByValue(values, recur.ByMonth, "BYMONTH");
                SerializeByValue(values, recur.ByMonthDay, "BYMONTHDAY");
                SerializeByValue(values, recur.BySecond, "BYSECOND");
                SerializeByValue(values, recur.BySetPosition, "BYSETPOS");
                SerializeByValue(values, recur.ByWeekNo, "BYWEEKNO");
                SerializeByValue(values, recur.ByYearDay, "BYYEARDAY");

                // Pop the recurrence pattern off the serialization stack
                SerializationContext.Pop();

                return(Encode(recur, string.Join(";", values.ToArray())));
            }
            return(null);
        }
        /**
         * Applies BYMONTHDAY rules specified in this Recur instance to the specified date list. If no BYMONTHDAY rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetMonthDayVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByMonthDay.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> monthDayDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMonthDay.Count; j++)
                    {
                        int monthDay = pattern.ByMonthDay[j];

                        int daysInMonth = Calendar.GetDaysInMonth(date.Year, date.Month);
                        if (Math.Abs(monthDay) <= daysInMonth)
                        {
                            // Account for positive or negative numbers
                            DateTime newDate;
                            if (monthDay > 0)
                                newDate = date.AddDays(-date.Day + monthDay);
                            else
                                newDate = date.AddDays(-date.Day + 1).AddMonths(1).AddDays(monthDay);

                            monthDayDates.Add(newDate);
                        }
                    }
                }
                return monthDayDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMonthDay.Count; j++)
                    {
                        int monthDay = pattern.ByMonthDay[j];

                        int daysInMonth = Calendar.GetDaysInMonth(date.Year, date.Month);
                        if (Math.Abs(monthDay) > daysInMonth)
                            throw new ArgumentException("Invalid day of month: " + date + " (day " + monthDay + ")");

                        // Account for positive or negative numbers
                        DateTime newDate;
                        if (monthDay > 0)
                            newDate = date.AddDays(-date.Day + monthDay);
                        else
                            newDate = date.AddDays(-date.Day + 1).AddMonths(1).AddDays(monthDay);

                        if (newDate.Day.Equals(date.Day))
                            goto Next;
                    }

                Next: ;
                    dates.RemoveAt(i);
                }                
            
                return dates;
            }
        }
        /**
         * Applies BYYEARDAY rules specified in this Recur instance to the specified date list. If no BYYEARDAY rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetYearDayVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByYearDay.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> yearDayDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByYearDay.Count; j++)
                    {
                        int yearDay = pattern.ByYearDay[j];

                        DateTime newDate;
                        if (yearDay > 0)
                            newDate = date.AddDays(-date.DayOfYear + yearDay);
                        else
                            newDate = date.AddDays(-date.DayOfYear + 1).AddYears(1).AddDays(yearDay);

                        yearDayDates.Add(newDate);
                    }
                }
                return yearDayDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByYearDay.Count; j++)
                    {
                        int yearDay = pattern.ByYearDay[j];

                        DateTime newDate;
                        if (yearDay > 0)
                            newDate = date.AddDays(-date.DayOfYear + yearDay);
                        else
                            newDate = date.AddDays(-date.DayOfYear + 1).AddYears(1).AddDays(yearDay);

                        if (newDate.DayOfYear == date.DayOfYear)
                            goto Next;
                    }

                    dates.RemoveAt(i);
                Next: ;                    
                }

                return dates;
            }
        }
        /**
         * Applies BYMONTH rules specified in this Recur instance to the specified date list. If no BYMONTH rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetMonthVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByMonth.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> monthlyDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMonth.Count; j++)
                    {
                        int month = pattern.ByMonth[j];
                        date = date.AddMonths(month - date.Month);
                        monthlyDates.Add(date);
                    }
                }
                return monthlyDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMonth.Count; j++)
                    {
                        if (date.Month == pattern.ByMonth[j])
                            goto Next;
                    }
                    dates.RemoveAt(i);
                Next: ;
                }
                return dates;
            }
        }
 /**
  * Returns a list of possible dates generated from the applicable BY* rules, using the specified date as a seed.
  * @param date the seed date
  * @param value the type of date list to return
  * @return a DateList
  */
 private List<DateTime> GetCandidates(DateTime date, IRecurrencePattern pattern, bool?[] expandBehaviors)
 {
     List<DateTime> dates = new List<DateTime>();
     dates.Add(date);
     dates = GetMonthVariants(dates, pattern, expandBehaviors[0]);
     dates = GetWeekNoVariants(dates, pattern, expandBehaviors[1]);
     dates = GetYearDayVariants(dates, pattern, expandBehaviors[2]);
     dates = GetMonthDayVariants(dates, pattern, expandBehaviors[3]);
     dates = GetDayVariants(dates, pattern, expandBehaviors[4]);
     dates = GetHourVariants(dates, pattern, expandBehaviors[5]);
     dates = GetMinuteVariants(dates, pattern, expandBehaviors[6]);
     dates = GetSecondVariants(dates, pattern, expandBehaviors[7]);
     dates = ApplySetPosRules(dates, pattern);
     return dates;
 }
        /**
         * Returns a list of start dates in the specified period represented by this recur. This method includes a base date
         * argument, which indicates the start of the fist occurrence of this recurrence. The base date is used to inject
         * default values to return a set of dates in the correct format. For example, if the search start date (start) is
         * Wed, Mar 23, 12:19PM, but the recurrence is Mon - Fri, 9:00AM - 5:00PM, the start dates returned should all be at
         * 9:00AM, and not 12:19PM.
         */
        private IList<DateTime> GetDates(IDateTime seed, DateTime periodStart, DateTime periodEnd, int maxCount, IRecurrencePattern pattern, bool includeReferenceDateInResults)
        {
            SortedList<DateTime, DateTime> dates = new SortedList<DateTime, DateTime>();
            DateTime originalDate = DateUtil.GetSimpleDateTimeData(seed);
            DateTime seedCopy = DateUtil.GetSimpleDateTimeData(seed);

            if (includeReferenceDateInResults)
                dates.Add(seedCopy, seedCopy);

            // If the interval is set to zero, or our count prevents us
            // from getting additional items, then return with the reference
            // date only.
            if (pattern.Interval == 0 ||
                (pattern.Count != int.MinValue && pattern.Count <= dates.Count))
            {
                return dates.Values;
            }

            // optimize the start time for selecting candidates
            // (only applicable where a COUNT is not specified)
            if (pattern.Count == int.MinValue)
            {
                DateTime incremented = seedCopy;
                // FIXME: we can more aggresively increment here when
                // the difference between dates is greater.
                IncrementDate(ref incremented, pattern, pattern.Interval);
                while (incremented < periodStart)
                {
                    seedCopy = incremented;
                    IncrementDate(ref incremented, pattern, pattern.Interval);
                }
            }

            bool?[] expandBehavior = RecurrenceUtil.GetExpandBehaviorList(pattern);

            int invalidCandidateCount = 0;
            int noCandidateIncrementCount = 0;
            DateTime candidate = DateTime.MinValue;
            while ((maxCount < 0) || (dates.Count < maxCount))
            {
                if (pattern.Until != DateTime.MinValue && candidate != DateTime.MinValue && candidate > pattern.Until)
                    break;

                if (periodEnd != null && candidate != DateTime.MinValue && candidate > periodEnd)
                    break;
                                
                if (pattern.Count >= 1 && (dates.Count + invalidCandidateCount) >= pattern.Count)
                    break;                

                List<DateTime> candidates = GetCandidates(seedCopy, pattern, expandBehavior);
                if (candidates.Count > 0)
                {
                    noCandidateIncrementCount = 0;

                    // sort candidates for identifying when UNTIL date is exceeded..
                    candidates.Sort();

                    for (int i = 0; i < candidates.Count; i++)
                    {
                        candidate = candidates[i];

                        // don't count candidates that occur before the original date..
                        if (candidate >= originalDate)
                        {
                            // candidates MAY occur before periodStart
                            // For example, FREQ=YEARLY;BYWEEKNO=1 could return dates
                            // from the previous year.
                            //
                            // candidates exclusive of periodEnd..
                            if (candidate >= periodEnd)
                            {
                                invalidCandidateCount++;
                            }
                            else if (pattern.Count >= 1 && (dates.Count + invalidCandidateCount) >= pattern.Count)
                            {
                                break;
                            }
                            else if (pattern.Until == DateTime.MinValue || candidate <= pattern.Until)
                            {
                                if (!dates.ContainsKey(candidate))
                                    dates.Add(candidate, candidate);                                
                            }
                        }
                    }
                } 
                else
                {
                    noCandidateIncrementCount++;
                    if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount))
                        break;
                }

                IncrementDate(ref seedCopy, pattern, pattern.Interval);
            }

            return dates.Values;
        }
        /**
         * Applies BYSECOND rules specified in this Recur instance to the specified date list. If no BYSECOND rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetSecondVariants(List<DateTime> dates, IRecurrencePattern pattern)
        {
            if (pattern.BySecond.Count == 0)
                return dates;

            List<DateTime> secondlyDates = new List<DateTime>();
            for (int i = 0; i < dates.Count; i++)
            {
                DateTime date = dates[i];
                for (int j = 0; j < pattern.BySecond.Count; j++)
                {
                    int second = pattern.BySecond[j];
                    date = date.AddSeconds(-date.Second + second);
                    secondlyDates.Add(date);
                }
            }
            return secondlyDates;
        }
 /**
  * Applies BYMINUTE rules specified in this Recur instance to the specified date list. If no BYMINUTE rules are
  * specified the date list is returned unmodified.
  * @param dates
  * @return
  */
 private List<DateTime> GetMinuteVariants(List<DateTime> dates, IRecurrencePattern pattern)
 {
     if (pattern.ByMinute.Count == 0)
         return dates;
     
     List<DateTime> minutelyDates = new List<DateTime>();
     for (int i = 0; i < dates.Count; i++)
     {
         DateTime date = dates[i];
         for (int j = 0; j < pattern.ByMinute.Count; j++)
         {
             int minute = pattern.ByMinute[j];
             date = date.AddMinutes(-date.Minute + minute);
             minutelyDates.Add(date);
         }
     }
     return minutelyDates;
 }
        /**
         * Applies BYHOUR rules specified in this Recur instance to the specified date list. If no BYHOUR rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetHourVariants(List<DateTime> dates, IRecurrencePattern pattern)
        {
            if (pattern.ByHour.Count == 0)
                return dates;

            List<DateTime> hourlyDates = new List<DateTime>();
            for (int i = 0; i < dates.Count; i++)
            {
                DateTime date = dates[i];
                for (int j = 0; j < pattern.ByHour.Count; j++)
                {
                    int hour = pattern.ByHour[j];
                    date = date.AddHours(-date.Hour + hour);                    
                    hourlyDates.Add(date);
                }
            }
            return hourlyDates;
        }
        /**
         * Applies BYDAY rules specified in this Recur instance to the specified date list. If no BYDAY rules are specified
         * the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetDayVariants(List<DateTime> dates, IRecurrencePattern pattern)
        {            
            if (pattern.ByDay.Count == 0)
                return dates;

            List<DateTime> weekDayDates = new List<DateTime>();
            for (int i = 0; i < dates.Count; i++)
            {
                DateTime date = dates[i];
                for (int j = 0; j < pattern.ByDay.Count; j++)
                {
                    IWeekDay weekDay = pattern.ByDay[j];
                    
                    // if BYYEARDAY or BYMONTHDAY is specified filter existing
                    // list..
                    if (pattern.ByYearDay.Count > 0 || pattern.ByMonthDay.Count > 0)
                    {
                        //int offset = weekDay.Offset;
                        //if (offset != int.MinValue)
                        //{
                        //    if (!weekDay.DayOfWeek.Equals(date.DayOfWeek))
                        //        continue;

                        //    int inc = offset > 0 ? 1 : -1;
                        //    int abs = Math.Abs(offset);
                        //    if (pattern.ByMonthDay.Count > 0)
                        //    {
                        //        // Get the start/end of the month
                        //        DateTime mondt = date.AddDays(-date.Day + 1);
                        //        if (offset > 0)
                        //            mondt = mondt.AddMonths(1).AddDays(-1);

                        //        // Navigate to the correct day of week
                        //        while (mondt.DayOfWeek != weekDay.DayOfWeek)
                        //            mondt = mondt.AddDays(inc);

                        //        // Navigate to the correct offset
                        //        mondt = mondt.AddDays((abs - 1) * inc);

                        //        // If equal, it's valid!
                        //        if (mondt.Equals(date))
                        //            weekDayDates.Add(date);
                        //    }
                        //    else
                        //    {
                        //        DateTime yeardt = date.AddDays(-date.DayOfYear + 1);
                        //        if (offset > 0)
                        //        {
                        //            // Start at end of year, or end of month if BYMONTH is specified
                        //            if (pattern.ByMonth.Count == 0)
                        //                yeardt = yeardt.AddYears(1).AddDays(-1);
                        //            else 
                        //                yeardt = yeardt.AddMonths(1).AddDays(-1);
                        //        }

                        //        // Navigate to the correct day of week
                        //        while (yeardt.DayOfWeek != weekDay.DayOfWeek)
                        //            yeardt = yeardt.AddDays(inc);

                        //        // Navigate to the correct offset
                        //        yeardt = yeardt.AddDays((abs - 1) * inc);

                        //        // If equal, it's valid!
                        //        if (yeardt.Equals(date))
                        //            weekDayDates.Add(date);
                        //    }
                        //}
                        //else 
                            
                        if (weekDay.DayOfWeek.Equals(date.DayOfWeek))
                        {
                            // If no offset is specified, simply test the day of week!
                            weekDayDates.Add(date);                          
                        }
                    }
                    else
                    {
                        weekDayDates.AddRange(GetAbsWeekDays(date, weekDay, pattern));
                    }
                }
            }

            return weekDayDates;
        }
Esempio n. 19
0
 public RecurrencePatternEvaluator(IRecurrencePattern pattern)
 {
     Pattern = pattern;
 }
Esempio n. 20
0
        /**
         * Applies BYYEARDAY rules specified in this Recur instance to the specified date list. If no BYYEARDAY rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List <DateTime> GetYearDayVariants(List <DateTime> dates, IRecurrencePattern pattern, bool?expand)
        {
            if (expand == null || pattern.ByYearDay.Count == 0)
            {
                return(dates);
            }

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List <DateTime> yearDayDates = new List <DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByYearDay.Count; j++)
                    {
                        int yearDay = pattern.ByYearDay[j];

                        DateTime newDate;
                        if (yearDay > 0)
                        {
                            newDate = date.AddDays(-date.DayOfYear + yearDay);
                        }
                        else
                        {
                            newDate = date.AddDays(-date.DayOfYear + 1).AddYears(1).AddDays(yearDay);
                        }

                        yearDayDates.Add(newDate);
                    }
                }
                return(yearDayDates);
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByYearDay.Count; j++)
                    {
                        int yearDay = pattern.ByYearDay[j];

                        DateTime newDate;
                        if (yearDay > 0)
                        {
                            newDate = date.AddDays(-date.DayOfYear + yearDay);
                        }
                        else
                        {
                            newDate = date.AddDays(-date.DayOfYear + 1).AddYears(1).AddDays(yearDay);
                        }

                        if (newDate.DayOfYear == date.DayOfYear)
                        {
                            goto Next;
                        }
                    }

                    dates.RemoveAt(i);
                    Next :;
                }

                return(dates);
            }
        }
Esempio n. 21
0
        /**
         * Applies BYMONTHDAY rules specified in this Recur instance to the specified date list. If no BYMONTHDAY rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List <DateTime> GetMonthDayVariants(List <DateTime> dates, IRecurrencePattern pattern, bool?expand)
        {
            if (expand == null || pattern.ByMonthDay.Count == 0)
            {
                return(dates);
            }

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List <DateTime> monthDayDates = new List <DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMonthDay.Count; j++)
                    {
                        int monthDay = pattern.ByMonthDay[j];

                        int daysInMonth = Calendar.GetDaysInMonth(date.Year, date.Month);
                        if (Math.Abs(monthDay) <= daysInMonth)
                        {
                            // Account for positive or negative numbers
                            DateTime newDate;
                            if (monthDay > 0)
                            {
                                newDate = date.AddDays(-date.Day + monthDay);
                            }
                            else
                            {
                                newDate = date.AddDays(-date.Day + 1).AddMonths(1).AddDays(monthDay);
                            }

                            monthDayDates.Add(newDate);
                        }
                    }
                }
                return(monthDayDates);
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMonthDay.Count; j++)
                    {
                        int monthDay = pattern.ByMonthDay[j];

                        int daysInMonth = Calendar.GetDaysInMonth(date.Year, date.Month);
                        if (Math.Abs(monthDay) > daysInMonth)
                        {
                            throw new ArgumentException("Invalid day of month: " + date + " (day " + monthDay + ")");
                        }

                        // Account for positive or negative numbers
                        DateTime newDate;
                        if (monthDay > 0)
                        {
                            newDate = date.AddDays(-date.Day + monthDay);
                        }
                        else
                        {
                            newDate = date.AddDays(-date.Day + 1).AddMonths(1).AddDays(monthDay);
                        }

                        if (newDate.Day.Equals(date.Day))
                        {
                            goto Next;
                        }
                    }

                    Next :;
                    dates.RemoveAt(i);
                }

                return(dates);
            }
        }
Esempio n. 22
0
 /// <summary>
 /// Throws the difference invalid.
 /// </summary>
 /// <param name="pattern">The pattern.</param>
 public override void ThrowIfInvalid(IRecurrencePattern pattern)
 {
     if (pattern.Frequency != RecurrenceFrequency.Yearly)
     {
         throw new InvalidRecurrenceRuleException(String.Format(CultureInfo.InvariantCulture,
                                                                  "BYMONTH必须在按年重复时使用。但实际的重复模式: {0}",
                                                                  pattern.Frequency));
     }
 }
        private void EnforceEvaluationRestrictions(IRecurrencePattern pattern)
        {
            RecurrenceEvaluationModeType? evaluationMode = pattern.EvaluationMode;
            RecurrenceRestrictionType? evaluationRestriction = pattern.RestrictionType;

            if (evaluationRestriction != RecurrenceRestrictionType.NoRestriction)
            {
                switch (evaluationMode)
                {
                    case RecurrenceEvaluationModeType.AdjustAutomatically:
                        switch (pattern.Frequency)
                        {
                            case FrequencyType.Secondly:
                                {
                                    switch (evaluationRestriction)
                                    {
                                        case RecurrenceRestrictionType.Default:
                                        case RecurrenceRestrictionType.RestrictSecondly: pattern.Frequency = FrequencyType.Minutely; break;
                                        case RecurrenceRestrictionType.RestrictMinutely: pattern.Frequency = FrequencyType.Hourly; break;
                                        case RecurrenceRestrictionType.RestrictHourly: pattern.Frequency = FrequencyType.Daily; break;
                                    }
                                } break;
                            case FrequencyType.Minutely:
                                {
                                    switch (evaluationRestriction)
                                    {
                                        case RecurrenceRestrictionType.RestrictMinutely: pattern.Frequency = FrequencyType.Hourly; break;
                                        case RecurrenceRestrictionType.RestrictHourly: pattern.Frequency = FrequencyType.Daily; break;
                                    }
                                } break;
                            case FrequencyType.Hourly:
                                {
                                    switch (evaluationRestriction)
                                    {
                                        case RecurrenceRestrictionType.RestrictHourly: pattern.Frequency = FrequencyType.Daily; break;
                                    }
                                } break;
                            default: break;
                        } break;
                    case RecurrenceEvaluationModeType.ThrowException:
                    case RecurrenceEvaluationModeType.Default:
                        switch (pattern.Frequency)
                        {
                            case FrequencyType.Secondly:
                                {
                                    switch (evaluationRestriction)
                                    {
                                        case RecurrenceRestrictionType.Default:
                                        case RecurrenceRestrictionType.RestrictSecondly:
                                        case RecurrenceRestrictionType.RestrictMinutely:
                                        case RecurrenceRestrictionType.RestrictHourly:
                                            throw new EvaluationEngineException();
                                    }
                                } break;
                            case FrequencyType.Minutely:
                                {
                                    switch (evaluationRestriction)
                                    {
                                        case RecurrenceRestrictionType.RestrictMinutely:
                                        case RecurrenceRestrictionType.RestrictHourly:
                                            throw new EvaluationEngineException();
                                    }
                                } break;
                            case FrequencyType.Hourly:
                                {
                                    switch (evaluationRestriction)
                                    {
                                        case RecurrenceRestrictionType.RestrictHourly:
                                            throw new EvaluationEngineException();
                                    }
                                } break;
                            default: break;
                        } break;
                }
            }
        }
Esempio n. 24
0
 /// <summary>
 /// Throws the difference invalid.
 /// </summary>
 /// <param name="pattern">The pattern.</param>
 public virtual void ThrowIfInvalid(IRecurrencePattern pattern)
 {
 }
        /**
         * Returns the the next date of this recurrence given a seed date
         * and start date.  The seed date indicates the start of the fist 
         * occurrence of this recurrence. The start date is the
         * starting date to search for the next recurrence.  Return null
         * if there is no occurrence date after start date.
         * @return the next date in the recurrence series after startDate
         * @param seed the start date of this Recurrence's first instance
         * @param startDate the date to start the search
         */
        private DateTime? GetNextDate(IDateTime referenceDate, DateTime periodStart, IRecurrencePattern pattern)
        {
            DateTime seedCopy = DateUtil.GetSimpleDateTimeData(referenceDate);
            // optimize the start time for selecting candidates
            // (only applicable where a COUNT is not specified)
            if (Pattern.Count == int.MinValue)
            {
                DateTime incremented = seedCopy;
                IncrementDate(ref incremented, pattern, pattern.Interval);
                while (incremented < periodStart)
                {
                    seedCopy = incremented;
                    IncrementDate(ref incremented, pattern, pattern.Interval);
                }
            }

            bool?[] expandBehaviors = RecurrenceUtil.GetExpandBehaviorList(pattern);

            int invalidCandidateCount = 0;
            int noCandidateIncrementCount = 0;
            DateTime candidate = DateTime.MinValue;

            while (true)
            {
                if (pattern.Until != DateTime.MinValue && candidate != DateTime.MinValue && candidate > pattern.Until)
                    break;

                if (pattern.Count > 0 && invalidCandidateCount >= pattern.Count)
                    break;

                List<DateTime> candidates = GetCandidates(seedCopy, pattern, expandBehaviors);
                if (candidates.Count > 0)
                {
                    noCandidateIncrementCount = 0;

                    // sort candidates for identifying when UNTIL date is exceeded..
                    candidates.Sort();

                    for (int i = 0; i < candidates.Count; i++)
                    {
                        candidate = candidates[i];

                        // don't count candidates that occur before the seed date..
                        if (candidate >= seedCopy)
                        {
                            // Candidate must be after startDate because
                            // we want the NEXT occurrence
                            if (candidate <= periodStart)
                            {
                                invalidCandidateCount++;
                            }
                            else if (pattern.Count > 0 && invalidCandidateCount >= pattern.Count)
                            {
                                break;
                            }
                            else if (pattern.Until == DateTime.MinValue || candidate <= pattern.Until)
                            {
                                return candidate;
                            }
                        }
                    }
                }
                else
                {
                    noCandidateIncrementCount++;
                    if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount))
                        break;
                }

                IncrementDate(ref seedCopy, pattern, pattern.Interval);
            }
            return null;
        }
        /**
         * Returns a list of applicable dates corresponding to the specified week day in accordance with the frequency
         * specified by this recurrence rule.
         * @param date
         * @param weekDay
         * @return
         */
        private List<DateTime> GetAbsWeekDays(DateTime date, IWeekDay weekDay, IRecurrencePattern pattern, bool? expand)
        {
            List<DateTime> days = new List<DateTime>();

            DayOfWeek dayOfWeek = weekDay.DayOfWeek;
            if (pattern.Frequency == FrequencyType.Daily)
            {
                if (date.DayOfWeek == dayOfWeek)
                    days.Add(date);
            }
            else if (pattern.Frequency == FrequencyType.Weekly || pattern.ByWeekNo.Count > 0)
            {
                // Rewind to the first day of the week
                while (date.DayOfWeek != pattern.FirstDayOfWeek)
                    date = date.AddDays(-1);

                // Step forward until we're on the day of week we're interested in
                while (date.DayOfWeek != dayOfWeek)
                    date = date.AddDays(1);
                
                days.Add(date);                   
            }
            else if (pattern.Frequency == FrequencyType.Monthly || pattern.ByMonth.Count > 0)
            {
                int month = date.Month;

                // construct a list of possible month days..
                date = date.AddDays(-date.Day + 1);
                while (date.DayOfWeek != dayOfWeek)
                    date = date.AddDays(1);

                while (date.Month == month)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            else if (pattern.Frequency == FrequencyType.Yearly)
            {
                int year = date.Year;

                // construct a list of possible year days..
                date = date.AddDays(-date.DayOfYear + 1);
                while (date.DayOfWeek != dayOfWeek)
                    date = date.AddDays(1);

                while (date.Year == year)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            return GetOffsetDates(days, weekDay.Offset);
        }
        /**
         * Applies BYSETPOS rules to <code>dates</code>. Valid positions are from 1 to the size of the date list. Invalid
         * positions are ignored.
         * @param dates
         */
        private List<DateTime> ApplySetPosRules(List<DateTime> dates, IRecurrencePattern pattern)
        {
            // return if no SETPOS rules specified..
            if (pattern.BySetPosition.Count == 0)
                return dates;

            // sort the list before processing..
            dates.Sort();

            List<DateTime> setPosDates = new List<DateTime>();
            int size = dates.Count;

            for (int i = 0; i < pattern.BySetPosition.Count; i++)
            {
                int pos = pattern.BySetPosition[i];
                if (pos > 0 && pos <= size)
                {
                    setPosDates.Add(dates[pos - 1]);
                }
                else if (pos < 0 && pos >= -size)
                {
                    setPosDates.Add(dates[size + pos]);
                }
            }
            return setPosDates;
        }
        /**
         * Applies BYMINUTE rules specified in this Recur instance to the specified date list. If no BYMINUTE rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetMinuteVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByMinute.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> minutelyDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMinute.Count; j++)
                    {
                        int minute = pattern.ByMinute[j];
                        date = date.AddMinutes(-date.Minute + minute);
                        minutelyDates.Add(date);
                    }
                }
                return minutelyDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByMinute.Count; j++)
                    {
                        int minute = pattern.ByMinute[j];
                        if (date.Minute == minute)
                            goto Next;
                    }
                    // Remove unmatched dates
                    dates.RemoveAt(i);
                Next: ;
                }
                return dates;
            }
        }
        /**
         * Applies BYWEEKNO rules specified in this Recur instance to the specified date list. If no BYWEEKNO rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetWeekNoVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByWeekNo.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> weekNoDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByWeekNo.Count; j++)
                    {
                        // Determine our target week number
                        int weekNo = pattern.ByWeekNo[j];

                        // Determine our current week number
                        int currWeekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
                        while (currWeekNo > weekNo)
                        {
                            // If currWeekNo > weekNo, then we're likely at the start of a year
                            // where currWeekNo could be 52 or 53.  If we simply step ahead 7 days
                            // we should be back to week 1, where we can easily make the calculation
                            // to move to weekNo.
                            date = date.AddDays(7);
                            currWeekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
                        }

                        // Move ahead to the correct week of the year
                        date = date.AddDays((weekNo - currWeekNo) * 7);

                        // Step backward single days until we're at the correct DayOfWeek
                        while (date.DayOfWeek != pattern.FirstDayOfWeek)
                            date = date.AddDays(-1);

                        for (int k = 0; k < 7; k++)
                        {
                            weekNoDates.Add(date);
                            date = date.AddDays(1);
                        }
                    }
                }
                return weekNoDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByWeekNo.Count; j++)
                    {
                        // Determine our target week number
                        int weekNo = pattern.ByWeekNo[j];

                        // Determine our current week number
                        int currWeekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);

                        if (weekNo == currWeekNo)
                            goto Next;
                    }

                    dates.RemoveAt(i);
                Next: ;
                }
                return dates;
            }
        }
Esempio n. 30
0
        /**
         * Returns a list of start dates in the specified period represented by this recur. This method includes a base date
         * argument, which indicates the start of the fist occurrence of this recurrence. The base date is used to inject
         * default values to return a set of dates in the correct format. For example, if the search start date (start) is
         * Wed, Mar 23, 12:19PM, but the recurrence is Mon - Fri, 9:00AM - 5:00PM, the start dates returned should all be at
         * 9:00AM, and not 12:19PM.
         */
        private List <DateTime> GetDates(IDateTime seed, DateTime periodStart, DateTime periodEnd, int maxCount, IRecurrencePattern pattern, bool includeReferenceDateInResults)
        {
            List <DateTime> dates        = new List <DateTime>();
            DateTime        originalDate = DateUtil.GetSimpleDateTimeData(seed);
            DateTime        seedCopy     = DateUtil.GetSimpleDateTimeData(seed);

            if (includeReferenceDateInResults)
            {
                dates.Add(seedCopy);
            }

            // If the interval is set to zero, or our count prevents us
            // from getting additional items, then return with the reference
            // date only.
            if (pattern.Interval == 0 ||
                (pattern.Count != int.MinValue && pattern.Count <= dates.Count))
            {
                return(dates);
            }

            // optimize the start time for selecting candidates
            // (only applicable where a COUNT is not specified)
            if (pattern.Count == int.MinValue)
            {
                DateTime incremented = seedCopy;
                // FIXME: we can more aggresively increment here when
                // the difference between dates is greater.
                IncrementDate(ref incremented, pattern, pattern.Interval);
                while (incremented < periodStart)
                {
                    seedCopy = incremented;
                    IncrementDate(ref incremented, pattern, pattern.Interval);
                }
            }

            bool?[] expandBehavior = RecurrenceUtil.GetExpandBehaviorList(pattern);

            int      invalidCandidateCount     = 0;
            int      noCandidateIncrementCount = 0;
            DateTime candidate = DateTime.MinValue;

            while ((maxCount < 0) || (dates.Count < maxCount))
            {
                if (pattern.Until != DateTime.MinValue && candidate != DateTime.MinValue && candidate > pattern.Until)
                {
                    break;
                }

                if (periodEnd != null && candidate != DateTime.MinValue && candidate > periodEnd)
                {
                    break;
                }

                if (pattern.Count >= 1 && (dates.Count + invalidCandidateCount) >= pattern.Count)
                {
                    break;
                }

                List <DateTime> candidates = GetCandidates(seedCopy, pattern, expandBehavior);
                if (candidates.Count > 0)
                {
                    noCandidateIncrementCount = 0;

                    // sort candidates for identifying when UNTIL date is exceeded..
                    candidates.Sort();

                    for (int i = 0; i < candidates.Count; i++)
                    {
                        candidate = candidates[i];

                        // don't count candidates that occur before the original date..
                        if (candidate >= originalDate)
                        {
                            // candidates MAY occur before periodStart
                            // For example, FREQ=YEARLY;BYWEEKNO=1 could return dates
                            // from the previous year.
                            //
                            // candidates exclusive of periodEnd..
                            if (candidate >= periodEnd)
                            {
                                invalidCandidateCount++;
                            }
                            else if (pattern.Count >= 1 && (dates.Count + invalidCandidateCount) >= pattern.Count)
                            {
                                break;
                            }
                            else if (pattern.Until == DateTime.MinValue || candidate <= pattern.Until)
                            {
                                if (!dates.Contains(candidate))
                                {
                                    dates.Add(candidate);
                                }
                            }
                        }
                    }
                }
                else
                {
                    noCandidateIncrementCount++;
                    if ((maxIncrementCount > 0) && (noCandidateIncrementCount > maxIncrementCount))
                    {
                        break;
                    }
                }

                IncrementDate(ref seedCopy, pattern, pattern.Interval);
            }

            // sort final list..
            dates.Sort();
            return(dates);
        }
        public RecurrencePatternEvaluator(IRecurrencePattern pattern)
	    {
            Pattern = pattern;
	    }
        /**
         * Returns a list of applicable dates corresponding to the specified week day in accordance with the frequency
         * specified by this recurrence rule.
         * @param date
         * @param weekDay
         * @return
         */
        private List<DateTime> GetAbsWeekDays(DateTime date, IWeekDay weekDay, IRecurrencePattern pattern, bool? expand)
        {
            List<DateTime> days = new List<DateTime>();

            DayOfWeek dayOfWeek = weekDay.DayOfWeek;
            if (pattern.Frequency == FrequencyType.Daily)
            {
                if (date.DayOfWeek == dayOfWeek)
                    days.Add(date);
            }
            else if (pattern.Frequency == FrequencyType.Weekly || pattern.ByWeekNo.Count > 0)
            {
                int weekNo = Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);

                // construct a list of possible week days..
                while (date.DayOfWeek != dayOfWeek)
                    date = date.AddDays(1);
                
                while (Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek) == weekNo)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            else if (pattern.Frequency == FrequencyType.Monthly || pattern.ByMonth.Count > 0)
            {
                int month = date.Month;

                // construct a list of possible month days..
                date = date.AddDays(-date.Day + 1);
                while (date.DayOfWeek != dayOfWeek)
                    date = date.AddDays(1);

                while (date.Month == month)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            else if (pattern.Frequency == FrequencyType.Yearly)
            {
                int year = date.Year;
                
                // construct a list of possible year days..
                date = date.AddDays(-date.DayOfYear + 1);
                while (date.DayOfWeek != dayOfWeek)
                    date = date.AddDays(1);

                while (date.Year == year)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            return GetOffsetDates(days, weekDay.Offset);
        }
        /**
         * Applies BYDAY rules specified in this Recur instance to the specified date list. If no BYDAY rules are specified
         * the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetDayVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByDay.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> weekDayDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByDay.Count; j++)
                    {
                        weekDayDates.AddRange(GetAbsWeekDays(date, pattern.ByDay[j], pattern, expand));
                    }
                }

                return weekDayDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByDay.Count; j++)
                    {
                        IWeekDay weekDay = pattern.ByDay[j];
                        if (weekDay.DayOfWeek.Equals(date.DayOfWeek))
                        {
                            // If no offset is specified, simply test the day of week!
                            // FIXME: test with offset...
                            if (date.DayOfWeek.Equals(weekDay.DayOfWeek))
                                goto Next;
                        }
                    }
                    dates.RemoveAt(i);
                Next: ;
                }

                return dates;
            }
        }
Esempio n. 34
0
        /**
         * Returns a list of applicable dates corresponding to the specified week day in accordance with the frequency
         * specified by this recurrence rule.
         * @param date
         * @param weekDay
         * @return
         */
        private List <DateTime> GetAbsWeekDays(DateTime date, IWeekDay weekDay, IRecurrencePattern pattern, bool?expand)
        {
            List <DateTime> days = new List <DateTime>();

            DayOfWeek dayOfWeek = weekDay.DayOfWeek;

            if (pattern.Frequency == FrequencyType.Daily)
            {
                if (date.DayOfWeek == dayOfWeek)
                {
                    days.Add(date);
                }
            }
            else if (pattern.Frequency == FrequencyType.Weekly || pattern.ByWeekNo.Count > 0)
            {
                // Rewind to the first day of the week
                while (date.DayOfWeek != pattern.FirstDayOfWeek)
                {
                    date = date.AddDays(-1);
                }

                // Step forward until we're on the day of week we're interested in
                while (date.DayOfWeek != dayOfWeek)
                {
                    date = date.AddDays(1);
                }

                days.Add(date);
            }
            else if (pattern.Frequency == FrequencyType.Monthly || pattern.ByMonth.Count > 0)
            {
                int month = date.Month;

                // construct a list of possible month days..
                date = date.AddDays(-date.Day + 1);
                while (date.DayOfWeek != dayOfWeek)
                {
                    date = date.AddDays(1);
                }

                while (date.Month == month)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            else if (pattern.Frequency == FrequencyType.Yearly)
            {
                int year = date.Year;

                // construct a list of possible year days..
                date = date.AddDays(-date.DayOfYear + 1);
                while (date.DayOfWeek != dayOfWeek)
                {
                    date = date.AddDays(1);
                }

                while (date.Year == year)
                {
                    days.Add(date);
                    date = date.AddDays(7);
                }
            }
            return(GetOffsetDates(days, weekDay.Offset));
        }
        /**
         * Applies BYHOUR rules specified in this Recur instance to the specified date list. If no BYHOUR rules are
         * specified the date list is returned unmodified.
         * @param dates
         * @return
         */
        private List<DateTime> GetHourVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
        {
            if (expand == null || pattern.ByHour.Count == 0)
                return dates;

            if (expand.HasValue && expand.Value)
            {
                // Expand behavior
                List<DateTime> hourlyDates = new List<DateTime>();
                for (int i = 0; i < dates.Count; i++)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByHour.Count; j++)
                    {
                        int hour = pattern.ByHour[j];
                        date = date.AddHours(-date.Hour + hour);
                        hourlyDates.Add(date);
                    }
                }
                return hourlyDates;
            }
            else
            {
                // Limit behavior
                for (int i = dates.Count - 1; i >= 0; i--)
                {
                    DateTime date = dates[i];
                    for (int j = 0; j < pattern.ByHour.Count; j++)
                    {
                        int hour = pattern.ByHour[j];
                        if (date.Hour == hour)
                            goto Next;
                    }
                    // Remove unmatched dates
                    dates.RemoveAt(i);
                Next: ;
                }
                return dates;
            }
        }
Esempio n. 36
0
		public IEnumerable<SEvent> GetRecurringEvents(IEvent evnt, IRecurrencePattern recur)
		{
			if (evnt == null || recur == null || evnt.UID.IsNullOrEmpty())
				yield break;
			SEvent rEvent = ToEvent(evnt, true);
			if (rEvent == null)
				yield break;

			rEvent.RRuleStr = recur.ToString();
			if (rEvent.RRuleStr.IsNullOrEmpty())
				yield break;

			DateTime maxDT = _now.AddMonths(3);

			IList<Occurrence> occurrences = evnt.GetOccurrences(EarliestIncludeEventTime, maxDT);

			if (occurrences == null)
				yield break;

			//if (occurrences.Count < 2) {
			//	occurrences = evnt.GetOccurrences(EarliestIncludeEventTime, maxDT);
			//	if (occurrences == null || occurrences.Count == 0)
			//		yield break;
			//}
			if (occurrences.IsNullOrEmpty())
				yield break;

			if (occurrences.Count > 9)
				occurrences = occurrences.Take(9).ToList();

			DateTime updated = evnt.LastModified.ToDateTime(evnt.Start.ToDateTime(_now));

			for (int i = 0; i < occurrences.Count; i++) {
	
				IPeriod period = occurrences[i].Period;
				if (period == null || period.StartTime == null)
					continue;
				if (period.EndTime == null)
					period.EndTime = period.StartTime;

				bool hasTime;
				DateTimeOffset start = GetLocalTime(period.StartTime, _currentTZ, out hasTime);
				
				string idAppend = i < 1 ? null : "_recur-" + i + "-" + start.Date.XmlTime();
				var ev = rEvent.Copy(idAppend);

				ev.Start = start;
				ev.End = GetLocalTime(period.EndTime, _currentTZ, out hasTime);
				ev.Updated = SetUpdatedEventTimeToStartTime ? ev.Start.DateTime : updated;
				ev.IsAllDay = ev.Start.TimeOfDay == con_EmptyTime && ev.End.TimeOfDay == con_EmptyTime;

				yield return ev;
			}
		}
 /**
  * Applies BYSECOND rules specified in this Recur instance to the specified date list. If no BYSECOND rules are
  * specified the date list is returned unmodified.
  * @param dates
  * @return
  */
 private List<DateTime> GetSecondVariants(List<DateTime> dates, IRecurrencePattern pattern, bool? expand)
 {
     if (expand == null || pattern.BySecond.Count == 0)
         return dates;
                 
     if (expand.HasValue && expand.Value)
     {
         // Expand behavior
         List<DateTime> secondlyDates = new List<DateTime>();
         for (int i = 0; i < dates.Count; i++)
         {
             DateTime date = dates[i];
             for (int j = 0; j < pattern.BySecond.Count; j++)
             {
                 int second = pattern.BySecond[j];
                 date = date.AddSeconds(-date.Second + second);
                 secondlyDates.Add(date);
             }
         }
         return secondlyDates;
     }
     else
     {
         // Limit behavior
         for (int i = dates.Count - 1; i >= 0; i--)
         {
             DateTime date = dates[i];
             for (int j = 0; j < pattern.BySecond.Count; j++)
             {
                 int second = pattern.BySecond[j];
                 if (date.Second == second)
                     goto Next;
             }
             // Remove unmatched dates
             dates.RemoveAt(i);
         Next: ;
         }
         return dates;
     }            
 }
Esempio n. 38
0
        private void EnforceEvaluationRestrictions(IRecurrencePattern pattern)
        {
            RecurrenceEvaluationModeType?evaluationMode        = pattern.EvaluationMode;
            RecurrenceRestrictionType?   evaluationRestriction = pattern.RestrictionType;

            if (evaluationRestriction != RecurrenceRestrictionType.NoRestriction)
            {
                switch (evaluationMode)
                {
                case RecurrenceEvaluationModeType.AdjustAutomatically:
                    switch (pattern.Frequency)
                    {
                    case FrequencyType.Secondly:
                    {
                        switch (evaluationRestriction)
                        {
                        case RecurrenceRestrictionType.Default:
                        case RecurrenceRestrictionType.RestrictSecondly: pattern.Frequency = FrequencyType.Minutely; break;

                        case RecurrenceRestrictionType.RestrictMinutely: pattern.Frequency = FrequencyType.Hourly; break;

                        case RecurrenceRestrictionType.RestrictHourly: pattern.Frequency = FrequencyType.Daily; break;
                        }
                    } break;

                    case FrequencyType.Minutely:
                    {
                        switch (evaluationRestriction)
                        {
                        case RecurrenceRestrictionType.RestrictMinutely: pattern.Frequency = FrequencyType.Hourly; break;

                        case RecurrenceRestrictionType.RestrictHourly: pattern.Frequency = FrequencyType.Daily; break;
                        }
                    } break;

                    case FrequencyType.Hourly:
                    {
                        switch (evaluationRestriction)
                        {
                        case RecurrenceRestrictionType.RestrictHourly: pattern.Frequency = FrequencyType.Daily; break;
                        }
                    } break;

                    default: break;
                    }
                    break;

                case RecurrenceEvaluationModeType.ThrowException:
                case RecurrenceEvaluationModeType.Default:
                    switch (pattern.Frequency)
                    {
                    case FrequencyType.Secondly:
                    {
                        switch (evaluationRestriction)
                        {
                        case RecurrenceRestrictionType.Default:
                        case RecurrenceRestrictionType.RestrictSecondly:
                        case RecurrenceRestrictionType.RestrictMinutely:
                        case RecurrenceRestrictionType.RestrictHourly:
                            throw new EvaluationEngineException();
                        }
                    } break;

                    case FrequencyType.Minutely:
                    {
                        switch (evaluationRestriction)
                        {
                        case RecurrenceRestrictionType.RestrictMinutely:
                        case RecurrenceRestrictionType.RestrictHourly:
                            throw new EvaluationEngineException();
                        }
                    } break;

                    case FrequencyType.Hourly:
                    {
                        switch (evaluationRestriction)
                        {
                        case RecurrenceRestrictionType.RestrictHourly:
                            throw new EvaluationEngineException();
                        }
                    } break;

                    default: break;
                    }
                    break;
                }
            }
        }