public void Format(CrontabField field, TextWriter writer, bool noNames) { if (field == null) { throw new ArgumentNullException(nameof(field)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } var next = field.GetFirst(); var count = 0; while (next != -1) { var first = next; int last; do { last = next; next = field.Next(last + 1); } while (next - last == 1); if (count == 0 && first == MinValue && last == MaxValue) { writer.Write('*'); return; } if (count > 0) { writer.Write(','); } if (first == last) { FormatValue(first, writer, noNames); } else { FormatValue(first, writer, noNames); writer.Write('-'); FormatValue(last, writer, noNames); } count++; } }
public DateTime GetNextOccurrence(DateTime baseTime, DateTime endTime) { const int nil = -1; var baseYear = baseTime.Year; var baseMonth = baseTime.Month; var baseDay = baseTime.Day; var baseHour = baseTime.Hour; var baseMinute = baseTime.Minute; var endYear = endTime.Year; var endMonth = endTime.Month; var endDay = endTime.Day; var year = baseYear; var month = baseMonth; var day = baseDay; var hour = baseHour; var minute = baseMinute + 1; // // Minute // minute = minutes.Next(minute); if (minute == nil) { minute = minutes.GetFirst(); hour++; } // // Hour // hour = hours.Next(hour); if (hour == nil) { minute = minutes.GetFirst(); hour = hours.GetFirst(); day++; } else if (hour > baseHour) { minute = minutes.GetFirst(); } // // Day // day = days.Next(day); RetryDayMonth: if (day == nil) { minute = minutes.GetFirst(); hour = hours.GetFirst(); day = days.GetFirst(); month++; } else if (day > baseDay) { minute = minutes.GetFirst(); hour = hours.GetFirst(); } // // Month // month = months.Next(month); if (month == nil) { minute = minutes.GetFirst(); hour = hours.GetFirst(); day = days.GetFirst(); month = months.GetFirst(); year++; } else if (month > baseMonth) { minute = minutes.GetFirst(); hour = hours.GetFirst(); day = days.GetFirst(); } // // The day field in a cron expression spans the entire range of days // in a month, which is from 1 to 31. However, the number of days in // a month tend to be variable depending on the month (and the year // in case of February). So a check is needed here to see if the // date is a border case. If the day happens to be beyond 28 // (meaning that we're dealing with the suspicious range of 29-31) // and the date part has changed then we need to determine whether // the day still makes sense for the given year and month. If the // day is beyond the last possible value, then the day/month part // for the schedule is re-evaluated. So an expression like "0 0 // 15,31 * *" will yield the following sequence starting on midnight // of Jan 1, 2000: // // Jan 15, Jan 31, Feb 15, Mar 15, Apr 15, Apr 31, ... // var dateChanged = day != baseDay || month != baseMonth || year != baseYear; if (day > 28 && dateChanged && day > Calendar.GetDaysInMonth(year, month)) { if (year >= endYear && month >= endMonth && day >= endDay) { return(endTime); } day = nil; goto RetryDayMonth; } var nextTime = new DateTime(year, month, day, hour, minute, 0, 0, baseTime.Kind); if (nextTime >= endTime) { return(endTime); } // // Day of week // if (daysOfWeek.Contains((int)nextTime.DayOfWeek)) { return(nextTime); } return(GetNextOccurrence(new DateTime(year, month, day, 23, 59, 0, 0, baseTime.Kind), endTime)); }