From c1295d9e26c9477a15ceb9d24b664b387ec86971 Mon Sep 17 00:00:00 2001 From: starainrt Date: Mon, 17 Apr 2023 23:45:08 +0800 Subject: [PATCH] update --- cron.go | 22 ++++++++ cron_test.go | 7 +++ time_test.go | 116 ++++++++++++++++++++++++++++++++++++---- timer.go | 147 ++++++++++++++++++++++++++++++++++++--------------- typed.go | 1 + 5 files changed, 242 insertions(+), 51 deletions(-) create mode 100644 cron.go create mode 100644 cron_test.go diff --git a/cron.go b/cron.go new file mode 100644 index 0000000..9027c25 --- /dev/null +++ b/cron.go @@ -0,0 +1,22 @@ +package startimer + +import ( + "errors" + "strings" +) + +func parseCron(cron string) (StarTimer, error) { + for { + oldLen := len(cron) + cron = strings.ReplaceAll(strings.TrimSpace(cron), " ", " ") + if len(cron) == oldLen { + break + } + } + ct := strings.Split(cron, " ") + if len(ct) != 6 { + return StarTimer{}, errors.New("Invalid cron,argument not enough") + } + + return StarTimer{}, nil +} diff --git a/cron_test.go b/cron_test.go new file mode 100644 index 0000000..f0fd0db --- /dev/null +++ b/cron_test.go @@ -0,0 +1,7 @@ +package startimer + +import "testing" + +func TestParseCron(t *testing.T) { + parseCron("0 */4 * * * *") +} diff --git a/time_test.go b/time_test.go index bde4070..d563f1c 100644 --- a/time_test.go +++ b/time_test.go @@ -7,16 +7,20 @@ import ( ) func TestTimer(t *testing.T) { - tk:= StarTimer{ - base: time.Now(), - repeat: []*Repeats{ + tk := StarTimer{ + base: time.Now(), + repeat: []*Repeats{ { - Every: false, + Every: false, Repeat: []Repeat{ { Unit: STAR_MINUTE, Value: 7, }, + { + Unit: STAR_HOUR, + Value: 19, + }, { Unit: STAR_HOUR, Value: 18, @@ -24,7 +28,7 @@ func TestTimer(t *testing.T) { }, }, { - Every: false, + Every: false, Repeat: []Repeat{ { Unit: STAR_MINUTE, @@ -37,7 +41,7 @@ func TestTimer(t *testing.T) { }, }, { - Every: true, + Every: true, Repeat: []Repeat{ { Unit: STAR_HOUR, @@ -47,9 +51,103 @@ func TestTimer(t *testing.T) { }, }, } - base:=tk.base - for i:=0;i<10;i++{ - base=tk.parseNextDate(base) + base := tk.base + for i := 0; i < 50; i++ { + base = tk.parseNextDate(base, true) + fmt.Println(base) + } +} + +func TestPrepareCronMax(t *testing.T) { + var rpt = new(Repeats) + for i := 0; i < 60; i++ { + if i%2 != 0 { + continue + } + rpt.Repeat = append(rpt.Repeat, Repeat{ + Unit: STAR_SECOND, + Value: uint32(i), + }, Repeat{ + Unit: STAR_MINUTE, + Value: uint32(i), + }) + } + /* + for i := 0; i < 24; i++ { + rpt.Repeat = append(rpt.Repeat, Repeat{ + Unit: STAR_HOUR, + Value: uint32(i), + }) + } + + */ + for i := 1; i < 7; i++ { + rpt.Repeat = append(rpt.Repeat, Repeat{ + Unit: STAR_MONTH, + Value: uint32(i), + }) + } + tk := StarTimer{ + base: time.Now(), + repeat: []*Repeats{ + { + Every: false, + Repeat: rpt.Repeat, + }, + }, + } + base := tk.base + for i := 0; i < 10; i++ { + base = tk.parseNextDate(base, true) + fmt.Println(base) + } +} + +func TestPrepareCron(t *testing.T) { + tk := StarTimer{ + base: time.Now(), + repeat: []*Repeats{ + { + //*/3,5,6 */2,4,6 6 1-5 5 + Every: false, + Repeat: []Repeat{ + {Unit: STAR_MINUTE, Value: 0}, {Unit: STAR_MINUTE, Value: 3}, {Unit: STAR_MINUTE, Value: 6}, {Unit: STAR_MINUTE, Value: 9}, {Unit: STAR_MINUTE, Value: 12}, {Unit: STAR_MINUTE, Value: 15}, {Unit: STAR_MINUTE, Value: 18}, {Unit: STAR_MINUTE, Value: 21}, + {Unit: STAR_MINUTE, Value: 24}, {Unit: STAR_MINUTE, Value: 27}, {Unit: STAR_MINUTE, Value: 30}, {Unit: STAR_MINUTE, Value: 33}, {Unit: STAR_MINUTE, Value: 36}, {Unit: STAR_MINUTE, Value: 39}, {Unit: STAR_MINUTE, Value: 42}, {Unit: STAR_MINUTE, Value: 45}, + {Unit: STAR_MINUTE, Value: 48}, {Unit: STAR_MINUTE, Value: 51}, {Unit: STAR_MINUTE, Value: 54}, {Unit: STAR_MINUTE, Value: 57}, {Unit: STAR_MINUTE, Value: 5}, + {Unit: STAR_HOUR, Value: 2}, {Unit: STAR_HOUR, Value: 4}, {Unit: STAR_HOUR, Value: 6}, {Unit: STAR_HOUR, Value: 8}, {Unit: STAR_HOUR, Value: 10}, {Unit: STAR_HOUR, Value: 12}, {Unit: STAR_HOUR, Value: 14}, {Unit: STAR_HOUR, Value: 16}, {Unit: STAR_HOUR, Value: 18}, {Unit: STAR_HOUR, Value: 20}, {Unit: STAR_HOUR, Value: 22}, {Unit: STAR_HOUR, Value: 0}, + {Unit: STAR_DAY, Value: 6}, + {Unit: STAR_MONTH, Value: 1}, {Unit: STAR_MONTH, Value: 2}, {Unit: STAR_MONTH, Value: 3}, {Unit: STAR_MONTH, Value: 4}, {Unit: STAR_MONTH, Value: 5}, + {Unit: STAR_WEEK, Value: 5}, + }, + }, + }, + } + base := tk.base + for i := 0; i < 10; i++ { + base = tk.parseNextDate(base, true) + fmt.Println(base) + } +} + +func TestPrepareCronSimple(t *testing.T) { + tk := StarTimer{ + base: time.Now(), + repeat: []*Repeats{ + { + Every: false, + Repeat: []Repeat{ + {Unit: STAR_MINUTE, Value: 0}, {Unit: STAR_MINUTE, Value: 3}, {Unit: STAR_MINUTE, Value: 6}, + {Unit: STAR_HOUR, Value: 2}, {Unit: STAR_HOUR, Value: 4}, {Unit: STAR_HOUR, Value: 6}, + {Unit: STAR_DAY, Value: 6}, + {Unit: STAR_MONTH, Value: 1}, {Unit: STAR_MONTH, Value: 5}, + }, + }, + }, + } + base := tk.base + for i := 0; i < 1; i++ { + base = tk.parseNextDate(base, true) fmt.Println(base) + fmt.Println("") } } diff --git a/timer.go b/timer.go index e2ae8b4..8ebba0b 100644 --- a/timer.go +++ b/timer.go @@ -201,9 +201,14 @@ func (t *StarTimer) parseNextDate(base time.Time, isMock bool) time.Time { if len(dates) == 0 { return time.Time{} } - now := time.Now().UnixNano() + var bt int64 + if !isMock { + bt = time.Now().UnixNano() + } else { + bt = base.UnixNano() + } for _, v := range dates { - if v.UnixNano() > now { + if v.UnixNano() > bt { return v } } @@ -211,54 +216,112 @@ func (t *StarTimer) parseNextDate(base time.Time, isMock bool) time.Time { } func (t *StarTimer) parseStaticNextDate(base time.Time, r *Repeats) time.Time { - target := base - if !r.Every { //固定日期 + var targets []time.Time + var uniqueRepeat [][]Repeat + selectMap := make(map[Unit][]Repeat) + { for _, d := range r.Repeat { - switch d.Unit { - case STAR_SECOND: - sub := int(d.Value) - target.Second() - if sub < 0 { - sub += 60 - } - target = target.Add(time.Second * time.Duration(sub)) - case STAR_MINUTE: - sub := int(d.Value) - target.Minute() - if sub < 0 { - sub += 60 - } - target = target.Add(time.Minute * time.Duration(sub)) - case STAR_HOUR: - sub := int(d.Value) - target.Hour() - if sub < 0 { - sub += 24 - } - target = target.Add(time.Hour * time.Duration(sub)) - case STAR_DAY: - sub := int(d.Value) - target.Day() - if sub >= 0 { - target = target.Add(time.Hour * 24 * time.Duration(sub)) - continue + selectMap[d.Unit] = append(selectMap[d.Unit], d) + } + for key, val := range selectMap { + if key == STAR_WEEK { + continue + } + defUnikey := make([][]Repeat, 0, 1024) + for _, vs := range val { + if len(uniqueRepeat) == 0 { + defUnikey = append(defUnikey, []Repeat{vs}) + } else { + for k := range uniqueRepeat { + tmp := make([]Repeat, len(uniqueRepeat[k])+1) + copy(tmp, append(uniqueRepeat[k], vs)) + defUnikey = append(defUnikey, tmp) + } } - target = time.Date(target.Year(), target.Month()+1, int(d.Value), target.Hour(), target.Minute(), target.Second(), 0, target.Location()) - case STAR_MONTH: - sub := int(d.Value) - int(target.Month()) - if sub < 0 { - sub += 12 + } + if len(defUnikey) > 0 { + uniqueRepeat = defUnikey + } + } + } + for _, task := range uniqueRepeat { + sort.SliceStable(task, func(i, j int) bool { + return task[i].Unit < task[j].Unit + }) + target := base + if !r.Every { //固定日期 + for _, d := range task { + switch d.Unit { + case STAR_SECOND: + sub := int(d.Value) - target.Second() + if sub < 0 { + sub += 60 + } + target = target.Add(time.Second * time.Duration(sub)) + case STAR_MINUTE: + sub := int(d.Value) - target.Minute() + if sub < 0 { + sub += 60 + } + target = target.Add(time.Minute * time.Duration(sub)) + case STAR_HOUR: + sub := int(d.Value) - target.Hour() + if sub < 0 { + sub += 24 + } + target = target.Add(time.Hour * time.Duration(sub)) + case STAR_DAY: + sub := int(d.Value) - target.Day() + if sub >= 0 { + target = target.Add(time.Hour * 24 * time.Duration(sub)) + continue + } + target = time.Date(target.Year(), target.Month()+1, int(d.Value), target.Hour(), target.Minute(), target.Second(), 0, target.Location()) + case STAR_MONTH: + sub := int(d.Value) - int(target.Month()) + if sub < 0 { + sub += 12 + } + target = target.AddDate(0, sub, 0) + case STAR_YEAR: + sub := int(d.Value) - int(target.Year()) + if sub < 0 { + continue + } + target = target.AddDate(sub, 0, 0) } - target = target.AddDate(0, sub, 0) - case STAR_YEAR: - sub := int(d.Value) - int(target.Year()) - if sub < 0 { - return time.Date(0, 0, 0, 0, 0, 0, 0, nil) + } + } + + if target == base { + continue + } + targets = append(targets, target) + + } + sort.SliceStable(targets, func(i, j int) bool { + return targets[i].UnixNano() < targets[j].UnixNano() + }) + for k, v := range targets { + if v.After(base) { + targets = targets[k:] + break + } + } + if val, ok := selectMap[STAR_WEEK]; ok { + if len(targets) > 0 { + for _, week := range val { + if int(targets[0].Weekday()) == int(week.Value) { + return targets[0] } - target = target.AddDate(sub, 0, 0) } + return t.parseStaticNextDate(targets[0].Add(time.Hour*24), r) } } - if target == base { - return time.Time{} + if len(targets) > 0 { + return targets[0] } - return target + return time.Time{} } func (t *StarTimer) parseEveryNextDate(target time.Time, r *Repeats, isMock bool) []time.Time { diff --git a/typed.go b/typed.go index 11a803e..3370b09 100644 --- a/typed.go +++ b/typed.go @@ -15,6 +15,7 @@ const ( STAR_DAY STAR_MONTH STAR_YEAR + STAR_WEEK ) type Repeats struct {