diff --git a/README.md b/README.md index e40a365..d2e10d0 100644 --- a/README.md +++ b/README.md @@ -54,5 +54,4 @@ Hyphens define ranges. For example, 2000-2010 indicates every year between 2000 ## Details -* At this moment, the package supports only **UTC** timezone. * The return value of `Next` and `Prev` is zero if the pattern doesn't match in five years. diff --git a/_example/location.go b/_example/location.go new file mode 100644 index 0000000..4dbe97d --- /dev/null +++ b/_example/location.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + "time" + + "github.com/gitploy-io/cronexpr" +) + +func main() { + nextTime := cronexpr.MustParseInLocation("0 * * * *", "Asia/Seoul").Next(time.Now()) + fmt.Printf("Parse the cron expression in the KR timezone: %s", nextTime) +} diff --git a/parser.go b/parser.go index cfdfe15..6bd29b8 100644 --- a/parser.go +++ b/parser.go @@ -4,6 +4,7 @@ import ( "fmt" "strconv" "strings" + "time" ) type ( @@ -55,6 +56,44 @@ var ( } ) +// MustParse returns the same result as Parse but it panic +// when something is wrong. +func MustParseInLocation(expr string, locName string) *Schedule { + loc, err := time.LoadLocation(locName) + if err != nil { + panic(err) + } + + schdule, err := Parse(expr) + if err != nil { + panic(err) + } + + schdule.Location = loc + return schdule +} + +// ParseInLocation parse the expression in the location and +// returns a new schedule representing the given spec. +// It returns an error when loading the location is failed or +// the syntax of the expression is wrong. +func ParseInLocation(expr string, locName string) (*Schedule, error) { + loc, err := time.LoadLocation(locName) + if err != nil { + return nil, err + } + + schdule, err := Parse(expr) + if err != nil { + return nil, err + } + + schdule.Location = loc + return schdule, nil +} + +// MustParse returns the same result as Parse but it panic +// when the syntax of expression is wrong. func MustParse(expr string) *Schedule { s, err := Parse(expr) if err != nil { @@ -64,6 +103,9 @@ func MustParse(expr string) *Schedule { return s } +// Parse parses the expression and returns a new schedule representing the given spec. +// And the default location of a schedule is "UTC". +// It returns an error when the syntax of expression is wrong. func Parse(expr string) (*Schedule, error) { err := verifyExpr(expr) if err != nil { diff --git a/schedule.go b/schedule.go index 492f677..1bb45b4 100644 --- a/schedule.go +++ b/schedule.go @@ -8,13 +8,19 @@ type ( Schedule struct { Minute, Hour, Dom, Month, Dow bitset - // TODO: support the timezone option - // Location *time.Location + Location *time.Location } ) +// Next returns the next time matched with the expression. func (s *Schedule) Next(t time.Time) time.Time { loc := time.UTC + if s.Location != nil { + loc = s.Location + } + + origLoc := t.Location() + t.In(loc) added := false @@ -88,11 +94,18 @@ L: } } - return t + return t.In(origLoc) } +// Next returns the previous time matched with the expression. func (s *Schedule) Prev(t time.Time) time.Time { loc := time.UTC + if s.Location != nil { + loc = s.Location + } + + origLoc := t.Location() + t.In(loc) subtracted := false @@ -167,7 +180,7 @@ L: } } - return t + return t.In(origLoc) } // dayMatches returns true if the schedule's day-of-week and day-of-month