diff options
author | Unknown <joe2010xtmf@163.com> | 2014-06-13 13:01:52 -0400 |
---|---|---|
committer | Unknown <joe2010xtmf@163.com> | 2014-06-13 13:01:52 -0400 |
commit | d952b4200c7c024ff5a809a3885bc79be9e4cce9 (patch) | |
tree | b106d81f51a10144749e20c923713fd2c78643e4 /modules/cron/spec.go | |
parent | e07674bff19dcc321a1611a3598d69c418ac8642 (diff) | |
download | gitea-d952b4200c7c024ff5a809a3885bc79be9e4cce9.tar.gz gitea-d952b4200c7c024ff5a809a3885bc79be9e4cce9.zip |
Add corn rask monitor panel
Diffstat (limited to 'modules/cron/spec.go')
-rw-r--r-- | modules/cron/spec.go | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/modules/cron/spec.go b/modules/cron/spec.go new file mode 100644 index 0000000000..cb3743325d --- /dev/null +++ b/modules/cron/spec.go @@ -0,0 +1,161 @@ +package cron + +import ( + "time" +) + +// SpecSchedule specifies a duty cycle (to the second granularity), based on a +// traditional crontab specification. It is computed initially and stored as bit sets. +type SpecSchedule struct { + Second, Minute, Hour, Dom, Month, Dow uint64 +} + +// bounds provides a range of acceptable values (plus a map of name to value). +type bounds struct { + min, max uint + names map[string]uint +} + +// The bounds for each field. +var ( + seconds = bounds{0, 59, nil} + minutes = bounds{0, 59, nil} + hours = bounds{0, 23, nil} + dom = bounds{1, 31, nil} + months = bounds{1, 12, map[string]uint{ + "jan": 1, + "feb": 2, + "mar": 3, + "apr": 4, + "may": 5, + "jun": 6, + "jul": 7, + "aug": 8, + "sep": 9, + "oct": 10, + "nov": 11, + "dec": 12, + }} + dow = bounds{0, 6, map[string]uint{ + "sun": 0, + "mon": 1, + "tue": 2, + "wed": 3, + "thu": 4, + "fri": 5, + "sat": 6, + }} +) + +const ( + // Set the top bit if a star was included in the expression. + starBit = 1 << 63 +) + +// Next returns the next time this schedule is activated, greater than the given +// time. If no time can be found to satisfy the schedule, return the zero time. +func (s *SpecSchedule) Next(t time.Time) time.Time { + // General approach: + // For Month, Day, Hour, Minute, Second: + // Check if the time value matches. If yes, continue to the next field. + // If the field doesn't match the schedule, then increment the field until it matches. + // While incrementing the field, a wrap-around brings it back to the beginning + // of the field list (since it is necessary to re-verify previous field + // values) + + // Start at the earliest possible time (the upcoming second). + t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond) + + // This flag indicates whether a field has been incremented. + added := false + + // If no time is found within five years, return zero. + yearLimit := t.Year() + 5 + +WRAP: + if t.Year() > yearLimit { + return time.Time{} + } + + // Find the first applicable month. + // If it's this month, then do nothing. + for 1<<uint(t.Month())&s.Month == 0 { + // If we have to add a month, reset the other parts to 0. + if !added { + added = true + // Otherwise, set the date at the beginning (since the current time is irrelevant). + t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location()) + } + t = t.AddDate(0, 1, 0) + + // Wrapped around. + if t.Month() == time.January { + goto WRAP + } + } + + // Now get a day in that month. + for !dayMatches(s, t) { + if !added { + added = true + t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + } + t = t.AddDate(0, 0, 1) + + if t.Day() == 1 { + goto WRAP + } + } + + for 1<<uint(t.Hour())&s.Hour == 0 { + if !added { + added = true + t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location()) + } + t = t.Add(1 * time.Hour) + + if t.Hour() == 0 { + goto WRAP + } + } + + for 1<<uint(t.Minute())&s.Minute == 0 { + if !added { + added = true + t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), 0, 0, t.Location()) + } + t = t.Add(1 * time.Minute) + + if t.Minute() == 0 { + goto WRAP + } + } + + for 1<<uint(t.Second())&s.Second == 0 { + if !added { + added = true + t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) + } + t = t.Add(1 * time.Second) + + if t.Second() == 0 { + goto WRAP + } + } + + return t +} + +// dayMatches returns true if the schedule's day-of-week and day-of-month +// restrictions are satisfied by the given time. +func dayMatches(s *SpecSchedule, t time.Time) bool { + var ( + domMatch bool = 1<<uint(t.Day())&s.Dom > 0 + dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0 + ) + + if s.Dom&starBit > 0 || s.Dow&starBit > 0 { + return domMatch && dowMatch + } + return domMatch || dowMatch +} |