Added some much-needed documentation
parent
135b6c3d7f
commit
0e5f31e649
|
@ -39,7 +39,7 @@ pub fn cron(conf Config) ? {
|
||||||
// }
|
// }
|
||||||
mut t := time.Time{
|
mut t := time.Time{
|
||||||
year: 2022
|
year: 2022
|
||||||
month: 2
|
month: 12
|
||||||
minute: 9
|
minute: 9
|
||||||
hour: 13
|
hour: 13
|
||||||
day: 12
|
day: 12
|
||||||
|
|
|
@ -12,13 +12,24 @@ struct CronExpression {
|
||||||
months []int
|
months []int
|
||||||
}
|
}
|
||||||
|
|
||||||
// next calculates the earliest time this cron expression is valid.
|
// next calculates the earliest time this cron expression is valid. It will
|
||||||
|
// always pick a moment in the future, even if ref matches completely up to the
|
||||||
|
// minute. This function conciously does not take gap years into account.
|
||||||
pub fn (ce &CronExpression) next(ref time.Time) ?time.Time {
|
pub fn (ce &CronExpression) next(ref time.Time) ?time.Time {
|
||||||
|
// For all of these values, the rule is the following: if their value is
|
||||||
|
// the length of their respective array in the CronExpression object, that
|
||||||
|
// means we've looped back around. This means that the "bigger" value has
|
||||||
|
// to be incremented by one. For example, if the minutes have looped
|
||||||
|
// around, that means that the hour has to be incremented as well.
|
||||||
mut minute_index := 0
|
mut minute_index := 0
|
||||||
mut hour_index := 0
|
mut hour_index := 0
|
||||||
mut day_index := 0
|
mut day_index := 0
|
||||||
mut month_index := 0
|
mut month_index := 0
|
||||||
|
|
||||||
|
// This chain is the same logic multiple times, namely that if a "bigger"
|
||||||
|
// value loops around, then the smaller value will always reset as well.
|
||||||
|
// For example, if we're going to a new day, the hour & minute will always
|
||||||
|
// be their smallest value again.
|
||||||
for month_index < ce.months.len && ref.month > ce.months[month_index] {
|
for month_index < ce.months.len && ref.month > ce.months[month_index] {
|
||||||
month_index++
|
month_index++
|
||||||
}
|
}
|
||||||
|
@ -34,7 +45,9 @@ pub fn (ce &CronExpression) next(ref time.Time) ?time.Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
if hour_index < ce.hours.len {
|
if hour_index < ce.hours.len {
|
||||||
// For each unit, we calculate what the next value is
|
// Minute is the only value where we explicitely make sure we
|
||||||
|
// can't match ref's value exactly. This is to ensure we only
|
||||||
|
// return values in the future.
|
||||||
for minute_index < ce.minutes.len && ref.minute >= ce.minutes[minute_index] {
|
for minute_index < ce.minutes.len && ref.minute >= ce.minutes[minute_index] {
|
||||||
minute_index++
|
minute_index++
|
||||||
}
|
}
|
||||||
|
@ -42,8 +55,9 @@ pub fn (ce &CronExpression) next(ref time.Time) ?time.Time {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Here, we increment the "bigger" values by one if the smaller ones loop
|
||||||
// Sometime we have to shift values one more
|
// around. The order is important, as it allows a sort-of waterfall effect
|
||||||
|
// to occur which updates all values if required.
|
||||||
if minute_index == ce.minutes.len && hour_index < ce.hours.len {
|
if minute_index == ce.minutes.len && hour_index < ce.hours.len {
|
||||||
hour_index += 1
|
hour_index += 1
|
||||||
}
|
}
|
||||||
|
@ -60,19 +74,20 @@ pub fn (ce &CronExpression) next(ref time.Time) ?time.Time {
|
||||||
mut hour := ce.hours[hour_index % ce.hours.len]
|
mut hour := ce.hours[hour_index % ce.hours.len]
|
||||||
mut day := ce.days[day_index % ce.days.len]
|
mut day := ce.days[day_index % ce.days.len]
|
||||||
|
|
||||||
mut reset := false
|
// Sometimes, we end up with a day that does not exist within the selected
|
||||||
|
// month, e.g. day 30 in February. When this occurs, we reset day back to
|
||||||
// If the day can't be planned in the current month, we go to the next one
|
// the smallest value & loop over to the next month that does have this
|
||||||
// and go back to day one
|
// day.
|
||||||
if day > days_in_month[ce.months[month_index % ce.months.len] - 1] {
|
if day > days_in_month[ce.months[month_index % ce.months.len] - 1] {
|
||||||
month_index += 1
|
|
||||||
day = ce.days[0]
|
day = ce.days[0]
|
||||||
|
month_index += 1
|
||||||
|
|
||||||
// Make sure we only plan in a month that the day occurs in
|
|
||||||
for day > days_in_month[ce.months[month_index & ce.months.len] - 1] {
|
for day > days_in_month[ce.months[month_index & ce.months.len] - 1] {
|
||||||
month_index += 1
|
month_index += 1
|
||||||
|
|
||||||
// Prevent scenario where there are no months that can be scheduled.
|
// If for whatever reason the day value ends up being something
|
||||||
|
// that can't be scheduled in any month, we have to make sure we
|
||||||
|
// don't create an infinite loop.
|
||||||
if month_index == 2 * ce.months.len {
|
if month_index == 2 * ce.months.len {
|
||||||
return error('No schedulable moment.')
|
return error('No schedulable moment.')
|
||||||
}
|
}
|
||||||
|
@ -83,6 +98,7 @@ pub fn (ce &CronExpression) next(ref time.Time) ?time.Time {
|
||||||
month := ce.months[month_index % ce.months.len]
|
month := ce.months[month_index % ce.months.len]
|
||||||
mut year := ref.year
|
mut year := ref.year
|
||||||
|
|
||||||
|
// If the month loops over, we need to increment the year.
|
||||||
if month_index >= ce.months.len {
|
if month_index >= ce.months.len {
|
||||||
year++
|
year++
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue