public DateTime GetNextScheduled()
{
ScheduleRepeater r = Schedule.ParseCronString(this.RepeatSchedule);
DateTime current = this.NextScheduledDate;
// if there's more than one time, and if there's a time that's later than the
// current, let's use the same day and return later time
foreach (Dictionary<string, int> t in r.Times)
{
// since we've sorted in order we loop through and return earliest time that's later than current
if (t["hours"] > current.Hour || (t["hours"] == current.Hour && t["minutes"] > current.Minute))
{
return new DateTime(current.Year, current.Month, current.Day, t["hours"], t["minutes"], 0);
}
}
// if there's no other times that're later than current, we continue and set the next date
// if there are specific dates set, we'll use the next date
// for each of the following, we'll use r.Times[0] as it'll be the first time that day, in case
// there are more than one time set to run
// to start we check to see if this is set up to skip months
if (r.SkipMonths != 0)
{
DateTime newDate = current.AddMonths(r.SkipMonths + 1);
return new DateTime(newDate.Year, newDate.Month, newDate.Day, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
//next we try checking for specific days of the month
if (r.DaysOfMonth.Count > 0)
{
DateTime newDate;
if (r.DaysOfMonth.Count == 1) // if there's only one day of the month, we just add a month
{
newDate = current.AddMonths(1); // addmonths automatically adjusts the day of the month back if
// it would overflow the month
return new DateTime(newDate.Year, newDate.Month, newDate.Day, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
// calculate number of days to add
int addDays = 0;
int daysThisMonth = DateTime.DaysInMonth(current.Year, current.Month);
DateTime nextMonth = current.AddMonths(1);
int daysNextMonth = DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month);
foreach (int date in r.DaysOfMonth)
{
// here we're checking for a later date this same month
if (date > current.Day)
{
if (date > daysThisMonth)
{
// if it's set to run on a date that's greater than the number of days in the month,
// we're going to default back to the last day of the month
addDays = daysThisMonth - current.Day;
}
else
{
addDays = date - current.Day;
}
break;
}
}
if (addDays == 0)
{
// if addDays is still 0, then whatever date we're on is the last shcduled for this month, and we
// need to move on to next month
if (r.DaysOfMonth[0] > daysNextMonth)
{
return new DateTime(nextMonth.Year, nextMonth.Month, daysNextMonth, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
else
{
addDays = daysThisMonth - current.Day + r.DaysOfMonth[0];
}
}
if (addDays == 0)
{
// if we're still running zero there may be a corner case where the process is repeating
// the last couple days every month and we're currently in a month that's shorter than the
// schedule. So we'll just return next month
return new DateTime(nextMonth.Year, nextMonth.Month, daysNextMonth, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
newDate = current.AddDays(addDays);
return new DateTime(newDate.Year, newDate.Month, newDate.Day, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
// if skipweeks is set we'll set a date that number of weeks ahead.
if (r.SkipWeeks != 0)
{
DateTime newDate = current.AddDays(7 * (r.SkipWeeks + 1));
return new DateTime(newDate.Year, newDate.Month, newDate.Day, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
// if we're going by days of the week, we'll set to run on the next available day which matches.
if (r.DaysOfWeek.Count > 0)
{
int addDays = 0;
foreach (int day in r.DaysOfWeek)
{
if (day > Convert.ToInt32(current.DayOfWeek))
{
// if there's a day later in the week
addDays = day - Convert.ToInt32(current.DayOfWeek);
break;
}
}
if (addDays == 0)
{
// we couldn't find a later day this week, so we'll go to next week
addDays = 7 - Convert.ToInt32(current.DayOfWeek) + r.DaysOfWeek[0];
}
// set new date based on adding number of days
DateTime newDate = current.AddDays(addDays);
// return datetime with earliest runtime that day
return new DateTime(newDate.Year, newDate.Month, newDate.Day, r.Times[0]["hours"], r.Times[0]["minutes"], 0);
}
throw new Exception("Cannot find next scheduled date. Parsing cronstring values yeilded no available dates.");
}