/// <summary> /// Calculates the first time an <see cref="NthIncludedDayTrigger" /> with /// intervalType = <see cref="IntervalTypeYearly" /> will fire /// after the specified date. See <see cref="GetNextFireTimeUtc" /> for more /// information. /// </summary> /// <param name="afterDateUtc"> /// The UTC time after which to find the nearest fire time. /// This argument is treated as exclusive 舒 that is, /// if afterTime is a valid fire time for the trigger, it /// will not be returned as the next fire time. /// </param> /// <returns> the first time the trigger will fire following the specified /// date /// </returns> private DateTimeOffset?GetYearlyFireTimeAfter(DateTimeOffset afterDateUtc) { int currN = 0; DateTimeOffset currCal = TimeZoneUtil.ConvertTime(afterDateUtc, TimeZone); currCal = new DateTime(currCal.Year, 1, 1, fireAtHour, fireAtMinute, fireAtSecond, 0); int currYear; int yearCount = 0; bool gotOne = false; currYear = currCal.Year; while ((!gotOne) && (yearCount < nextFireCutoffInterval)) { while ((currN != n) && (yearCount < 5)) { //if we move into a new year, reset the current "n" counter if (currCal.Year != currYear) { currN = 0; yearCount++; currYear = currCal.Year; } //treating a null calendar as an all-inclusive calendar, // increment currN if the current date being tested is included // on the calendar if (calendar == null || calendar.IsTimeIncluded(currCal)) { currN++; } if (currN != n) { currCal = currCal.AddDays(1); } //if we pass endTime, drop out and return null. if (EndTimeUtc.HasValue && TimeZoneUtil.ConvertTime(currCal, TimeZone) > EndTimeUtc.Value) { return(null); } } //We found an "n" or we've checked the requisite number of years. // If we've found an "n", is it the right one? -- that is, we // could be looking at an nth day PRIOR to afterDateUtc if (currN == n) { if (afterDateUtc < TimeZoneUtil.ConvertTime(currCal, TimeZone)) { gotOne = true; } else { //resume checking on the first day of the next year currCal = new DateTime(currCal.Year + 1, 1, 1, currCal.Hour, currCal.Minute, currCal.Second); currN = 0; } } } if (yearCount < nextFireCutoffInterval) { return(TimeZoneUtil.ConvertTime(currCal, TimeZone)); } else { return(null); } }
/// <summary> /// Calculate and set the EndTimeOfDay using count, interval and StarTimeOfDay. This means /// that these must be set before this method is call. /// </summary> /// <param name="count"></param> /// <returns>the updated DailyTimeIntervalScheduleBuilder</returns> public DailyTimeIntervalScheduleBuilder EndingDailyAfterCount(int count) { if (count <= 0) { throw new ArgumentException("Ending daily after count must be a positive number!"); } if (startTimeOfDayUtc == null) { throw new ArgumentException("You must set the StartDailyAt() before calling this EndingDailyAfterCount()!"); } DateTimeOffset today = SystemTime.UtcNow(); DateTimeOffset startTimeOfDayDate = startTimeOfDayUtc.GetTimeOfDayForDate(today); DateTimeOffset maxEndTimeOfDayDate = TimeOfDay.HourMinuteAndSecondOfDay(23, 59, 59).GetTimeOfDayForDate(today); //apply proper offsets according to timezone TimeZoneInfo targetTimeZone = timeZone ?? TimeZoneInfo.Local; startTimeOfDayDate = new DateTimeOffset(startTimeOfDayDate.DateTime, TimeZoneUtil.GetUtcOffset(startTimeOfDayDate.DateTime, targetTimeZone)); maxEndTimeOfDayDate = new DateTimeOffset(maxEndTimeOfDayDate.DateTime, TimeZoneUtil.GetUtcOffset(maxEndTimeOfDayDate.DateTime, targetTimeZone)); TimeSpan remainingMillisInDay = maxEndTimeOfDayDate - startTimeOfDayDate; TimeSpan intervalInMillis; if (intervalUnit == IntervalUnit.Second) { intervalInMillis = TimeSpan.FromSeconds(interval); } else if (intervalUnit == IntervalUnit.Minute) { intervalInMillis = TimeSpan.FromMinutes(interval); } else if (intervalUnit == IntervalUnit.Hour) { intervalInMillis = TimeSpan.FromHours(interval); } else { throw new ArgumentException("The IntervalUnit: " + intervalUnit + " is invalid for this trigger."); } if (remainingMillisInDay < intervalInMillis) { throw new ArgumentException("The startTimeOfDay is too late with given Interval and IntervalUnit values."); } long maxNumOfCount = remainingMillisInDay.Ticks / intervalInMillis.Ticks; if (count > maxNumOfCount) { throw new ArgumentException("The given count " + count + " is too large! The max you can set is " + maxNumOfCount); } TimeSpan incrementInMillis = TimeSpan.FromTicks((count - 1) * intervalInMillis.Ticks); DateTimeOffset endTimeOfDayDate = startTimeOfDayDate.Add(incrementInMillis); if (endTimeOfDayDate > maxEndTimeOfDayDate) { throw new ArgumentException("The given count " + count + " is too large! The max you can set is " + maxNumOfCount); } DateTime cal = SystemTime.UtcNow().Date; cal = cal.Add(endTimeOfDayDate.TimeOfDay); endTimeOfDayUtc = TimeOfDay.HourMinuteAndSecondOfDay(cal.Hour, cal.Minute, cal.Second); return(this); }
/// <summary> /// Calculates the first time an <see cref="NthIncludedDayTrigger" /> with /// <c>intervalType = IntervalTypeWeekly</c> will fire /// after the specified date. See <see cref="GetNextFireTimeUtc" /> for more /// information. /// </summary> /// <param name="afterDateUtc">The time after which to find the nearest fire time. /// This argument is treated as exclusive 舒 that is, /// if afterTime is a valid fire time for the trigger, it /// will not be returned as the next fire time. /// </param> /// <returns> the first time the trigger will fire following the specified /// date /// </returns> private DateTimeOffset?GetWeeklyFireTimeAfter(DateTimeOffset afterDateUtc) { int currN = 0; int currWeek; int weekCount = 0; bool gotOne = false; afterDateUtc = TimeZoneUtil.ConvertTime(afterDateUtc, TimeZone); DateTime currCal = new DateTime(afterDateUtc.Year, afterDateUtc.Month, afterDateUtc.Day); // move to the first day of the week // TODO, we are still bound to fixed local time zone as with TimeZone property while (currCal.DayOfWeek != DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek) { currCal = currCal.AddDays(-1); } currCal = new DateTime(currCal.Year, currCal.Month, currCal.Day, fireAtHour, fireAtMinute, fireAtSecond, 0); currWeek = GetWeekOfYear(currCal); while ((!gotOne) && (weekCount < nextFireCutoffInterval)) { while ((currN != n) && (weekCount < 12)) { //if we move into a new week, reset the current "n" counter if (GetWeekOfYear(currCal) != currWeek) { currN = 0; weekCount++; currWeek = GetWeekOfYear(currCal); } //treating a null calendar as an all-inclusive calendar, // increment currN if the current date being tested is included // on the calendar if ((calendar == null) || calendar.IsTimeIncluded(currCal)) { currN++; } if (currN != n) { currCal = currCal.AddDays(1); } //if we pass endTime, drop out and return null. if (EndTimeUtc.HasValue && TimeZoneInfo.ConvertTimeToUtc(currCal, TimeZone) > EndTimeUtc.Value) { return(null); } } // We found an "n" or we've checked the requisite number of weeks. // If we've found an "n", is it the right one? -- that is, we could // be looking at an nth day PRIOR to afterDateUtc if (currN == n) { if (afterDateUtc < TimeZoneInfo.ConvertTimeToUtc(currCal, TimeZone)) { gotOne = true; } else { // resume checking on the first day of the next week // move back to the beginning of the week and add 7 days // TODO, need to correlate with time zone in .NET 3.5 while (currCal.DayOfWeek != DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek) { currCal = currCal.AddDays(-1); } currCal = currCal.AddDays(7); currN = 0; } } } if (weekCount < nextFireCutoffInterval) { return(TimeZoneInfo.ConvertTimeToUtc(currCal, TimeZone)); } else { return(null); } }