Skip to content

Commit

Permalink
add interval notation e.g */3
Browse files Browse the repository at this point in the history
  • Loading branch information
pitluga committed Jan 5, 2016
1 parent 5a70d48 commit 0c8ebf8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 12 deletions.
46 changes: 34 additions & 12 deletions pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cron

import(
"fmt"
"math"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -38,6 +39,16 @@ func (r *Range) Matches(timePart int) bool {
return timePart >= r.min && timePart <= r.max
}

type Interval struct {
field string
numerator FieldMatcher
denominator int
}

func (interval *Interval) Matches(timePart int) bool {
return interval.numerator.Matches(timePart) && math.Mod(float64(timePart), float64(interval.denominator)) == 0
}

type CronSchedule struct {
minutes FieldMatcher
hours FieldMatcher
Expand All @@ -56,6 +67,14 @@ func (schedule CronSchedule) ShouldRun(t time.Time) bool {

}

func safeAtoi(str string) int {
number, err := strconv.Atoi(str)
if err != nil {
panic(fmt.Sprintf("regexp matched integer, but couldn't convert %q to int", str))
}
return number
}

func parseField(field string) FieldMatcher {
constantRegexp, err := regexp.Compile(`\A\d+\z`)
if err != nil {
Expand All @@ -65,26 +84,29 @@ func parseField(field string) FieldMatcher {
if err != nil {
panic("invalid hardcoded regexp!")
}
intervalRegexp, err := regexp.Compile(`\A.*/\d+\z`)
if err != nil {
panic("invalid hardcoded regexp!")
}

if "*" == field {
return &Wildcard{field}
} else if constantRegexp.MatchString(field) {
number, err := strconv.Atoi(field)
if err != nil {
panic(fmt.Sprintf("regexp matched integer, but couldn't convert %q to int", field))
}
return &Constant{field, number}
return &Constant{field, safeAtoi(field)}
} else if rangeRegexp.MatchString(field) {
rangeParts := strings.Split(field, "-")
min, err := strconv.Atoi(rangeParts[0])
if err != nil {
panic(fmt.Sprintf("regexp matched integer, but couldn't convert %q to int", rangeParts[0]))
return &Range{
field: field,
min: safeAtoi(rangeParts[0]),
max: safeAtoi(rangeParts[1]),
}
max, err := strconv.Atoi(rangeParts[1])
if err != nil {
panic(fmt.Sprintf("regexp matched integer, but couldn't convert %q to int", rangeParts[1]))
} else if intervalRegexp.MatchString(field) {
intervalParts := strings.Split(field, "/")
return &Interval{
field: field,
numerator: parseField(intervalParts[0]),
denominator: safeAtoi(intervalParts[1]),
}
return &Range{field, min, max}
}
return nil
}
Expand Down
16 changes: 16 additions & 0 deletions pattern_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,19 @@ func TestRanges(t *testing.T) {
{time.Date(2016, time.January, 5, 10, 8, 0, 0, time.UTC), true},
})
}

func TestIntervals(t *testing.T) {
IsScheduled(t, "*/3 * * * * *", []TimeTestCase{
{time.Date(2016, time.January, 5, 10, 15, 0, 0, time.UTC), true},
{time.Date(2016, time.January, 5, 10, 5, 0, 0, time.UTC), false},
{time.Date(2016, time.January, 5, 10, 4, 0, 0, time.UTC), false},
{time.Date(2016, time.January, 5, 10, 33, 0, 0, time.UTC), true},
})

IsScheduled(t, "1-30/3 * * * * *", []TimeTestCase{
{time.Date(2016, time.January, 5, 10, 15, 0, 0, time.UTC), true},
{time.Date(2016, time.January, 5, 10, 5, 0, 0, time.UTC), false},
{time.Date(2016, time.January, 5, 10, 4, 0, 0, time.UTC), false},
{time.Date(2016, time.January, 5, 10, 33, 0, 0, time.UTC), false},
})
}

0 comments on commit 0c8ebf8

Please sign in to comment.