-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcron_instance.go
120 lines (106 loc) · 3.27 KB
/
cron_instance.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package schedule
import (
"time"
)
// CronInstance is created from CronExpression's and is used to hold state and determine next cron date according to it's expression.
type CronInstance struct {
crn *CronExpression
following time.Time
location *time.Location
ms int
s int
min int
h int
d int
lastD bool
am *AttunedMonth
err error
}
// Next uses it's following date to determine the next valid cron date according to it's expression.
// Each subsequent execution advances the instance's following date.
func (crnI *CronInstance) Next() error {
crnI.nextMs()
if crnI.err != nil {
return crnI.err
}
d := time.Date(crnI.am.Year(), crnI.am.Month(), crnI.d, crnI.h, crnI.min, crnI.s, crnI.ms*int(time.Millisecond), crnI.location)
if !crnI.following.IsZero() && d.Before(crnI.following) {
return CronOutdatedInvalidError
}
crnI.following = d
return nil
}
// Following returns the following valid cron date determined by the Next function without modifying its state.
func (crnI *CronInstance) Following() time.Time {
return crnI.following
}
func (crnI *CronInstance) nextMs() {
fromMs := crnI.ms
crnI.ms, _ = next(crnI.crn.milliseconds, fromMs, false)
if crnI.nextS(crnI.ms > fromMs) {
crnI.ms, _ = next(crnI.crn.milliseconds, 0, true)
}
}
func (crnI *CronInstance) nextS(inc bool) bool {
fromS := crnI.s
crnI.s, _ = next(crnI.crn.seconds, fromS, inc)
if crnI.nextMin(crnI.s > fromS || inc && crnI.s == fromS) {
crnI.s, _ = next(crnI.crn.seconds, 0, true)
return true
}
return crnI.s != fromS
}
func (crnI *CronInstance) nextMin(inc bool) bool {
fromMin := crnI.min
crnI.min, _ = next(crnI.crn.minutes, fromMin, inc)
if crnI.nextH(crnI.min > fromMin || inc && crnI.min == fromMin) {
crnI.min, _ = next(crnI.crn.minutes, 0, true)
return true
}
return crnI.min != fromMin
}
func (crnI *CronInstance) nextH(inc bool) bool {
fromH := crnI.h
crnI.h, _ = next(crnI.crn.hours, fromH, inc)
if crnI.nextD(crnI.h > fromH || inc && crnI.h == fromH) {
crnI.h, _ = next(crnI.crn.hours, 0, true)
return true
}
return crnI.h != fromH
}
func (crnI *CronInstance) nextD(inc bool) bool {
fromD, fromY, last, invalid, reset := crnI.d, crnI.am.y, false, true, false
if reset = crnI.nextMonY(true); reset {
crnI.d, inc = 1, true
}
for invalid {
crnI.d, last, invalid = crnI.nextDay(crnI.d, inc)
inc = false
if invalid && last {
if reset = crnI.nextMonY(false); !reset || crnI.am.y-fromY > 400 {
crnI.err = CronOutdatedInvalidError
return false
}
crnI.d, inc = 1, true
}
}
return reset || crnI.d != fromD
}
func (crnI *CronInstance) nextMonY(inc bool) bool {
fromMon, fromY := crnI.am.mon, crnI.am.y
nextMon, _ := next(crnI.crn.months, fromMon, inc)
nextY, _ := next(crnI.crn.years, fromY, nextMon > fromMon || inc && nextMon == fromMon)
if nextY != fromY {
nextMon, _ := next(crnI.crn.months, 1, true)
crnI.am.UpdateMonthYear(nextMon, nextY)
return true
}
crnI.am.UpdateMonth(nextMon)
return nextMon != fromMon
}
func (crnI *CronInstance) nextDay(fromD int, inc bool) (d int, last bool, invalid bool) {
d, last = next(crnI.crn.days, fromD, inc)
last = last || crnI.am.IsMonthLastDay(d)
invalid = d < fromD || !inc && d == fromD || !crnI.am.Contains(d) || !crnI.crn.containsWeekday(crnI.am.WeekDay(d))
return d, last, invalid
}