Compare commits

..

No commits in common. "master" and "v0.0.1" have entirely different histories.

6 changed files with 265 additions and 592 deletions

View File

@ -1 +0,0 @@
package crontab

View File

@ -4,49 +4,46 @@ import (
"errors" "errors"
"fmt" "fmt"
"log" "log"
"reflect"
"regexp" "regexp"
"strconv"
"strings" "strings"
"time" "time"
"github.com/satori/go.uuid" clinked "474420502.top/eson/structure/circular_linked"
"474420502.top/eson/structure/circular_linked"
"github.com/Pallinder/go-randomdata" "github.com/Pallinder/go-randomdata"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
) )
// StatusType 设置状态的类型 type randLR struct {
type StatusType int left, right int
const (
_ StatusType = iota
// SExecuteOK 设置这个次成功或者失败的状态
SExecuteOK
// SExecuteSleep 设置下次Sleep时间, 只影响一次
SExecuteSleep
// SExecuteCrontab 设置改写Crontab, 覆盖以前的Crontab
SExecuteCrontab
)
// Force 强制下次执行
type Force struct {
sleep time.Duration
} }
// NextTime 下次执行时间 type hInterval struct {
func (force *Force) NextTime() time.Time { PlanFail []randLR
return time.Now().Add(force.sleep) PlanNormal []randLR
Count int
ConstCount int
}
func (interval *hInterval) reset() {
interval.Count = interval.ConstCount
}
type timePointer struct {
left, right int
leftlimit, rightlimit int
per int
isAll bool
}
func (tp *timePointer) String() string {
return fmt.Sprintf("left: %d, right: %d, leftlimit: %d, rightlimit: %d, per: %d", tp.left, tp.right, tp.leftlimit, tp.rightlimit, tp.per)
} }
// Crontab 的string解析 // Crontab 的string解析
type Crontab struct { type Crontab struct {
crontab string
uid uuid.UUID
force *Force
min []timePointer min []timePointer
hour []timePointer hour []timePointer
day []timePointer day []timePointer
@ -60,74 +57,33 @@ type Crontab struct {
interval *clinked.CircularLinked interval *clinked.CircularLinked
lastStatus bool lastStatus bool
isCalculated bool
trueCount int
failCount int
nextTime time.Time nextTime time.Time
} }
// NewCrontab create 一个crontab // NewCrontab create 一个crontab
func NewCrontab(crontab string) *Crontab { func NewCrontab(crontab string) *Crontab {
cron := &Crontab{} cron := &Crontab{}
cron.crontab = strings.TrimSpace(crontab) cron.FromString(crontab)
cron.FromString(cron.crontab)
return cron return cron
} }
// UnmarshalYAML 添加序列化接口 Marshal没实现, 需要的时候可以自己添加 // SetStatus 设置状态 接口定义
func (cron *Crontab) UnmarshalYAML(unmarshal func(interface{}) error) error { func (cron *Crontab) SetStatus(status interface{}) {
var buf string
err := unmarshal(&buf)
if err != nil {
return nil
}
if err := cron.FromString(buf); err != nil {
return err
}
return nil
}
// SetStatus 设置上次状态 true false
func (cron *Crontab) SetStatus(statusType StatusType, statusValue ...interface{}) {
switch statusType {
case SExecuteOK:
if cron.interval != nil { if cron.interval != nil {
cron.lastStatus = statusValue[0].(bool) cron.lastStatus = status.(bool)
} }
case SExecuteSleep:
force := new(Force)
ivalue := statusValue[0]
switch value := ivalue.(type) {
case int:
force.sleep = time.Duration(value) * time.Second
case int64:
force.sleep = time.Duration(value) * time.Second
case time.Duration:
force.sleep = value
default:
panic(errors.New("statusValue type is error, the type is" + reflect.TypeOf(ivalue).String()))
}
cron.force = force
case SExecuteCrontab:
crontab := statusValue[0].(string)
cron.crontab = strings.TrimSpace(crontab)
cron.FromString(cron.crontab)
default:
panic(errors.New("StatusType is unknown, the type " + reflect.TypeOf(statusType).String()))
} }
// GetStatus 设置状态 接口定义
func (cron *Crontab) GetStatus() (status interface{}) {
if cron.interval != nil {
return cron.lastStatus
}
return nil
} }
// // GetStatus 获取上次状态 true false // TimeUp 是否时间快到
// func (cron *Crontab) GetStatus() (status bool) {
// return cron.lastStatus
// }
// TimeUp 是否时间快到, 时间间隔调用完TimeUp后必须调用NextTime, 为了精准控制时间
func (cron *Crontab) TimeUp() bool { func (cron *Crontab) TimeUp() bool {
if cron.interval != nil { if cron.interval != nil {
@ -138,27 +94,16 @@ func (cron *Crontab) TimeUp() bool {
} }
// NextTime 返回下次任务的时间 // NextTime 返回下次任务的时间
func (cron *Crontab) NextTime() time.Time { func (cron *Crontab) NextTime() *time.Time {
if cron.force != nil {
nt := cron.force.NextTime()
cron.force = nil
return nt
}
if cron.interval != nil { if cron.interval != nil {
if !cron.isCalculated { return &cron.nextTime
now := time.Now()
cron.intervalCalculateNextTime(now)
}
return cron.nextTime
} }
if len(cron.WillPlans) > 0 { if len(cron.WillPlans) > 0 {
return cron.WillPlans[0] return &cron.WillPlans[0]
} }
return time.Now().Add(time.Second * 2) return nil
} }
func (cron *Crontab) String() string { func (cron *Crontab) String() string {
@ -167,36 +112,15 @@ func (cron *Crontab) String() string {
// FromString 解析crontab 的 表达式 // FromString 解析crontab 的 表达式
func (cron *Crontab) FromString(crontab string) error { func (cron *Crontab) FromString(crontab string) error {
crontab = cron.crontab crontab = strings.TrimSpace(crontab)
uid, err := uuid.NewV4()
if err != nil {
panic(err)
}
cron.uid = uid
cron.interval = nil
cron.min = nil
cron.hour = nil
cron.day = nil
cron.month = nil
cron.week = nil
cron.WillPlans = nil
cron.SkipPlans = nil
cron.YearPlan = nil
matches := regexp.MustCompile("[^ ]+").FindAllString(crontab, -1) matches := regexp.MustCompile("[^ ]+").FindAllString(crontab, -1)
mlen := len(matches) mlen := len(matches)
switch mlen { switch mlen {
case 1: case 1:
// "f1-2|5-10x5,f1|10m,10-15,f1" // "f1-2|5-10x5,f1|10m,10-15,f1"
cron.lastStatus = true
cron.isCalculated = true
cron.nextTime = time.Now() cron.nextTime = time.Now()
cron.lastStatus = true
cron.interval = clinked.NewCircularLinked() cron.interval = clinked.NewCircularLinked()
var intervalList []interface{} var intervalList []interface{}
intervalList = parseIntervalString(matches[0]) intervalList = parseIntervalString(matches[0])
@ -210,7 +134,6 @@ func (cron *Crontab) FromString(crontab string) error {
cron.week = createTimePointer(matches[4], 0, 6, true) cron.week = createTimePointer(matches[4], 0, 6, true)
cron.createYearPlan() cron.createYearPlan()
cron.TimeUp()
default: default:
return errors.New("mathches len != want, check crontab string") return errors.New("mathches len != want, check crontab string")
} }
@ -230,7 +153,7 @@ func (cron *Crontab) linuxTimeUp() bool {
createlen := 500 createlen := 500
plen := len(cron.WillPlans) plen := len(cron.WillPlans)
if plen <= createlen { // 如果当前生成的计划表少于 限制的500. 就生成新的计划表 if plen <= createlen {
var lastplan time.Time var lastplan time.Time
if plen == 0 { if plen == 0 {
lastplan = now lastplan = now
@ -248,13 +171,9 @@ func (cron *Crontab) linuxTimeUp() bool {
if len(cron.WillPlans) > 0 { if len(cron.WillPlans) > 0 {
istimeup := false istimeup := false
for i := 0; i < maxlen; i++ { for i := 0; i < maxlen; i++ {
// 统计过了多少计划任务时间表 i - 1
if now.Unix() >= cron.WillPlans[i].Unix() { if now.Unix() >= cron.WillPlans[i].Unix() {
istimeup = true istimeup = true
} else { } else {
// 清除过时的计划任务时间表
if istimeup { if istimeup {
if i-1 > 0 { if i-1 > 0 {
cron.SkipPlans = append(cron.SkipPlans, cron.WillPlans[0:i-1]...) cron.SkipPlans = append(cron.SkipPlans, cron.WillPlans[0:i-1]...)
@ -269,7 +188,7 @@ func (cron *Crontab) linuxTimeUp() bool {
return istimeup return istimeup
} }
} }
// 如果所有计划表都不符合, 全部放到忽略的计划表上, 这个表方便打印查看, 因为程序执行超时过了多少计划任务
cron.SkipPlans = append(cron.SkipPlans, cron.WillPlans...) cron.SkipPlans = append(cron.SkipPlans, cron.WillPlans...)
cron.WillPlans = nil cron.WillPlans = nil
return istimeup return istimeup
@ -279,52 +198,21 @@ func (cron *Crontab) linuxTimeUp() bool {
return false return false
} }
// IntervalCalculateNextTime 计算时间间隔的下次时间 func (cron *Crontab) intervalTimeUp() bool {
func (cron *Crontab) intervalCalculateNextTime(now time.Time) {
iv := cron.interval.Cursor().GetValue().(*hInterval) now := time.Now()
if now.Unix() >= cron.nextTime.Unix() {
iv := cron.interval.Cursor().GetValue().(hInterval)
isecond := 0 isecond := 0
if cron.lastStatus == false && len(iv.PlanFail) > 0 {
if iv.PlanFailCount.Size() == 0 && len(iv.PlanFail) == 0 {
cron.lastStatus = true
}
if cron.lastStatus {
cron.trueCount++
cron.failCount = 0
isecond = intervalPriorityListISecond(&iv.PlanTrueCount, cron.trueCount)
if isecond == -1 {
if len(iv.PlanTrue) > 0 {
idx := randomdata.Number(len(iv.PlanTrue))
lr := iv.PlanTrue[idx]
isecond = randomdata.Number(lr.left, lr.right+1)
} else {
isecond = 0
}
}
fmt.Println(time.Now().Format("01-02 15:04:05"), cron.uid.String(), "success:", cron.trueCount, " wait:", isecond)
} else {
cron.failCount++
cron.trueCount = 0
isecond = intervalPriorityListISecond(&iv.PlanFailCount, cron.failCount)
if isecond == -1 {
if len(iv.PlanFail) > 0 {
idx := randomdata.Number(len(iv.PlanFail)) idx := randomdata.Number(len(iv.PlanFail))
lr := iv.PlanFail[idx] lr := iv.PlanFail[idx]
isecond = randomdata.Number(lr.left, lr.right+1) isecond = randomdata.Number(lr.left, lr.right+1)
} else { } else {
isecond = 0 idx := randomdata.Number(len(iv.PlanNormal))
} lr := iv.PlanNormal[idx]
} isecond = randomdata.Number(lr.left, lr.right+1)
fmt.Println(time.Now().Format("01-02 15:04:05"), cron.uid.String(), "fail:", cron.failCount, " wait:", isecond)
} }
iv.Count-- iv.Count--
@ -333,19 +221,192 @@ func (cron *Crontab) intervalCalculateNextTime(now time.Time) {
cron.interval.MoveNext() cron.interval.MoveNext()
} }
cron.isCalculated = true
cron.nextTime = now.Add(time.Duration(isecond) * time.Second) cron.nextTime = now.Add(time.Duration(isecond) * time.Second)
}
func (cron *Crontab) intervalTimeUp() bool {
if cron.isCalculated { // 需要调用nexttime()才能正常正常计算下次的时间
now := time.Now()
if now.Unix() >= cron.nextTime.Unix() {
cron.isCalculated = false
return true return true
} }
}
return false return false
} }
func createTimePointer(min string, llimit, rlimit int, fixedLeftRight bool) []timePointer {
var result []timePointer
exelist := strings.Split(min, ",")
for _, exe := range exelist {
tp := timePointer{}
takeper := strings.Split(exe, "/") // per
var rangevalue, per string
if len(takeper) == 1 {
rangevalue = exe
per = "1"
} else {
rangevalue = takeper[0]
per = takeper[1]
}
// takeRange
be := strings.Split(rangevalue, "-")
var left, rigth string
switch len(be) {
case 1:
left = be[0]
rigth = be[0]
case 2:
left = be[0]
rigth = be[1]
default:
panic(errors.New("range value is > 2"))
}
if left == "*" {
tp.left = llimit
} else {
ileft, err := strconv.Atoi(strings.Replace(left, "^", "-", -1))
if err != nil {
panic(err)
}
tp.left = ileft
}
if rigth == "*" {
tp.right = rlimit
} else {
iright, err := strconv.Atoi(strings.Replace(rigth, "^", "-", -1))
if err != nil {
panic(err)
}
tp.right = iright
}
iper, err := strconv.Atoi(per)
if err != nil {
panic(err)
}
tp.per = iper
tp.leftlimit = llimit
tp.rightlimit = rlimit
// 修正左值
leftfixed := tp.left
if leftfixed < 0 {
leftfixed += tp.rightlimit + 1
if fixedLeftRight {
tp.left = leftfixed
}
}
rightfixed := tp.right
if rightfixed < 0 {
rightfixed += tp.rightlimit + 1
if fixedLeftRight {
tp.right = rightfixed
}
}
// 全部符合 当左等于左 且 右等于右最大 并且 per == 1 TODO: 如果加入时间间隔 就需要 加多一个 附加值
if leftfixed == tp.leftlimit && rightfixed == tp.rightlimit && tp.per == 1 {
tp.isAll = true
}
result = append(result, tp)
}
return result
}
func parseIntervalString(crontab string) []interface{} {
var result []interface{}
values := strings.Split(crontab, ",")
for _, value := range values {
interval := hInterval{}
// 次数
valuesCounts := strings.Split(value, "x")
switch len(valuesCounts) {
case 1:
interval.ConstCount = 1
case 2:
count, err := strconv.Atoi(valuesCounts[1])
if err != nil {
panic(err)
}
interval.ConstCount = count
default:
panic("valuesCounts error, the len is not in range")
}
// 统计失败与普通间隔值的数组
failAndNormal := valuesCounts[0]
valuesFN := strings.Split(failAndNormal, "|")
for _, FN := range valuesFN {
if FN == "" {
continue
}
switch FN[0] {
case 'f', 'F':
fvalue := FN[1:]
interval.PlanFail = append(interval.PlanFail, parseRandLR(fvalue))
case 'n':
value := FN[1:]
interval.PlanNormal = append(interval.PlanNormal, parseRandLR(value))
default:
interval.PlanNormal = append(interval.PlanNormal, parseRandLR(FN))
}
}
interval.reset()
result = append(result, interval)
}
return result
}
func parseRandLR(value string) randLR {
vlen := len(value)
lastchar := value[vlen-1]
lr := strings.Split(value, "-")
switch len(lr) {
case 1:
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[0], lastchar)}
return lr
case 2:
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[1], lastchar)}
return lr
default:
panic("lr is error")
}
}
func getInt(v string) int {
vint, err := strconv.Atoi(v)
if err != nil {
panic(err)
}
return vint
}
func parseTimeValue(v string, lastchar byte) int {
vlen := len(v)
switch lastchar {
case 's':
return getInt(v[:vlen-1])
case 'm':
return getInt(v[:vlen-1]) * 60
case 'h':
return getInt(v[:vlen-1]) * 3600
case 'd':
return getInt(v[:vlen-1]) * 3600 * 24
default:
return getInt(v)
}
}

View File

@ -2,12 +2,9 @@ package crontab
import ( import (
"fmt" "fmt"
"log"
"runtime" "runtime"
"testing" "testing"
"time" "time"
"github.com/satori/go.uuid"
) )
// type LRValue struct { // type LRValue struct {
@ -29,8 +26,8 @@ func TestParseCrontab(t *testing.T) {
} }
cron.createYearPlan() cron.createYearPlan()
if cron.TimeUp() { if !cron.TimeUp() {
t.Error("timeup error", cron.WillPlans[0:2]) t.Error("timeup error")
} }
PrintMemUsage() PrintMemUsage()
@ -39,13 +36,13 @@ func TestParseCrontab(t *testing.T) {
func TestParseInterval(t *testing.T) { func TestParseInterval(t *testing.T) {
//crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围 //crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围
//crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f22?15-12" //crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f1"
crontab := "2s" crontab := "2"
cron := NewCrontab(crontab) cron := NewCrontab(crontab)
now := time.Now() now := time.Now()
for i := 0; i <= 3; i++ { for i := 0; i <= 6; i++ {
log.Println(cron.NextTime())
if cron.TimeUp() { if cron.TimeUp() {
sec := time.Since(now).Seconds() sec := time.Since(now).Seconds()
if i != 0 { if i != 0 {
if 2.0 <= sec && sec <= 2.1 { if 2.0 <= sec && sec <= 2.1 {
@ -61,85 +58,13 @@ func TestParseInterval(t *testing.T) {
} }
} }
func isInRangeTime(sec, t float64) error {
if sec >= t-0.05 && sec <= t+0.05 {
return nil
}
return fmt.Errorf("计算错误 范围 %f-%f interval time is %f", t-0.05, t+0.05, sec)
}
func TestParseIntervalOnline1(t *testing.T) {
uid, _ := uuid.NewV4()
log.Println(string(uid.Bytes()))
crontab := "f[c > 2]=3|s[c <= 2]"
log.Println(crontab)
}
func TestParseIntervalPlus(t *testing.T) { func TestParseIntervalPlus(t *testing.T) {
// crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围 // crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围
// crondata := NewCrontab("*22 * * * *") // crondata := NewCrontab("*22 * * * *")
//crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围 //crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围
//crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f1" ^代表往后算 ^5 2月份就代表 28-4=24 f代表失败后1-2秒设置 由SetStatus控制 t 相反默认不写前缀为t //crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f1"
log.SetFlags(log.Llongfile)
crontab := "f=2|f2>=3|f3>=4|1|s4>=5"
cron := NewCrontab(crontab)
i := 0
now := time.Now()
lasttime := now
for j := 0; j <= 2500; j++ {
nexttime := cron.NextTime()
if j >= 5 && !nexttime.Equal(lasttime) {
lasttime = nexttime
}
if cron.TimeUp() {
sec := time.Since(now).Seconds()
switch i {
case 0:
case 1:
if err := isInRangeTime(sec, 2.0); err != nil {
t.Error(err.Error(), "status = ", cron.lastStatus)
}
case 2:
if err := isInRangeTime(sec, 3.0); err != nil {
t.Error(err.Error(), "status = ", cron.lastStatus)
}
case 3:
if err := isInRangeTime(sec, 4.0); err != nil {
t.Error(err.Error(), "status = ", cron.lastStatus)
}
case 5:
if err := isInRangeTime(sec, 1); err != nil {
t.Error(err.Error(), "status = ", cron.lastStatus)
}
default:
if i >= 10 {
if err := isInRangeTime(sec, 5.0); err != nil {
t.Error(err.Error(), "status = ", cron.lastStatus)
}
}
}
if i <= 3 {
cron.SetStatus(SExecuteOK, false)
} else {
cron.SetStatus(SExecuteOK, true)
}
now = time.Now()
i++
}
time.Sleep(time.Millisecond * 10)
}
} }
func PrintMemUsage() { func PrintMemUsage() {

View File

@ -1,205 +0,0 @@
package crontab
import (
"errors"
"strconv"
"strings"
"474420502.top/eson/structure/priority_list"
randomdata "github.com/Pallinder/go-randomdata"
)
type randLR struct {
left, right int
}
// NodeCount 用于priority_list
type NodeCount struct {
plist.Node
randLR
}
type hInterval struct {
PlanFailCount plist.PriorityList
PlanTrueCount plist.PriorityList
PlanFail []randLR
PlanTrue []randLR
Count int
ConstCount int
}
func (interval *hInterval) reset() {
interval.Count = interval.ConstCount
}
// Compare NodeCount比较函数
func (rlr *NodeCount) Compare(v plist.INode) bool {
return rlr.GetValue().(int) > v.GetValue().(int)
}
func parseIntervalFail(interval *hInterval, FN string) {
scharIndex := strings.Index(FN, ">")
if scharIndex != -1 {
if FN[scharIndex+1] != '=' {
panic(errors.New("= is not exist"))
}
fc := FN[0:scharIndex]
flr := FN[scharIndex+2:]
node := new(NodeCount)
node.SetValue(getInt(fc[1:]))
node.randLR = parseRandLR(flr)
interval.PlanFailCount.Insert(node)
} else {
if FN[1] != '=' {
panic(errors.New("= is not exist"))
}
fvalue := FN[2:]
interval.PlanFail = append(interval.PlanFail, parseRandLR(fvalue))
}
}
func parseIntervalSuccess(interval *hInterval, FN string) {
scharIndex := strings.Index(FN, ">")
if scharIndex != -1 {
if FN[scharIndex+1] != '=' {
panic(errors.New("= is not exist"))
}
tc := FN[0:scharIndex]
tlr := FN[scharIndex+2:]
node := new(NodeCount)
node.SetValue(getInt(tc[1:]))
node.randLR = parseRandLR(tlr)
interval.PlanTrueCount.Insert(node)
} else {
if FN[1] != '=' {
panic(errors.New("= is not exist"))
}
tvalue := FN[2:]
interval.PlanTrue = append(interval.PlanTrue, parseRandLR(tvalue))
}
}
func parseIntervalString(crontab string) []interface{} {
var result []interface{}
values := strings.Split(crontab, ",")
for _, value := range values {
interval := &hInterval{}
// 次数
valuesCounts := strings.Split(value, "x")
switch len(valuesCounts) {
case 1:
interval.ConstCount = 1
case 2:
count, err := strconv.Atoi(valuesCounts[1])
if err != nil {
panic(err)
}
interval.ConstCount = count
default:
panic("valuesCounts error, the len is not in range")
}
// 统计失败与普通间隔值的数组
failAndNormal := valuesCounts[0]
valuesFN := strings.Split(failAndNormal, "|")
for _, FN := range valuesFN {
if FN == "" {
continue
}
switch FN[0] {
case 'f', 'F':
parseIntervalFail(interval, FN)
case 's', 'S':
parseIntervalSuccess(interval, FN)
default:
FN = "s=" + FN
parseIntervalSuccess(interval, FN)
}
}
interval.reset()
result = append(result, interval)
}
return result
}
func parseRandLR(lrvalue string) randLR {
vlen := len(lrvalue)
lastchar := lrvalue[vlen-1]
lr := strings.Split(lrvalue, "-")
switch len(lr) {
case 1:
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[0], lastchar)}
return lr
case 2:
lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[1], lastchar)}
return lr
default:
panic("lr is error")
}
}
// intervalPriorityListISecond 获取优先链表比较的值
func intervalPriorityListISecond(planlist *plist.PriorityList, count int) int {
if planlist.Size() > 0 {
node := new(NodeCount)
node.SetValue(count)
iwantNode := planlist.GetCompare(node)
if iwantNode != nil {
wantNode := iwantNode.(*NodeCount)
lr := wantNode.randLR
return randomdata.Number(lr.left, lr.right+1)
}
}
return -1
}
func getInt(v string) int {
vint, err := strconv.Atoi(v)
if err != nil {
panic(err)
}
return vint
}
func parseTimeValue(v string, lastchar byte) int {
vlen := len(v)
switch lastchar {
case 's':
return getInt(v[:vlen-1])
case 'm':
return getInt(v[:vlen-1]) * 60
case 'h':
return getInt(v[:vlen-1]) * 3600
case 'd':
return getInt(v[:vlen-1]) * 3600 * 24
default:
return getInt(v)
}
}

View File

@ -123,7 +123,7 @@ func (ty *trieYear) GetPlanTime(cron *Crontab, aftertime time.Time, count uint)
for j := 1; j <= 31; j++ { for j := 1; j <= 31; j++ {
if nmonth == i { if nmonth == i {
if j < nday { // 获取当天的计划表 if j < nday {
continue continue
} }
} }
@ -132,7 +132,7 @@ func (ty *trieYear) GetPlanTime(cron *Crontab, aftertime time.Time, count uint)
if day != nil { if day != nil {
if day.IsClear { if day.IsClear {
insertHour(cron, day) // 生成小时的计划表 insertHour(cron, day)
} }
for k := 0; k <= 23; k++ { for k := 0; k <= 23; k++ {
@ -144,7 +144,7 @@ func (ty *trieYear) GetPlanTime(cron *Crontab, aftertime time.Time, count uint)
} }
hour := day.Hour[k] hour := day.Hour[k]
// 遍历24小时 生成需要的计划表
if hour != nil { if hour != nil {
for n := 0; n <= 59; n++ { for n := 0; n <= 59; n++ {
@ -159,7 +159,7 @@ func (ty *trieYear) GetPlanTime(cron *Crontab, aftertime time.Time, count uint)
curTime := time.Date(ty.Year, time.Month(i), j, k, n, 0, 0, time.Local) curTime := time.Date(ty.Year, time.Month(i), j, k, n, 0, 0, time.Local)
result = append(result, curTime) result = append(result, curTime)
count-- // 统计完当前需要的计划任务后就结束 count--
if count <= 0 { if count <= 0 {
ty.clearHour() ty.clearHour()
return result return result
@ -168,8 +168,8 @@ func (ty *trieYear) GetPlanTime(cron *Crontab, aftertime time.Time, count uint)
} }
} }
} }
} }
} }
} }

View File

@ -1,107 +0,0 @@
package crontab
import (
"errors"
"fmt"
"strconv"
"strings"
)
type timePointer struct {
left, right int
leftlimit, rightlimit int
per int
isAll bool
}
func (tp *timePointer) String() string {
return fmt.Sprintf("left: %d, right: %d, leftlimit: %d, rightlimit: %d, per: %d", tp.left, tp.right, tp.leftlimit, tp.rightlimit, tp.per)
}
func createTimePointer(min string, llimit, rlimit int, fixedLeftRight bool) []timePointer {
var result []timePointer
exelist := strings.Split(min, ",")
for _, exe := range exelist {
tp := timePointer{}
takeper := strings.Split(exe, "/") // per
var rangevalue, per string
if len(takeper) == 1 {
rangevalue = exe
per = "1"
} else {
rangevalue = takeper[0]
per = takeper[1]
}
// takeRange
be := strings.Split(rangevalue, "-")
var left, rigth string
switch len(be) {
case 1:
left = be[0]
rigth = be[0]
case 2:
left = be[0]
rigth = be[1]
default:
panic(errors.New("range value is > 2"))
}
if left == "*" {
tp.left = llimit
} else {
ileft, err := strconv.Atoi(strings.Replace(left, "^", "-", -1))
if err != nil {
panic(err)
}
tp.left = ileft
}
if rigth == "*" {
tp.right = rlimit
} else {
iright, err := strconv.Atoi(strings.Replace(rigth, "^", "-", -1))
if err != nil {
panic(err)
}
tp.right = iright
}
iper, err := strconv.Atoi(per)
if err != nil {
panic(err)
}
tp.per = iper
tp.leftlimit = llimit
tp.rightlimit = rlimit
// 修正左值
leftfixed := tp.left
if leftfixed < 0 {
leftfixed += tp.rightlimit + 1
if fixedLeftRight {
tp.left = leftfixed
}
}
rightfixed := tp.right
if rightfixed < 0 {
rightfixed += tp.rightlimit + 1
if fixedLeftRight {
tp.right = rightfixed
}
}
// 全部符合 当左等于左 且 右等于右最大 并且 per == 1
if leftfixed == tp.leftlimit && rightfixed == tp.rightlimit && tp.per == 1 {
tp.isAll = true
}
result = append(result, tp)
}
return result
}