cron.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // This library implements a cron spec parser and runner. See the README for
  2. // more details.
  3. package cron
  4. import (
  5. "time"
  6. )
  7. // Cron keeps track of any number of entries, invoking the associated func as
  8. // specified by the spec. See http://en.wikipedia.org/wiki/Cron
  9. // It may be started and stopped.
  10. type Cron struct {
  11. Entries []*Entry
  12. stop chan struct{}
  13. }
  14. // A cron entry consists of a schedule and the func to execute on that schedule.
  15. type Entry struct {
  16. *Schedule
  17. Func func()
  18. }
  19. func New() *Cron {
  20. return new(Cron)
  21. }
  22. func (c *Cron) Add(spec string, cmd func()) {
  23. c.Entries = append(c.Entries, &Entry{Parse(spec), cmd})
  24. }
  25. func (c *Cron) Run() {
  26. ticker := time.Tick(1 * time.Minute)
  27. for {
  28. select {
  29. case now := <-ticker:
  30. for _, entry := range c.Entries {
  31. if matches(now, entry.Schedule) {
  32. go entry.Func()
  33. }
  34. }
  35. case <-c.stop:
  36. return
  37. }
  38. }
  39. }
  40. func (c Cron) Stop() {
  41. c.stop <- struct{}{}
  42. }
  43. // Return true if the given entries overlap.
  44. func matches(t time.Time, sched *Schedule) bool {
  45. var (
  46. domMatch bool = 1<<uint(t.Day())&sched.Dom > 0
  47. dowMatch bool = 1<<uint(t.Weekday())&sched.Dow > 0
  48. dayMatch bool
  49. )
  50. if sched.Dom&STAR_BIT > 0 || sched.Dow&STAR_BIT > 0 {
  51. dayMatch = domMatch && dowMatch
  52. } else {
  53. dayMatch = domMatch || dowMatch
  54. }
  55. return 1<<uint(t.Minute())&sched.Minute > 0 &&
  56. 1<<uint(t.Hour())&sched.Hour > 0 &&
  57. 1<<uint(t.Month())&sched.Month > 0 &&
  58. dayMatch
  59. }
  60. // // Return the number of units betwee now and then.
  61. // func difference(then, now uint64, r bounds) uint {
  62. // // Shift the current time fields left (and around) until & is non-zero.
  63. // i := 0
  64. // for then & now << ((i - r.min) % (r.max - r.min + 1) + r.min) == 0 {
  65. // // A guard against no units selected.
  66. // if i > r.max {
  67. // panic("Entry had no minute/hour selected.")
  68. // }
  69. // i++
  70. // }
  71. // return i
  72. // }