package startimer import ( "errors" "strconv" "strings" "sync" "time" ) var rpmonths = map[string]int{ "JAN": 1, "FEB": 2, "MAR": 3, "APR": 4, "MAY": 5, "JUN": 6, "JUL": 7, "AUG": 8, "SEP": 9, "OCT": 10, "NOV": 11, "DEC": 12, } var rpweekdays = map[string]int{ "SUN": 0, "MON": 1, "TUE": 2, "WED": 3, "THU": 4, "FRI": 5, "SAT": 6, } func NewTimerWithCron(cron ...string) (StarTimer, error) { tmr := StarTimer{ base: time.Now(), nextDate: time.Time{}, mu: new(sync.RWMutex), } for _, c := range cron { c = "0 " + c rpt, err := parseCron(c) if err != nil { return tmr, err } tmr.repeat = append(tmr.repeat, rpt) } return tmr, nil } func NewTimerWithSecCron(cron ...string) (StarTimer, error) { tmr := StarTimer{ base: time.Now(), nextDate: time.Time{}, mu: new(sync.RWMutex), } for _, c := range cron { rpt, err := parseCron(c) if err != nil { return tmr, err } tmr.repeat = append(tmr.repeat, rpt) } return tmr, nil } func parseCron(cron string) (*Repeats, error) { { cron = strings.ToUpper(cron) for k, v := range rpmonths { cron = strings.ReplaceAll(cron, k, strconv.Itoa(v)) } for k, v := range rpweekdays { cron = strings.ReplaceAll(cron, k, strconv.Itoa(v)) } } for { oldLen := len(cron) cron = strings.ReplaceAll(strings.TrimSpace(cron), " ", " ") if len(cron) == oldLen { break } } ct := strings.Split(cron, " ") if len(ct) != 6 { return nil, errors.New("Invalid cron,argument not enough") } foundFirstAll := false var myMap = make(map[Unit]map[uint32]Repeat) for idx, c := range ct { if _, ok := myMap[Unit(idx)]; !ok { myMap[Unit(idx)] = make(map[uint32]Repeat) } var minVal, maxVal int switch Unit(idx) { case STAR_MINUTE, STAR_SECOND: minVal = 0 maxVal = 60 case STAR_HOUR: minVal = 0 maxVal = 24 case STAR_DAY: minVal = 1 maxVal = 32 case STAR_MONTH: minVal = 1 maxVal = 13 case STAR_WEEK: minVal = 0 maxVal = 7 } cdt := strings.Split(c, ",") for _, dtl := range cdt { dtl = strings.TrimSpace(dtl) if dtl == "*" { if !foundFirstAll { foundFirstAll = true if maxVal > 0 { for i := minVal; i < maxVal; i++ { val := uint32(i) myMap[Unit(idx)][val] = Repeat{ Unit: Unit(idx), Value: val, } } } } continue } if strings.Contains(dtl, "*/") { num, err := strconv.Atoi(strings.TrimPrefix(dtl, "*/")) if err != nil { return nil, err } for i := minVal; i < maxVal; i++ { val := i if Unit(idx) == STAR_DAY || Unit(idx) == STAR_MONTH { val-- } if val%num == 0 { myMap[Unit(idx)][uint32(val)] = Repeat{ Unit: Unit(idx), Value: uint32(i), } } } continue } if strings.Contains(dtl, "-") { numbers := strings.Split(dtl, "-") if len(numbers) != 2 { return nil, errors.New("Invalid Cron") } startNum, err := strconv.Atoi(numbers[0]) if err != nil { return nil, err } endNum, err := strconv.Atoi(numbers[1]) if err != nil { return nil, err } if startNum < minVal && endNum >= maxVal { return nil, errors.New("Invalid Cron") } for i := startNum; i <= endNum; i++ { myMap[Unit(idx)][uint32(i)] = Repeat{ Unit: Unit(idx), Value: uint32(i), } } continue } number, err := strconv.Atoi(dtl) if err != nil { return nil, err } myMap[Unit(idx)][uint32(number)] = Repeat{ Unit: Unit(idx), Value: uint32(number), } } } var repeat Repeats for _, v := range myMap { for _, rpt := range v { repeat.Repeat = append(repeat.Repeat, rpt) } } return &repeat, nil }