Skip to content

Commit 8c99442

Browse files
committed
Fix for #23 where scheduling jobs on several weekdays will result in all jobs being run at the same time/day. Added a test for this, and preemptive tests for possible edge cases with weekday functions, mostly to ensure I didn't break anything with my fix.
1 parent 3c914c8 commit 8c99442

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ _testmain.go
2121

2222
*.exe
2323
*.test
24+
25+
# IDE project files
26+
.idea

gocron.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ func (j *Job) shouldRun() bool {
8686
return time.Now().After(j.nextRun)
8787
}
8888

89-
//Run the job and immdiately reschedulei it
89+
//Run the job and immediately reschedule it
9090
func (j *Job) run() (result []reflect.Value, err error) {
9191
f := reflect.ValueOf(j.funcs[j.jobFunc])
9292
params := j.fparams[j.jobFunc]
9393
if len(params) != f.Type().NumIn() {
94-
err = errors.New("The number of param is not adapted.")
94+
err = errors.New("the number of param is not adapted")
9595
return
9696
}
9797
in := make([]reflect.Value, len(params))
@@ -104,7 +104,7 @@ func (j *Job) run() (result []reflect.Value, err error) {
104104
return
105105
}
106106

107-
// for given function fn , get the name of funciton.
107+
// for given function fn, get the name of function.
108108
func getFunctionName(fn interface{}) string {
109109
return runtime.FuncForPC(reflect.ValueOf((fn)).Pointer()).Name()
110110
}
@@ -167,7 +167,7 @@ func (j *Job) At(t string) *Job {
167167
j.lastRun = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-1, hour, min, 0, 0, loc)
168168
}
169169
} else if j.unit == "weeks" {
170-
if time.Now().After(mock) {
170+
if j.startDay != time.Now().Weekday() || (time.Now().After(mock) && j.startDay == time.Now().Weekday()) {
171171
i := mock.Weekday() - j.startDay
172172
if i < 0 {
173173
i = 7 + i

gocron_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,61 @@ func TestSecond(*testing.T) {
2323
time.Sleep(10 * time.Second)
2424
}
2525

26+
// This is a basic test for the issue described here: https://github.com/jasonlvhit/gocron/issues/23
27+
func TestScheduler_Weekdays(t *testing.T) {
28+
scheduler := NewScheduler()
29+
30+
job1 := scheduler.Every(1).Monday().At("23:59")
31+
job2 := scheduler.Every(1).Wednesday().At("23:59")
32+
job1.Do(task)
33+
job2.Do(task)
34+
t.Logf("job1 scheduled for %s", job1.NextScheduledTime())
35+
t.Logf("job2 scheduled for %s", job2.NextScheduledTime())
36+
if job1.NextScheduledTime() == job2.NextScheduledTime() {
37+
t.Fail()
38+
t.Logf("Two jobs scheduled at the same time on two different weekdays should never run at the same time.[job1: %s; job2: %s]", job1.NextScheduledTime(), job2.NextScheduledTime())
39+
}
40+
}
41+
42+
// This ensures that if you schedule a job for today's weekday, but the time is already passed, it will be scheduled for
43+
// next week at the requested time.
44+
func TestScheduler_WeekdaysTodayAfter(t *testing.T) {
45+
scheduler := NewScheduler()
46+
47+
now := time.Now()
48+
timeToSchedule := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()-1, 0, 0, time.Local)
49+
50+
job := callTodaysWeekday(scheduler.Every(1)).At(fmt.Sprintf("%02d:%02d", timeToSchedule.Hour(), timeToSchedule.Minute()))
51+
job.Do(task)
52+
t.Logf("job is scheduled for %s", job.NextScheduledTime())
53+
if job.NextScheduledTime().Weekday() != timeToSchedule.Weekday() {
54+
t.Fail()
55+
t.Logf("Job scheduled for current weekday for earlier time, should still be scheduled for current weekday (but next week)")
56+
}
57+
nextWeek := time.Date(now.Year(), now.Month(), now.Day()+7, now.Hour(), now.Minute()-1, 0, 0, time.Local)
58+
if !job.NextScheduledTime().Equal(nextWeek) {
59+
t.Fail()
60+
t.Logf("Job should be scheduled for the correct time next week.")
61+
}
62+
}
63+
64+
// This is to ensure that if you schedule a job for today's weekday, and the time hasn't yet passed, the next run time
65+
// will be scheduled for today.
66+
func TestScheduler_WeekdaysTodayBefore(t *testing.T) {
67+
scheduler := NewScheduler()
68+
69+
now := time.Now()
70+
timeToSchedule := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()+1, 0, 0, time.Local)
71+
72+
job := callTodaysWeekday(scheduler.Every(1)).At(fmt.Sprintf("%02d:%02d", timeToSchedule.Hour(), timeToSchedule.Minute()))
73+
job.Do(task)
74+
t.Logf("job is scheduled for %s", job.NextScheduledTime())
75+
if !job.NextScheduledTime().Equal(timeToSchedule) {
76+
t.Fail()
77+
t.Logf("Job should be run today, at the set time.")
78+
}
79+
}
80+
2681
func Test_formatTime(t *testing.T) {
2782
tests := []struct {
2883
name string
@@ -90,3 +145,17 @@ func Test_formatTime(t *testing.T) {
90145
})
91146
}
92147
}
148+
149+
// utility function for testing the weekday functions *on* the current weekday.
150+
func callTodaysWeekday(job *Job) *Job {
151+
switch time.Now().Weekday() {
152+
case 0: job.Sunday()
153+
case 1: job.Monday()
154+
case 2: job.Tuesday()
155+
case 3: job.Wednesday()
156+
case 4: job.Thursday()
157+
case 5: job.Friday()
158+
case 6: job.Saturday()
159+
}
160+
return job
161+
}

0 commit comments

Comments
 (0)