-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcron_expression.go
More file actions
286 lines (245 loc) · 6.46 KB
/
cron_expression.go
File metadata and controls
286 lines (245 loc) · 6.46 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
package schedule
import (
"sync/atomic"
"time"
)
// CronExpression is used to represent the complete cron expression.
// It is used to create new CronInstances.
type CronExpression struct {
milliseconds Expression
seconds Expression
minutes Expression
hours Expression
days Expression
weekdays Expression
months Expression
years Expression
initialized *uint32
}
// Cron creates and returns a reference to a new CronExpression.
func Cron() *CronExpression {
return &CronExpression{
initialized: new(uint32),
}
}
//------Public Functions------//
// NewInstance creates and returns a reference to a new CronInstance for the referenced CronExpression.
func (crn *CronExpression) NewInstance(from time.Time) *CronInstance {
crn.initialize()
return &CronInstance{
crn: crn,
following: from,
location: from.Location(),
ms: from.Nanosecond() / int(time.Millisecond),
s: from.Second(),
min: from.Minute(),
h: from.Hour(),
d: from.Day(),
am: NewAttunedMonth(int(from.Month()), from.Year()),
}
}
//------Expression------//
// EveryMillisecond sets this expression to return a date for every millisecond.
func (crn *CronExpression) EveryMillisecond() *CronExpression {
return crn.OnMilliseconds(Between(0, 999))
}
// OnMilliseconds sets this expression to return a date on the provided millisecond.
func (crn *CronExpression) OnMilliseconds(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateMillisecond(exp)
}
crn.milliseconds = exp
crn.reset()
return crn
}
// EverySecond sets this expression to return a date for every second.
func (crn *CronExpression) EverySecond() *CronExpression {
return crn.OnSeconds(Between(0, 59))
}
// OnSeconds sets this expression to return a date on the provided seconds.
func (crn *CronExpression) OnSeconds(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateSecond(exp)
}
crn.seconds = exp
crn.handleMillisecond()
crn.reset()
return crn
}
// EveryMinute sets this expression to return a date for every minute.
func (crn *CronExpression) EveryMinute() *CronExpression {
return crn.OnMinutes(Between(0, 59))
}
// OnMinutes sets this expression to return a date on the provided minutes.
func (crn *CronExpression) OnMinutes(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateMinute(exp)
}
crn.minutes = exp
crn.handleSecond()
crn.reset()
return crn
}
// EveryHour sets this expression to return a date for every hour.
func (crn *CronExpression) EveryHour() *CronExpression {
return crn.OnHours(Between(0, 23))
}
// OnHours sets this expression to return a date on the provided hours.
func (crn *CronExpression) OnHours(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateHour(exp)
}
crn.hours = exp
crn.handleMinute()
crn.reset()
return crn
}
// EveryDay sets this expression to return a date for every day.
func (crn *CronExpression) EveryDay() *CronExpression {
return crn.OnDays(Between(1, 31))
}
// OnDays sets this expression to return a date on the provided days.
func (crn *CronExpression) OnDays(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateDay(exp)
}
crn.days = exp
crn.handleHour()
crn.reset()
return crn
}
// OnWeekdays sets this expression to return a date on the provided weekdays.
func (crn *CronExpression) OnWeekdays(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateWeekday(exp)
}
crn.weekdays = exp
crn.handleHour()
crn.reset()
return crn
}
// EveryMonth sets this expression to return a date for every month.
func (crn *CronExpression) EveryMonth() *CronExpression {
return crn.OnMonths(BetweenMonths(time.January, time.December))
}
// OnMonths sets this expression to return a date on the provided months.
func (crn *CronExpression) OnMonths(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateMonth(exp)
}
crn.months = exp
crn.handleDay()
crn.reset()
return crn
}
// OnYears sets this expression to return a date on the provided years.
func (crn *CronExpression) OnYears(exp Expression) *CronExpression {
if exp, iOf := exp.(int); iOf {
validateYear(exp)
}
crn.years = exp
crn.handleMonth()
crn.reset()
return crn
}
//------Initialization------//
func (crn *CronExpression) initialize() {
if atomic.CompareAndSwapUint32(crn.initialized, 0, 1) {
crn.ensureSeconds()
crn.ensureMinutes()
crn.ensureHours()
crn.ensureDays()
crn.ensureWeekdays()
crn.ensureMonths()
crn.ensureYears()
}
}
func (crn *CronExpression) reset() {
atomic.CompareAndSwapUint32(crn.initialized, 1, 0)
}
func (crn *CronExpression) ensureSeconds() {
if crn.seconds == nil {
crn.seconds = BetweenSeconds(0, 59)
}
}
func (crn *CronExpression) ensureMinutes() {
if crn.minutes == nil {
crn.minutes = BetweenMinutes(0, 59)
}
}
func (crn *CronExpression) ensureHours() {
if crn.hours == nil {
crn.hours = BetweenHours(0, 23)
}
}
func (crn *CronExpression) ensureDays() {
if crn.days == nil {
crn.days = BetweenDays(1, 31)
}
}
func (crn *CronExpression) ensureWeekdays() {
if crn.weekdays == nil {
crn.weekdays = BetweenWeekdays(time.Sunday, time.Saturday)
}
}
func (crn *CronExpression) ensureMonths() {
if crn.months == nil {
crn.months = BetweenMonths(time.January, time.December)
}
}
func (crn *CronExpression) ensureYears() {
if crn.years == nil {
crn.years = BetweenYears(1970, 200000000)
}
}
//------Utils------//
func (crn *CronExpression) handleMillisecond() {
if crn.milliseconds == nil {
crn.milliseconds = 0
}
}
func (crn *CronExpression) handleSecond() {
if crn.seconds == nil {
crn.seconds = 0
}
crn.handleMillisecond()
}
func (crn *CronExpression) handleMinute() {
if crn.minutes == nil {
crn.minutes = 0
}
crn.handleSecond()
}
func (crn *CronExpression) handleHour() {
if crn.hours == nil {
crn.hours = 0
}
crn.handleMinute()
}
func (crn *CronExpression) handleDay() {
if crn.days == nil {
crn.days = 1
}
crn.handleHour()
}
func (crn *CronExpression) handleMonth() {
if crn.months == nil {
crn.months = 1
}
crn.handleDay()
}
func next(exp Expression, from int, inc bool) (int, bool) {
switch exp := exp.(type) {
case IteratorExpression:
return exp.Next(from, inc)
case time.Month:
return int(exp), true
}
return exp.(int), true
}
func (crn *CronExpression) containsWeekday(wd time.Weekday) bool {
if weekdays, iOf := crn.weekdays.(IteratorExpression); iOf {
return weekdays.Contains(int(wd))
}
return crn.weekdays.(time.Weekday) == wd
}