-
Notifications
You must be signed in to change notification settings - Fork 0
/
when.go
106 lines (91 loc) · 3.2 KB
/
when.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
// Copyright 2021 xgfone
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gron
import (
"fmt"
"strings"
"time"
"github.com/xgfone/gron/crontab"
)
// CronSpecParser is the parser to parse the cron specification expression.
var CronSpecParser = crontab.NewParser(crontab.SecondOptional |
crontab.Minute |
crontab.Hour |
crontab.Dom |
crontab.Month |
crontab.Dow |
crontab.Descriptor)
// Every is equal to ParseWhen("@every interval").
func Every(interval time.Duration) When {
return &when{spec: "@every " + interval.String(), every: interval}
}
// EveryWithDelay is the same as Every, but delay to run the job for delay duration.
func EveryWithDelay(interval, delay time.Duration) When {
return &when{spec: "@every " + interval.String(), every: interval, delay: delay}
}
// MustParseWhen is the same as ParseWhen, but panic if there is an error.
func MustParseWhen(s string) When {
w, err := ParseWhen(s)
if err != nil {
panic(err)
}
return w
}
// ParseWhen parses the spec to a when implementation, which uses and returns
// the UTC time.
//
// spec supports CRON Expression Format, see https://en.wikipedia.org/wiki/Cron,
// which also supports one of several pre-defined schedules like this:
//
// Entry | Description | Equivalent To
// ----- | ----------- | -------------
// @yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 1 1 *
// @monthly | Run once a month, midnight, first of month | 0 0 1 * *
// @weekly | Run once a week, midnight between Sat/Sun | 0 0 * * 0
// @daily (or @midnight) | Run once a day, midnight | 0 0 * * *
// @hourly | Run once an hour, beginning of hour | 0 * * * *
// @every Duration | Run once every interval duration |
//
func ParseWhen(spec string) (When, error) {
spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "@every ") {
interval, err := time.ParseDuration(spec[7:])
if err != nil {
return nil, fmt.Errorf("When: invalid 'every' argument: '%s'", spec[7:])
}
return &when{spec: spec, every: interval}, nil
}
scheduler, err := CronSpecParser.Parse(spec)
if err != nil {
return nil, err
}
scheduler.Location = time.UTC
return &when{spec: spec, sched: scheduler}, nil
}
type when struct {
spec string
delay time.Duration
every time.Duration
sched *crontab.SpecSchedule
}
func (w *when) String() string { return w.spec }
func (w *when) Next(prev time.Time) (next time.Time) {
if prev.IsZero() { // First time
prev = time.Now().UTC()
}
if w.every > 0 {
return prev.Add(w.every)
}
return w.sched.Next(prev)
}