/// <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"); } }
/// <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; }
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; } }
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."); } }
/// <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; }
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."); } }
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 }; } }
/** * 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; }
public RecurrencePatternEvaluator(IRecurrencePattern pattern) { Pattern = pattern; }
/** * 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 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); } }
/// <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; } } }
/// <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; } }
/** * 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); }
/** * 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; } }
/** * 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; } }
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; } }
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; } } }