Repository: go-co-op/gocron
Pull request #48 (2020-07-19 04:56:57)

Parse the At() time with time.Parse()
### What does this do?
Parse the At() time with time.Parse() instead of `Atoi`

### Which issue(s) does this PR fix/relate to?
#14 


### List any changes that modify/break current functionality
One small change is before `6:40` would have been considered valid, but now, it has to be `06:40`.

### Have you included tests for your changes?
Existing tests suffice 

### Did you document any new/modified functionality?

- [ ] Updated `example_test.go`
- [ ] Updated `README.md`

### Notes



Patch:
diff --git a/gocron.go b/gocron.go
index d7c0acb..38ad955 100644
--- a/gocron.go
+++ b/gocron.go
@@ -15,19 +15,26 @@ import (
 	"errors"
 	"fmt"
 	"reflect"
+	"regexp"
 	"runtime"
-	"strconv"
-	"strings"
+	"time"
 )
 
 // Error declarations for gocron related errors
 var (
-	ErrTimeFormat          = errors.New("time format error")
-	ErrParamsNotAdapted    = errors.New("the number of params is not adapted")
-	ErrNotAFunction        = errors.New("only functions can be schedule into the job queue")
-	ErrPeriodNotSpecified  = errors.New("unspecified job period")
-	ErrNotScheduledWeekday = errors.New("job not scheduled weekly on a weekday")
-	ErrJobNotFoundWithTag  = errors.New("no jobs found with given tag")
+	ErrTimeFormat            = errors.New("time format error")
+	ErrParamsNotAdapted      = errors.New("the number of params is not adapted")
+	ErrNotAFunction          = errors.New("only functions can be schedule into the job queue")
+	ErrPeriodNotSpecified    = errors.New("unspecified job period")
+	ErrNotScheduledWeekday   = errors.New("job not scheduled weekly on a weekday")
+	ErrJobNotFoundWithTag    = errors.New("no jobs found with given tag")
+	ErrUnsupportedTimeFormat = errors.New("the given time format is not supported")
+)
+
+// regex patterns for supported time formats
+var (
+	timeWithSeconds    = regexp.MustCompile(`(?m)^\d\d:\d\d:\d\d$`)
+	timeWithoutSeconds = regexp.MustCompile(`(?m)^\d\d:\d\d$`)
 )
 
 type timeUnit int
@@ -63,27 +70,20 @@ func getFunctionKey(funcName string) string {
 	return fmt.Sprintf("%x", h.Sum(nil))
 }
 
-func formatTime(t string) (hour, min, sec int, err error) {
-	ts := strings.Split(t, ":")
-	if len(ts) < 2 || len(ts) > 3 {
-		return 0, 0, 0, ErrTimeFormat
-	}
-
-	if hour, err = strconv.Atoi(ts[0]); err != nil {
-		return 0, 0, 0, err
-	}
-	if min, err = strconv.Atoi(ts[1]); err != nil {
-		return 0, 0, 0, err
-	}
-	if len(ts) == 3 {
-		if sec, err = strconv.Atoi(ts[2]); err != nil {
-			return 0, 0, 0, err
-		}
+func parseTime(t string) (hour, min, sec int, err error) {
+	var timeLayout string
+	switch {
+	case timeWithSeconds.Match([]byte(t)):
+		timeLayout = "15:04:05"
+	case timeWithoutSeconds.Match([]byte(t)):
+		timeLayout = "15:04"
+	default:
+		return 0, 0, 0, ErrUnsupportedTimeFormat
 	}
 
-	if hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59 {
-		return 0, 0, 0, ErrTimeFormat
+	parsedTime, err := time.Parse(timeLayout, t)
+	if err != nil {
+		return 0, 0, 0, ErrUnsupportedTimeFormat
 	}
-
-	return hour, min, sec, nil
+	return parsedTime.Hour(), parsedTime.Minute(), parsedTime.Second(), nil
 }
diff --git a/scheduler.go b/scheduler.go
index 605eb7e..1f90d1c 100644
--- a/scheduler.go
+++ b/scheduler.go
@@ -327,7 +327,7 @@ func (s *Scheduler) Do(jobFun interface{}, params ...interface{}) (*Job, error)
 // At schedules the Job at a specific time of day in the form "HH:MM:SS" or "HH:MM"
 func (s *Scheduler) At(t string) *Scheduler {
 	j := s.getCurrentJob()
-	hour, min, sec, err := formatTime(t)
+	hour, min, sec, err := parseTime(t)
 	if err != nil {
 		j.err = ErrTimeFormat
 		return s


Test patch:
diff --git a/gocron_test.go b/gocron_test.go
index 72fc29b..c349d23 100644
--- a/gocron_test.go
+++ b/gocron_test.go
@@ -26,7 +26,7 @@ func TestFormatTime(t *testing.T) {
 		},
 		{
 			name:     "normal_with_second",
-			args:     "6:18:01",
+			args:     "06:18:01",
 			wantHour: 6,
 			wantMin:  18,
 			wantSec:  1,
@@ -77,7 +77,7 @@ func TestFormatTime(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			gotHour, gotMin, gotSec, err := formatTime(tt.args)
+			gotHour, gotMin, gotSec, err := parseTime(tt.args)
 			if tt.wantErr {
 				assert.NotEqual(t, nil, err, tt.args)
 				return