Skip to content

Commit 23baae2

Browse files
authored
Merge pull request robfig#73 from soltysh/issue58
Add method capable of parsing standard cron spec
2 parents ab4c16f + b43eae7 commit 23baae2

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

parser.go

+40
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,46 @@ import (
99
"time"
1010
)
1111

12+
// ParseStandard returns a new crontab schedule representing the given standardSpec
13+
// (https://en.wikipedia.org/wiki/Cron). It differs from Parse requiring to always
14+
// pass 5 entries representing: minute, hour, day of month, month and day of week,
15+
// in that order. It returns a descriptive error if the spec is not valid.
16+
//
17+
// It accepts
18+
// - Standard crontab specs, e.g. "* * * * ?"
19+
// - Descriptors, e.g. "@midnight", "@every 1h30m"
20+
func ParseStandard(standardSpec string) (_ Schedule, err error) {
21+
// Convert panics into errors
22+
defer func() {
23+
if recovered := recover(); recovered != nil {
24+
err = fmt.Errorf("%v", recovered)
25+
}
26+
}()
27+
28+
if standardSpec[0] == '@' {
29+
return parseDescriptor(standardSpec), nil
30+
}
31+
32+
// Split on whitespace. We require exactly 5 fields.
33+
// (minute) (hour) (day of month) (month) (day of week)
34+
fields := strings.Fields(standardSpec)
35+
if len(fields) != 5 {
36+
log.Panicf("Expected exactly 5, found %d: %s", len(fields), standardSpec)
37+
}
38+
39+
schedule := &SpecSchedule{
40+
Second: 1 << seconds.min,
41+
Minute: getField(fields[0], minutes),
42+
Hour: getField(fields[1], hours),
43+
Dom: getField(fields[2], dom),
44+
Month: getField(fields[3], months),
45+
Dow: getField(fields[4], dow),
46+
}
47+
48+
return schedule, nil
49+
50+
}
51+
1252
// Parse returns a new crontab schedule representing the given spec.
1353
// It returns a descriptive error if the spec is not valid.
1454
//

parser_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,23 @@ func TestSpecSchedule(t *testing.T) {
115115
}
116116
}
117117
}
118+
119+
func TestStandardSpecSchedule(t *testing.T) {
120+
entries := []struct {
121+
expr string
122+
expected Schedule
123+
}{
124+
{"5 * * * *", &SpecSchedule{1 << seconds.min, 1 << 5, all(hours), all(dom), all(months), all(dow)}},
125+
{"@every 5m", ConstantDelaySchedule{time.Duration(5) * time.Minute}},
126+
}
127+
128+
for _, c := range entries {
129+
actual, err := ParseStandard(c.expr)
130+
if err != nil {
131+
t.Error(err)
132+
}
133+
if !reflect.DeepEqual(actual, c.expected) {
134+
t.Errorf("%s => (expected) %b != %b (actual)", c.expr, c.expected, actual)
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)