Repository: go-co-op/gocron
Pull request #5 (2020-03-25 15:25:58)

StartAt logic moved to scheduler.go


Patch:
diff --git a/README.md b/README.md
index 6c1f038..7878c10 100644
--- a/README.md
+++ b/README.md
@@ -64,13 +64,14 @@ func main() {
     s2.Every(1).Monday().At("18:30").Do(task)
     s2.Every(1).Tuesday().At("18:30:59").Do(task)
 
-    // use .From(gocron.NextTick()) to run job immediately upon start
-    s2.Every(1).Hour().From(gocron.NextTick()).Do(task)
-
     // Begin job at a specific date/time. 
     // Attention: scheduler timezone has precedence over job's timezone!
     t := time.Date(2019, time.November, 10, 15, 0, 0, 0, time.UTC)
-    s2.Every(1).Hour().From(&t).Do(task)
+    s2.Every(1).Hour().StartAt(t).Do(task)
+
+    // use .StartImmediately() to run job upon scheduler start
+    s2.Every(1).Hour().StartImmediately().Do(task)
+
 
     // NextRun gets the next running time
     _, time := s2.NextRun()
@@ -83,7 +84,7 @@ func main() {
     s2.Clear()
 
     // Start all the pending jobs
-    <- gocron.Start()
+    <- s2.Start()
 }
 ```
 
diff --git a/go.mod b/go.mod
index 786f4df..5baf982 100644
--- a/go.mod
+++ b/go.mod
@@ -9,5 +9,4 @@ require (
 	github.com/stretchr/testify v1.4.0
 	golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
-	golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
 )
diff --git a/go.sum b/go.sum
index 3e8fac3..72fa774 100644
--- a/go.sum
+++ b/go.sum
@@ -29,9 +29,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
diff --git a/gocron.go b/gocron.go
index 17a9674..35144bc 100644
--- a/gocron.go
+++ b/gocron.go
@@ -25,7 +25,6 @@ import (
 	"runtime"
 	"strconv"
 	"strings"
-	"time"
 )
 
 // Locker provides a method to lock jobs from running
@@ -103,9 +102,3 @@ func formatTime(t string) (hour, min, sec int, err error) {
 
 	return hour, min, sec, nil
 }
-
-// NextTick returns a pointer to a time that will run at the next tick
-func NextTick() *time.Time {
-	now := time.Now().Add(time.Second)
-	return &now
-}
diff --git a/job.go b/job.go
index 738025f..20f4de7 100644
--- a/job.go
+++ b/job.go
@@ -15,18 +15,19 @@ var (
 
 // Job struct keeping information about job
 type Job struct {
-	interval uint64                   // pause interval * unit between runs
-	jobFunc  string                   // the job jobFunc to run, func[jobFunc]
-	unit     timeUnit                 // time units, ,e.g. 'minutes', 'hours'...
-	atTime   time.Duration            // optional time at which this job runs
-	err      error                    // error related to job
-	lastRun  time.Time                // datetime of last run
-	nextRun  time.Time                // datetime of next run
-	startDay time.Weekday             // Specific day of the week to start on
-	funcs    map[string]interface{}   // Map for the function task store
-	fparams  map[string][]interface{} // Map for function and  params of function
-	lock     bool                     // lock the job from running at same time form multiple instances
-	tags     []string                 // allow the user to tag jobs with certain labels
+	interval          uint64                   // pause interval * unit between runs
+	startsImmediately bool                     // if the job should run upon scheduler start
+	jobFunc           string                   // the job jobFunc to run, func[jobFunc]
+	unit              timeUnit                 // time units, ,e.g. 'minutes', 'hours'...
+	atTime            time.Duration            // optional time at which this job runs
+	err               error                    // error related to job
+	lastRun           time.Time                // datetime of last run
+	nextRun           time.Time                // datetime of next run
+	startDay          time.Weekday             // Specific day of the week to start on
+	funcs             map[string]interface{}   // Map for the function task store
+	fparams           map[string][]interface{} // Map for function and  params of function
+	lock              bool                     // lock the job from running at same time form multiple instances
+	tags              []string                 // allow the user to tag jobs with certain labels
 }
 
 // NewJob creates a new job with the time interval.
diff --git a/scheduler.go b/scheduler.go
index 8ea14e1..bab2f2c 100644
--- a/scheduler.go
+++ b/scheduler.go
@@ -67,10 +67,6 @@ func (s *Scheduler) ChangeLoc(newLocation *time.Location) {
 
 // scheduleNextRun Compute the instant when this job should run next
 func (s *Scheduler) scheduleNextRun(j *Job) error {
-	if j.nextRun.Location() != s.loc {
-		j.nextRun = j.nextRun.In(s.loc)
-	}
-
 	now := time.Now().In(s.loc)
 	if j.lastRun == time.Unix(0, 0) {
 		j.lastRun = now
@@ -110,8 +106,8 @@ func (s *Scheduler) scheduleNextRun(j *Job) error {
 }
 
 // roundToMidnight truncate time to midnight
-func (j *Scheduler) roundToMidnight(t time.Time) time.Time {
-	return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, j.loc)
+func (s *Scheduler) roundToMidnight(t time.Time) time.Time {
+	return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, s.loc)
 }
 
 // Get the current runnable jobs, which shouldRun is True
@@ -252,8 +248,11 @@ func (s *Scheduler) Do(jobFun interface{}, params ...interface{}) (*Job, error)
 	j.funcs[fname] = jobFun
 	j.fparams[fname] = params
 	j.jobFunc = fname
-	if err := s.scheduleNextRun(j); err != nil {
-		return nil, err
+
+	if !j.startsImmediately {
+		if err := s.scheduleNextRun(j); err != nil {
+			return nil, err
+		}
 	}
 
 	return j, nil
@@ -280,10 +279,17 @@ func (j *Job) GetAt() string {
 	return fmt.Sprintf("%d:%d", j.atTime/time.Hour, (j.atTime%time.Hour)/time.Minute)
 }
 
-// From schedules the next run of the job
-func (s *Scheduler) From(t *time.Time) *Scheduler {
-	currentJob := s.getCurrentJob()
-	currentJob.nextRun = *t
+// StartAt schedules the next run of the job
+func (s *Scheduler) StartAt(t time.Time) *Scheduler {
+	s.getCurrentJob().nextRun = t
+	return s
+}
+
+// StartImmediately sets the jobs next run as soon as the scheduler starts
+func (s *Scheduler) StartImmediately() *Scheduler {
+	job := s.getCurrentJob()
+	job.nextRun = time.Now().In(s.loc)
+	job.startsImmediately = true
 	return s
 }
 
@@ -349,6 +355,12 @@ func (s *Scheduler) Week() *Scheduler {
 	return s
 }
 
+// Weeks sets the job's unit with weeks
+func (s *Scheduler) Weeks() *Scheduler {
+	s.setUnit(weeks)
+	return s
+}
+
 // Weekday start job on specific Weekday
 func (s *Scheduler) Weekday(startDay time.Weekday) *Scheduler {
 	s.mustInterval(1)


Test patch:
diff --git a/gocron_test.go b/gocron_test.go
index fadac86..7275b83 100644
--- a/gocron_test.go
+++ b/gocron_test.go
@@ -90,36 +90,15 @@ func TestScheduler_WeekdaysTodayAfter(t *testing.T) {
 	}
 }
 
-func TestScheduleNextRunLoc(t *testing.T) {
-	laLocation, err := time.LoadLocation("America/Los_Angeles")
-	if err != nil {
-		t.Fatalf("unable to load America/Los_Angeles time location")
-	}
-
-	sched := NewScheduler(time.UTC)
-
-	job, _ := sched.Every(1).Day().At("20:44").Do(task)
-
-	// job just ran (this is 20:45 UTC), so next run should be tomorrow
-	today := time.Now().In(laLocation)
-	job.lastRun = time.Date(today.Year(), today.Month(), today.Day(), 13, 45, 0, 0, laLocation)
-
-	tomorrow := today.AddDate(0, 0, 1)
-	assert.Equal(t, 20, job.NextScheduledTime().UTC().Hour())
-	assert.Equal(t, 44, job.NextScheduledTime().UTC().Minute())
-	assert.Equal(t, tomorrow.Day(), job.NextScheduledTime().UTC().Day())
-}
-
 func TestScheduleNextRunFromNow(t *testing.T) {
 	sched := NewScheduler(time.UTC)
 	now := time.Now().UTC()
 
-	job, _ := sched.Every(1).Hour().From(NextTick()).Do(task)
-
+	job, _ := sched.Every(1).Hour().StartImmediately().Do(task)
 	next := job.NextScheduledTime()
-	nextRounded := time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), next.Minute(), next.Second(), 0, time.UTC)
 
-	expected := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.UTC).Add(time.Second)
+	nextRounded := time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), next.Minute(), next.Second(), 0, time.UTC)
+	expected := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.UTC)
 
 	assert.Exactly(t, expected, nextRounded)
 }