/// <summary> /// Gets the date and time of the next occurrence from <paramref name="now"/>. /// </summary> /// <param name="now">The current date and time assumed to be an universal time if not specified to avoid invalid and ambiguous times.</param> /// <returns>The date and time of the next occurrence in local time.</returns> protected override DateTime GetNextTime(DateTime inNow) { var now = inNow.AsLocalTime(); // consider first occurrence var firstOccurrence = (timesOfDayQueue == null); // initialize timesOfDayQueue if necessary if (timesOfDayQueue == null) { // consider current dayOfWeek not in requested WeekDays if ((WeekDays & FlagsEnum.PowerOfTwo <RecurrentWeekDays>(now.DayOfWeek)) != FlagsEnum.PowerOfTwo <RecurrentWeekDays>(now.DayOfWeek)) { timesOfDayQueue = new Queue <TimeSpan>(TimesOfDay); } else { // order the timesOfDay according to the current date and time timesOfDayQueue = new Queue <TimeSpan>(TimesOfDay .SkipWhile(match => match <= now.TimeOfDay) .Concat(TimesOfDay) .Take(TimesOfDay.Count()) .DefaultIfEmpty(TimesOfDay.First())); } } // remove the current timeOfDay from the queue var timeOfDay = timesOfDayQueue.Dequeue(); // add the current timeOfDay to the end timesOfDayQueue.Enqueue(timeOfDay); // get today to maintain the specified timeOfDay across the daylight time var today = now.Date.AsLocalTime(); // shift today if necessary in order to calculate correctly the next date if ((firstOccurrence && now.TimeOfDay < timeOfDay) || (!firstOccurrence && timesOfDayQueue.Count > 1 && timeOfDay > timesOfDayQueue.Min())) { today = today.AddDays(-1); } // get the next date var nextDate = GetNextDateByDayOfWeek(today); // keep the found next date var index = (int)nextDate.DayOfWeek; if (nextDates[index] != null && nextDates[index].Value < nextDate) { nextDate = nextDates[index].Value.AddDays(7 * Weeks); } nextDates[index] = nextDate; // consider next time validity if (TimeZoneContext.Current.TimeZoneInfo.IsInvalidTime(nextDate.Add(timeOfDay)) && Behavior.InvalidTime == InvalidTimeBehavior.Skip) { // get the next valid time return(GetNextTime(nextDate)); } // consider next time ambiguity if (TimeZoneContext.Current.TimeZoneInfo.IsAmbiguousTime(nextDate.Add(timeOfDay)) && Behavior.AmbiguousTime == AmbiguousTimeBehavior.DaylightTime) { // get the next time from the universal time return(nextDate.AsUniversalTime().Add(timeOfDay).AsLocalTime()); } // get the next time from the local time return(nextDate.Add(timeOfDay)); }
/// <summary> /// Gets the date and time of the next occurrence from <paramref name="now"/>. /// </summary> /// <param name="now">The current date and time assumed to be an universal time if not specified to avoid invalid and ambiguous times.</param> /// <returns>The date and time of the next occurrence in local time.</returns> protected override DateTime GetNextTime(DateTime inNow) { if (inNow.Kind == DateTimeKind.Unspecified) { throw new InvalidTimeZoneException("DateTime Kind should be set. Unspecified is unsupported!"); } var now = inNow.AsLocalTime(); // consider first occurrence var firstOccurrence = (timesOfDayQueue == null); // initialize timesOfDayQueue if necessary if (timesOfDayQueue == null) { // consider current dayOfWeek not in requested WeekDays if (Days == 0 && (WeekDays & FlagsEnum.PowerOfTwo <RecurrentWeekDays>(now.DayOfWeek)) != FlagsEnum.PowerOfTwo <RecurrentWeekDays>(now.DayOfWeek)) { timesOfDayQueue = new Queue <TimeSpan>(TimesOfDay); } else { // order the timesOfDay according to the current date and time timesOfDayQueue = new Queue <TimeSpan>(TimesOfDay .SkipWhile(match => match <= now.TimeOfDay) .Concat(TimesOfDay) .Take(TimesOfDay.Count()) .DefaultIfEmpty(TimesOfDay.First())); } } // remove the current timeOfDay from the queue var timeOfDay = timesOfDayQueue.Dequeue(); // add the current timeOfDay to the end timesOfDayQueue.Enqueue(timeOfDay); // get today to maintain the specified timeOfDay across the daylight time var today = now.Date; // shift today if necessary in order to calculate correctly the next date if ((firstOccurrence && now.TimeOfDay < timeOfDay) || (!firstOccurrence && timesOfDayQueue.Count > 1 && timeOfDay > timesOfDayQueue.Min())) { today = today.AddDays(Days != 0 ? -Days : -1); } // get the next date var nextDate = (Days != 0) ? today.AddDays(Days) : GetNextDateByDayOfWeek(today); // consider next time validity if (TimeZoneContext.Current.TimeZoneInfo.IsInvalidTime(nextDate.Add(timeOfDay)) && Behavior.InvalidTime == InvalidTimeBehavior.Skip) { // get the next valid time return(GetNextTime(nextDate)); } // consider next time ambiguity if (TimeZoneContext.Current.TimeZoneInfo.IsAmbiguousTime(nextDate.Add(timeOfDay)) && Behavior.AmbiguousTime == AmbiguousTimeBehavior.DaylightTime) { // get the next time from the universal time return(nextDate.AsUniversalTime().Add(timeOfDay).AsLocalTime()); } // get the next time from the local time return(nextDate.Add(timeOfDay)); }