/// <summary> /// This method should not be used by the Quartz client. /// </summary> /// <remarks> /// <para> /// Called by the scheduler at the time a <see cref="ITrigger" /> is first /// added to the scheduler, in order to have the <see cref="ITrigger" /> /// compute its first fire time, based on any associated calendar. /// </para> /// /// <para> /// After this method has been called, <see cref="ITrigger.GetNextFireTimeUtc" /> /// should return a valid answer. /// </para> /// </remarks> /// <returns> /// The first time at which the <see cref="ITrigger" /> will be fired /// by the scheduler, which is also the same value <see cref="ITrigger.GetNextFireTimeUtc" /> /// will return (until after the first firing of the <see cref="ITrigger" />). /// </returns> public override DateTimeOffset?ComputeFirstFireTimeUtc(ICalendar calendar) { DateTimeOffset startTime = TimeZoneUtil.ConvertTime(StartTimeUtc, TimeZone); DateTimeOffset?startTimeOfDayDate = StartTimeOfDay.GetTimeOfDayForDate(startTime); // If startTime is after the timeOfDay, then use starTime if (startTime > startTimeOfDayDate) { nextFireTimeUtc = GetFireTimeAfter(startTime); } else { nextFireTimeUtc = AdvanceToNextDayOfWeek(startTimeOfDayDate.Value, false); } // Check calendar for date-time exclusion while (nextFireTimeUtc != null && calendar != null && !calendar.IsTimeIncluded(nextFireTimeUtc.Value)) { nextFireTimeUtc = GetFireTimeAfter(nextFireTimeUtc); if (nextFireTimeUtc == null) { break; } //avoid infinite loop if (nextFireTimeUtc.Value.Year > YearToGiveupSchedulingAt) { return(null); } } return(nextFireTimeUtc); }
/// <summary> /// Validates whether the properties of the <see cref="IJobDetail" /> are /// valid for submission into a <see cref="IScheduler" />. /// </summary> public override void Validate() { base.Validate(); if (repeatIntervalUnit != IntervalUnit.Second && repeatIntervalUnit != IntervalUnit.Minute && repeatIntervalUnit == IntervalUnit.Hour) { throw new SchedulerException("Invalid repeat IntervalUnit (must be Second, Minute or Hour)."); } if (repeatInterval < 1) { throw new SchedulerException("Repeat Interval cannot be zero."); } // Ensure interval does not exceed 24 hours const long SecondsInHour = 24 * 60 * 60L; if (repeatIntervalUnit == IntervalUnit.Second && repeatInterval > SecondsInHour) { throw new SchedulerException("repeatInterval can not exceed 24 hours (" + SecondsInHour + " seconds). Given " + repeatInterval); } if (repeatIntervalUnit == IntervalUnit.Minute && repeatInterval > SecondsInHour / 60L) { throw new SchedulerException("repeatInterval can not exceed 24 hours (" + SecondsInHour / 60L + " minutes). Given " + repeatInterval); } if (repeatIntervalUnit == IntervalUnit.Hour && repeatInterval > 24) { throw new SchedulerException("repeatInterval can not exceed 24 hours. Given " + repeatInterval + " hours."); } // Ensure timeOfDay is in order. if (EndTimeOfDay != null && !StartTimeOfDay.Before(EndTimeOfDay)) { throw new SchedulerException("StartTimeOfDay " + startTimeOfDay + " should not come after endTimeOfDay " + endTimeOfDay); } }
/// <summary> /// Returns the next time at which the <see cref="IDailyTimeIntervalTrigger" /> will /// fire, after the given time. If the trigger will not fire after the given /// time, <see langword="null" /> will be returned. /// </summary> /// <param name="afterTime"></param> /// <returns></returns> public override DateTimeOffset?GetFireTimeAfter(DateTimeOffset?afterTime) { // Check if trigger has completed or not. if (complete) { return(null); } // Check repeatCount limit if (repeatCount != RepeatIndefinitely && timesTriggered > repeatCount) { return(null); } // a. Increment afterTime by a second, so that we are comparing against a time after it! if (afterTime == null) { afterTime = SystemTime.UtcNow().AddSeconds(1); } else { afterTime = afterTime.Value.AddSeconds(1); } // if afterTime is before startTime, then return startTime directly. if (afterTime <= startTimeUtc) { return(startTimeUtc); } // now change to local time zone afterTime = TimeZoneUtil.ConvertTime(afterTime.Value, TimeZone); // b.Check to see if afterTime is after endTimeOfDay or not. // If yes, then we need to advance to next day as well. bool afterTimePassEndTimeOfDay = false; if (endTimeOfDay != null) { afterTimePassEndTimeOfDay = afterTime.Value > endTimeOfDay.GetTimeOfDayForDate(afterTime).Value; } DateTimeOffset?fireTime = AdvanceToNextDayOfWeek(afterTime.Value, afterTimePassEndTimeOfDay); if (fireTime == null) { return(null); } // apply timezone for this date & time fireTime = new DateTimeOffset(fireTime.Value.DateTime, TimeZone.GetUtcOffset(fireTime.Value)); // c. Calculate and save fireTimeEndDate variable for later use DateTimeOffset fireTimeEndDate; if (endTimeOfDay == null) { fireTimeEndDate = new TimeOfDay(23, 59, 59).GetTimeOfDayForDate(fireTime).Value; } else { fireTimeEndDate = endTimeOfDay.GetTimeOfDayForDate(fireTime).Value; } // apply the proper offset for the end date fireTimeEndDate = new DateTimeOffset(fireTimeEndDate.DateTime, this.TimeZone.GetUtcOffset(fireTimeEndDate.DateTime)); // e. Check fireTime against startTime or startTimeOfDay to see which go first. DateTimeOffset fireTimeStartDate = startTimeOfDay.GetTimeOfDayForDate(fireTime).Value; // apply the proper offset for the start date fireTimeStartDate = new DateTimeOffset(fireTimeStartDate.DateTime, this.TimeZone.GetUtcOffset(fireTimeStartDate.DateTime)); if (fireTime < startTimeUtc && startTimeUtc < fireTimeStartDate) { return(fireTimeStartDate); } if (fireTime < startTimeUtc && startTimeUtc > fireTimeStartDate) { return(startTimeUtc); } if (fireTime > startTimeUtc && fireTime < fireTimeStartDate) { return(fireTimeStartDate); } // Always adjust the startTime to be startTimeOfDay startTimeUtc = fireTimeStartDate.ToUniversalTime(); // f. Continue to calculate the fireTime by incremental unit of intervals. startTimeUtc = TimeZoneUtil.ConvertTime(startTimeUtc, TimeZone); long secondsAfterStart = (long)(fireTime.Value - startTimeUtc).TotalSeconds; long repeatLong = RepeatInterval; DateTimeOffset sTime = startTimeUtc; IntervalUnit repeatUnit = RepeatIntervalUnit; if (repeatUnit == IntervalUnit.Second) { long jumpCount = secondsAfterStart / repeatLong; if (secondsAfterStart % repeatLong != 0) { jumpCount++; } sTime = sTime.AddSeconds(RepeatInterval * (int)jumpCount); fireTime = sTime; } else if (repeatUnit == IntervalUnit.Minute) { long jumpCount = secondsAfterStart / (repeatLong * 60L); if (secondsAfterStart % (repeatLong * 60L) != 0) { jumpCount++; } sTime = sTime.AddMinutes(RepeatInterval * (int)jumpCount); fireTime = sTime; } else if (repeatUnit == IntervalUnit.Hour) { long jumpCount = secondsAfterStart / (repeatLong * 60L * 60L); if (secondsAfterStart % (repeatLong * 60L * 60L) != 0) { jumpCount++; } sTime = sTime.AddHours(RepeatInterval * (int)jumpCount); fireTime = sTime; } // g. Ensure this new fireTime is within one day, or else we need to advance to next day. if (fireTime > fireTimeEndDate) { // Check to see if fireTime has pass fireTime's end of day. If not, we need to advance by one day. DateTimeOffset fireTimeEndOfDay = new TimeOfDay(23, 59, 59).GetTimeOfDayForDate(fireTimeEndDate).Value; if (fireTime > fireTimeEndOfDay) { fireTime = AdvanceToNextDayOfWeek(fireTime.Value, false); } else { fireTime = AdvanceToNextDayOfWeek(fireTime.Value, true); } if (fireTime == null) { return(null); } // Check to see if next day fireTime is before startTimeOfDay, if not, we need to set to startTimeOfDay. DateTimeOffset nextDayfireTimeStartDate = StartTimeOfDay.GetTimeOfDayForDate(fireTime).Value; if (fireTime < nextDayfireTimeStartDate) { fireTime = nextDayfireTimeStartDate; } } // i. Return calculated fireTime. return(fireTime.Value.ToUniversalTime()); }