From 2c2dd2abc493d93c29fe20696f48f5ad25c94455 Mon Sep 17 00:00:00 2001 From: Laxman Vallandas Date: Thu, 15 Jun 2017 18:55:57 +0000 Subject: [PATCH 1/3] cron job trigger on timezone based, daylightsaving taken care --- README.md | 10 +++++++--- example/example.go | 10 +++++++--- gocron.go | 29 ++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6add738..9b67fed 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ func task() { fmt.Println("I am runnning task.") } +func task1() { + fmt.Println("I am runnning task1.") +} + func taskWithParams(a int, b string) { fmt.Println(a, b) } @@ -46,9 +50,9 @@ func main() { gocron.Every(1).Monday().Do(task) gocron.Every(1).Thursday().Do(task) - // function At() take a string like 'hour:min' - gocron.Every(1).Day().At("10:30").Do(task) - gocron.Every(1).Monday().At("18:30").Do(task) + // function At() take a string like 'hour:min:sec' ->Add your time here + gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(task1) + gocron.Every(1).Monday().At("18:30:00").Do(task) // remove, clear and next_run _, time := gocron.NextRun() diff --git a/example/example.go b/example/example.go index fa24025..bb41b10 100644 --- a/example/example.go +++ b/example/example.go @@ -10,6 +10,10 @@ func task() { fmt.Println("I am runnning task.") } +func task1() { + fmt.Println("I am runnning task1.") +} + func taskWithParams(a int, b string) { fmt.Println(a, b) } @@ -32,9 +36,9 @@ func main() { gocron.Every(1).Monday().Do(task) gocron.Every(1).Thursday().Do(task) - // function At() take a string like 'hour:min' - gocron.Every(1).Day().At("10:30").Do(task) - gocron.Every(1).Monday().At("18:30").Do(task) + // function At() take a string like 'hour:min:sec' ->Add your time here + gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(task1) + gocron.Every(1).Monday().At("18:30:00").Do(task) // remove, clear and next_run _, time := gocron.NextRun() diff --git a/gocron.go b/gocron.go index c8d2243..66df195 100644 --- a/gocron.go +++ b/gocron.go @@ -64,6 +64,9 @@ type Job struct { // Map for function and params of function fparams map[string]([]interface{}) + + //diff time zone for each timer + timeZone *time.Location } // Create a new job with the time interval. @@ -76,6 +79,7 @@ func NewJob(intervel uint64) *Job { time.Sunday, make(map[string]interface{}), make(map[string]([]interface{})), + time.UTC, } } @@ -97,7 +101,7 @@ func (j *Job) run() (result []reflect.Value, err error) { in[k] = reflect.ValueOf(param) } result = f.Call(in) - j.lastRun = time.Now() + j.lastRun = time.Now().In(j.timeZone) j.scheduleNextRun() return } @@ -128,17 +132,18 @@ func (j *Job) Do(jobFun interface{}, params ...interface{}) { func (j *Job) At(t string) *Job { hour := int((t[0]-'0')*10 + (t[1] - '0')) min := int((t[3]-'0')*10 + (t[4] - '0')) - if hour < 0 || hour > 23 || min < 0 || min > 59 { + sec := int((t[6]-'0')*10 + (t[7] - '0')) + if hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59 { panic("time format error.") } // time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) - mock := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), int(hour), int(min), 0, 0, loc) + mock := time.Date(time.Now().In(j.timeZone).Year(), time.Now().In(j.timeZone).Month(), time.Now().In(j.timeZone).Day(), int(hour), int(min), int(sec), 0, j.timeZone) if j.unit == "days" { if time.Now().After(mock) { j.lastRun = mock } else { - j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-1, hour, min, 0, 0, loc) + j.lastRun = time.Date(time.Now().In(j.timeZone).AddDate(0, 0, -1).Year(), time.Now().In(j.timeZone).AddDate(0, 0, -1).Month(), time.Now().In(j.timeZone).AddDate(0, 0, -1).Day(), hour, min, sec, 0, j.timeZone) } } else if j.unit == "weeks" { if time.Now().After(mock) { @@ -146,9 +151,9 @@ func (j *Job) At(t string) *Job { if i < 0 { i = 7 + i } - j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-int(i), hour, min, 0, 0, loc) + j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-int(i), hour, min, sec, 0, j.timeZone) } else { - j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-7, hour, min, 0, 0, loc) + j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-7, hour, min, sec, 0, j.timeZone) } } return j @@ -162,7 +167,7 @@ func (j *Job) scheduleNextRun() { if i < 0 { i = 7 + i } - j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-int(i), 0, 0, 0, 0, loc) + j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-int(i), 0, 0, 0, 0, j.timeZone) } else { j.lastRun = time.Now() @@ -193,6 +198,16 @@ func (j *Job) scheduleNextRun() { } } +// Set timezone for timer +func (j *Job) Zone(timeZone string) *Job { + recivedTimeZone, err := time.LoadLocation(timeZone) + if err != nil { + panic("time zone format error.") + } + j.timeZone = recivedTimeZone + return j +} + // the follow functions set the job's unit with seconds,minutes,hours... // Set the unit with second From d8edef998b5708da0ff79196e579bf03b343f251 Mon Sep 17 00:00:00 2001 From: laxmanvallandas Date: Tue, 16 Jan 2018 12:07:13 +0530 Subject: [PATCH 2/3] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9b67fed..28da76b 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ func main() { // function At() take a string like 'hour:min:sec' ->Add your time here gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(task1) + // Zone() will handle daylight savings if CST6CDT is used instead of CST. + gocron.Every(1).Day().Zone("CST6CDT").At("12:34:37").Do(task1) gocron.Every(1).Monday().At("18:30:00").Do(task) // remove, clear and next_run From 141d84d40d76e53b4170b2fec422f861ac088b5c Mon Sep 17 00:00:00 2001 From: "laxman.vallandas" Date: Mon, 12 Aug 2019 22:44:08 +0530 Subject: [PATCH 3/3] Fix to make it stable --- README.md | 10 +++++---- example/example.go | 16 +++++++++------ gocron.go | 22 ++++++++++++-------- gocron_test.go | 51 +++++++++++++++++++++++++++++++--------------- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 9853145..515edcd 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ func task() { fmt.Println("I am runnning task.") } -func task1() { +func dayLightTask() { fmt.Println("I am runnning task1.") } @@ -54,10 +54,12 @@ func main() { gocron.Every(1).Monday().Do(task) gocron.Every(1).Thursday().Do(task) - // function At() take a string like 'hour:min:sec' ->Add your time here - gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(task1) + // function At() take a string like 'hour:min' + gocron.Every(1).Day().At("10:30").Do(task) + // function At() take a string like 'hour:min:sec' + gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(dayLightTask) // Zone() will handle daylight savings if CST6CDT is used instead of CST. - gocron.Every(1).Day().Zone("CST6CDT").At("12:34:37").Do(task1) + gocron.Every(1).Day().Zone("CST6CDT").At("12:34:37").Do(dayLightTask) gocron.Every(1).Monday().At("18:30:00").Do(task) // remove, clear and next_run diff --git a/example/example.go b/example/example.go index bb41b10..0502103 100644 --- a/example/example.go +++ b/example/example.go @@ -3,15 +3,15 @@ package main import ( "fmt" - "github.com/jasonlvhit/gocron" + "github.com/laxmanvallandas/gocron" ) func task() { fmt.Println("I am runnning task.") } -func task1() { - fmt.Println("I am runnning task1.") +func dayLightTask() { + fmt.Println("I am runnning dayLightTask.") } func taskWithParams(a int, b string) { @@ -36,9 +36,13 @@ func main() { gocron.Every(1).Monday().Do(task) gocron.Every(1).Thursday().Do(task) - // function At() take a string like 'hour:min:sec' ->Add your time here - gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(task1) - gocron.Every(1).Monday().At("18:30:00").Do(task) + // function At() take a string like 'hour:min' + gocron.Every(1).Day().At("10:30").Do(task) + // function At() take a string like 'hour:min:sec' + gocron.Every(1).Day().Zone("EST").At("12:34:37").Do(dayLightTask) + // Zone() will handle daylight savings if CST6CDT is used instead of CST. + gocron.Every(1).Monday().Zone("CST6CDT").At("12:34:37").Do(dayLightTask) + gocron.Every(1).Monday().At("18:30:00").Do(task) // remove, clear and next_run _, time := gocron.NextRun() diff --git a/gocron.go b/gocron.go index 0f0ab56..0f5e665 100644 --- a/gocron.go +++ b/gocron.go @@ -129,10 +129,10 @@ func (j *Job) Do(jobFun interface{}, params ...interface{}) { j.scheduleNextRun() } -func formatTime(t string) (hour, min int, err error) { +func formatTime(t string) (hour, min, sec int, err error) { var er = errors.New("time format error") ts := strings.Split(t, ":") - if len(ts) != 2 { + if len(ts) != 2 && len(ts) != 3 { err = er return } @@ -145,21 +145,25 @@ func formatTime(t string) (hour, min int, err error) { if err != nil { return } - sec, err = strconv.Atoi(ts[2]) - if err != nil { - return + if len(ts) == 3 { + sec, err = strconv.Atoi(ts[2]) + if err != nil { + return + } + } else { + sec = 0 } if hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59 { err = er - return + return } - return hour, min, nil + return hour, min, sec, nil } // s.Every(1).Day().At("10:30").Do(task) // s.Every(1).Monday().At("10:30").Do(task) func (j *Job) At(t string) *Job { - hour, min, err := formatTime(t) + hour, min, sec, err := formatTime(t) if err != nil { panic(err) } @@ -240,7 +244,7 @@ func (j *Job) Zone(timeZone string) *Job { j.timeZone = recivedTimeZone return j } - + // the follow functions set the job's unit with seconds,minutes,hours... // Set the unit with second diff --git a/gocron_test.go b/gocron_test.go index cd4a5c2..c4506d5 100644 --- a/gocron_test.go +++ b/gocron_test.go @@ -45,19 +45,18 @@ func TestScheduler_WeekdaysTodayAfter(t *testing.T) { scheduler := NewScheduler() now := time.Now() - timeToSchedule := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()-1, 0, 0, time.Local) + timeToSchedule := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()-1, now.Second()-1, 0, time.UTC) - job := callTodaysWeekday(scheduler.Every(1)).At(fmt.Sprintf("%02d:%02d", timeToSchedule.Hour(), timeToSchedule.Minute())) + job := callTodaysWeekday(scheduler.Every(1)).At(fmt.Sprintf("%02d:%02d:%02d", timeToSchedule.Hour(), timeToSchedule.Minute(), timeToSchedule.Second())) job.Do(task) t.Logf("job is scheduled for %s", job.NextScheduledTime()) if job.NextScheduledTime().Weekday() != timeToSchedule.Weekday() { t.Fail() t.Logf("Job scheduled for current weekday for earlier time, should still be scheduled for current weekday (but next week)") } - nextWeek := time.Date(now.Year(), now.Month(), now.Day()+7, now.Hour(), now.Minute()-1, 0, 0, time.Local) + nextWeek := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()-1, now.Second()-1, 0, time.UTC) if !job.NextScheduledTime().Equal(nextWeek) { - t.Fail() - t.Logf("Job should be scheduled for the correct time next week.") + t.Errorf("Job should be scheduled for the correct time next week.\nGot %+v, expected %+v", job.NextScheduledTime(), nextWeek) } } @@ -67,9 +66,9 @@ func TestScheduler_WeekdaysTodayBefore(t *testing.T) { scheduler := NewScheduler() now := time.Now() - timeToSchedule := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()+1, 0, 0, time.Local) + timeToSchedule := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()+1, now.Second()+1, 0, time.UTC) - job := callTodaysWeekday(scheduler.Every(1)).At(fmt.Sprintf("%02d:%02d", timeToSchedule.Hour(), timeToSchedule.Minute())) + job := callTodaysWeekday(scheduler.Every(1)).Day().At(fmt.Sprintf("%02d:%02d:%02d", timeToSchedule.Hour(), timeToSchedule.Minute(), timeToSchedule.Second())) job.Do(task) t.Logf("job is scheduled for %s", job.NextScheduledTime()) if !job.NextScheduledTime().Equal(timeToSchedule) { @@ -84,6 +83,7 @@ func Test_formatTime(t *testing.T) { args string wantHour int wantMin int + wantSec int wantErr bool }{ { @@ -115,10 +115,19 @@ func Test_formatTime(t *testing.T) { wantErr: true, }, { - name: "wrongformat", + name: "normal", args: "19:18:17", + wantHour: 19, + wantMin: 18, + wantSec: 17, + wantErr: false, + }, + { + name: "wrongformat", + args: "19:18:17:11", wantHour: 0, wantMin: 0, + wantSec: 0, wantErr: true, }, { @@ -131,7 +140,7 @@ func Test_formatTime(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotHour, gotMin, err := formatTime(tt.args) + gotHour, gotMin, gotSec, err := formatTime(tt.args) if (err != nil) != tt.wantErr { t.Errorf("formatTime() error = %v, wantErr %v", err, tt.wantErr) return @@ -142,6 +151,9 @@ func Test_formatTime(t *testing.T) { if gotMin != tt.wantMin { t.Errorf("formatTime() gotMin = %v, want %v", gotMin, tt.wantMin) } + if gotSec != tt.wantSec { + t.Errorf("formatTime() gotMin = %v, want %v", gotSec, tt.wantSec) + } }) } } @@ -149,13 +161,20 @@ func Test_formatTime(t *testing.T) { // utility function for testing the weekday functions *on* the current weekday. func callTodaysWeekday(job *Job) *Job { switch time.Now().Weekday() { - case 0: job.Sunday() - case 1: job.Monday() - case 2: job.Tuesday() - case 3: job.Wednesday() - case 4: job.Thursday() - case 5: job.Friday() - case 6: job.Saturday() + case 0: + job.Sunday() + case 1: + job.Monday() + case 2: + job.Tuesday() + case 3: + job.Wednesday() + case 4: + job.Thursday() + case 5: + job.Friday() + case 6: + job.Saturday() } return job }