管理人新建任务,并指定该任务的执行crond规则
通过Go程序启动一个每秒执行的定时器,监听创建好的任务列表,通过当前时间进行一定的转换,判断转换后的数据是否落在对应crond范围内
以下代码主要实现,当前时间是否满足cron表达的要求
package cronpackage
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
"time"
)
type CheckCrontab struct{}
func NewCheckCrontab() *CheckCrontab {
return &CheckCrontab{}
}
/**
* 此类仅用于判断给定的时间是否符合时间规则,如果符合则返回true其它业务逻辑自行处理
* 使用说明
* format = '* * * * * ';
* 本类模仿crond的规则分5个部分分别是分、时、日期、月、周(的第几天)
* 每部分可单独设置为一个数,如:1 * * * * ,当分为1时 true
* 可以使用 '/' 来分开设置重复规则,如: * / 1 * * * * , 每分钟 ; * / 2 * * * * 每两分钟(注意每部分之间是没有空格的,这里是PHP的注释部分)
* 可以设置区间: 4-20/2 * * * * , 当分为4 - 20之间,并且为2的倍数时
* 可以为集合: * /5,8,10 * * * * , 当分为5,8,10时返回true,其它部分同理。
* '0 23 * * 6' 每周六的11点
* '* 23-7/1 * * * ' 每天晚上23-7点,每隔一小时
*/
func (c *CheckCrontab) Handle(ctx context.Context) {
currentTime := time.Now()
_, err := NewCheckCrontab().Check(currentTime, "'* * * * *")
fmt.Println(err)
}
func (c *CheckCrontab) Check(t time.Time, strCron string) (bool, error) {
formatTime := strings.Split(t.Format("04 15 02 01"), " ") //分钟、小时、日、月
formatTime = append(formatTime, strconv.Itoa(int(time.Now().Weekday()))) //星期几
formatCron, err := c.FormatCrontab(strCron)
if err != nil {
return false, err
}
defaultRes := false
for i, v := range formatTime {
vInt, err := strconv.Atoi(v)
if err != nil {
return false, err
}
if len(formatCron[i]) > 0 && !InArray(vInt, formatCron[i]) { //此处不满足则直接返回
return false, nil
}
defaultRes = true
}
return defaultRes, nil
}
func (c *CheckCrontab) FormatCrontab(strCron string) ([][]int, error) {
var arrCron [][]int
_, err := cron.ParseStandard(strCron) //校验表达式
if err != nil {
return arrCron, err
}
parts := strings.Split(strCron, " ")
part0, _ := c.ParseCronPart(parts[0], 0, 59)
arrCron = append(arrCron, part0) //分
part1, _ := c.ParseCronPart(parts[1], 0, 59)
arrCron = append(arrCron, part1) //时
part2, _ := c.ParseCronPart(parts[2], 1, 31)
arrCron = append(arrCron, part2) //日
part3, _ := c.ParseCronPart(parts[3], 1, 12)
arrCron = append(arrCron, part3) //月
part4, _ := c.ParseCronPart(parts[4], 0, 6)
arrCron = append(arrCron, part4) //周(0周日)
return arrCron, nil
}
// part 时间计划里的一个部分,被空格分隔后的一个部分
// fMin 此部分的最小取值
// fMax 此部分的最大取值
func (c *CheckCrontab) ParseCronPart(part string, fMin int, fMax int) ([]int, error) {
list := []int{}
//处理"," -- 列表
if strings.Contains(part, ",") {
arr := strings.Split(part, ",")
for _, v := range arr {
tmpList, _ := c.ParseCronPart(v, fMin, fMax)
list = append(list, tmpList...)
}
return list, nil
}
//处理"/" -- 间隔
tmp := strings.Split(part, "/")
part = tmp[0]
step := 1
if len(tmp) > 1 && tmp[1] != "" {
tmp1, _ := strconv.Atoi(tmp[1])
step = tmp1
}
//处理"-" -- 范围
min := 0
max := 0
if strings.Contains(part, "-") {
var err error
partArr := strings.Split(part, "-")
if len(partArr) != 2 {
return list, errors.New("Parameter exception when using '-' to set the range")
}
min, err = strconv.Atoi(partArr[0])
if err != nil {
return list, errors.New("The minimum value is not a number")
}
max, err = strconv.Atoi(partArr[1])
if err != nil {
return list, errors.New("The maximum value is not a number")
}
if min > max {
return list, errors.New("When using '-' to set the range, the left cannot be greater than the right")
}
} else if part == "*" {
min = fMin
max = fMax
} else { //数字
partNum, _ := strconv.Atoi(part)
min = partNum
max = partNum
}
//空数组表示可以任意值
if min == fMin && max == fMax && step == 1 {
return list, nil
}
//越界判断
if min < fMin || max > fMax {
return list, errors.New("The value is out of range. Should be: minutes 0-59, hours 0-59, days 1-31, months 1-12, weeks 0-6")
}
if max-min > step {
return c.rangeFunction(min, max, step), nil
}
return []int{min}, nil
}
func (c *CheckCrontab) rangeFunction(start, end, step int) []int {
var result []int
if step == 0 {
return result
}
for start != end {
result = append(result, start)
start += step
if start == end {
result = append(result, start)
break
}
if start > end {
break
}
}
return result
}
// 判断某一个值是否含在切片之中
func InArray(need interface{}, haystack interface{}) bool {
switch key := need.(type) {
case int:
for _, item := range haystack.([]int) {
if item == key {
return true
}
}
case string:
for _, item := range haystack.([]string) {
if item == key {
return true
}
}
case int64:
for _, item := range haystack.([]int64) {
if item == key {
return true
}
}
case float64:
for _, item := range haystack.([]float64) {
if item == key {
return true
}
}
default:
return false
}
return false
}
参考文档:https://blog.csdn.net/hotlinhao/article/details/79341443
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。