基于linux的Cron表达式时间触发运用

本项目中并不是运用linux系统自带的cron触发功能,而是自己实现cron表达式时间触发机制,代码是对busybox中的源码进行裁剪:

一、Cron表达式基础

1、cron表达式

顺序

分钟

小时

日期

月份

星期

年(可选)

取值

0-59

0-59

0-23

1-30(31)

1-12

1-7

 

允许特殊字符

, - * /

, - * /

, - * /

, - * / ? L W C

, - * /

, - * / L # C

1970-2099 , - * /

2、每个字段含义

*:代表所有可能的值
-:指定范围
,:列出枚举  例如在分钟里,"5,15"表示5分钟和20分钟触发
/:指定增量  例如在分钟里,"3/15"表示从3分钟开始,没隔15分钟执行一次
?:表示没有具体的值,使用?要注意冲突
L:表示last,例如星期中表示7或SAT,月份中表示最后一天31或30,6L表示这个月倒数第6天,FRIL表示这个月的最后一个星期五
W:只能用在月份中,表示最接近指定天的工作日
#:只能用在星期中,表示这个月的第几个周几,例如6#3表示这个月的第3个周五

3、示例

0 * * * * ? 每1分钟触发一次
0 0 * * * ? 每天每1小时触发一次
0 0 10 * * ? 每天10点触发一次
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
0 30 9 1 * ? 每月1号上午9点半
0 15 10 15 * ? 每月15日上午10:15触发
*/5 * * * * ? 每隔5秒执行一次
0 */1 * * * ? 每隔1分钟执行一次
0 0 5-15 * * ? 每天5-15点整点触发
0 0/3 * * * ? 每三分钟触发一次
0 0 0 1 * ?  每月1号凌晨执行一次

二、Cron表达式时间触发代码运用

本项目中并不是运用linux系统自带的cron触发功能,而是自己实现cron表达式触发机制,代码是对busybox中的源码进行裁剪:

功能:到某一个时间点触发一个时间:

直接上代码:

从linux系统 busybox源码中裁剪出的代码:

typedef struct CronLine
{
    /* ordered by size, not in natural order. makes code smaller: */
    char cl_Dow[7];         /* 0-6, beginning sunday                */
    char cl_Mons[13];       /* 1-12                                 */
    char cl_Hrs[24];        /* 0-23                                 */
    char cl_Days[32];       /* 1-31                                 */
    char cl_Mins[60];       /* 0-59                                 */
} CronLine;


static void ParseField(char *ary, int modvalue, char *ptr)
{
    char *base = ptr;
    int n1 = -1;
    int n2 = -1;

    while (1)
    {
        int skip = 0;
        if (*ptr == '*')
        {
            n1 = 0;   /* everything will be filled */
            n2 = modvalue - 1;
            skip = 1;
            ++ptr;
        }
        else if (isdigit(*ptr))   //是否为十进制数字字符
        {
            char *endp;
            if (n1 < 0)
            {
                n1 = strtol(ptr, &endp, 10);  //将字符串转换为长整型数(long)
            }
            else
            {
                n2 = strtol(ptr, &endp, 10);
            }
            ptr = endp; /* gcc likes temp var for &endp */
            skip = 1;
        }

        /* handle optional range '-' */
        if (skip == 0)
        {
            goto err;
        }
        if (*ptr == '-' && n2 < 0)
        {
            ++ptr;
            continue;
        }

        /*
         * collapse single-value ranges, handle skipmark, and fill
         * in the character array appropriately.
         */
        if (n2 < 0)
        {
            n2 = n1;
        }
        if (*ptr == '/')
        {
            char *endp;
            skip = strtol(ptr + 1, &endp, 10);
            ptr = endp; /* gcc likes temp var for &endp */
        }

        /*
         * fill array, using a failsafe is the easiest way to prevent
         * an endless loop
         */
        {
            int s0 = 1;
            int failsafe = 1024;

            --n1;
            do
            {
                n1 = (n1 + 1) % modvalue;

                if (--s0 == 0)
                {
                    ary[n1 % modvalue] = 1;
                    s0 = skip;
                }
                if (--failsafe == 0)
                {
                    goto err;
                }
            }
            while (n1 != n2);
        }
        if (*ptr != ',')
        {
            break;
        }
        ++ptr;
        n1 = -1;
        n2 = -1;
    }
    if (*ptr)
    {
err:
        PRINT_LOG(" parse error at %s\n", base);
        return;
    }
}
static void FixDayDow(CronLine *line)
{
    unsigned i;
    int weekUsed = 0;
    int daysUsed = 0;

    for (i = 0; i < ARRAY_SIZE(line->cl_Dow); ++i)
    {
        if (line->cl_Dow[i] == 0)
        {
            weekUsed = 1;
            break;
        }
    }
    for (i = 0; i < ARRAY_SIZE(line->cl_Days); ++i)
    {
        if (line->cl_Days[i] == 0)
        {
            daysUsed = 1;
            break;
        }
    }
    if (weekUsed != daysUsed)
    {
        if (weekUsed)
            memset(line->cl_Days, 0, sizeof(line->cl_Days));
        else /* daysUsed */
            memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
    }
}

static void  Sync_CronTime(char *CronStr, UINT strLen, CronLine *cronLine)
{
    char *tokens[5];
    BYTE i;
    char CronStrTemp[48];
    char *start;
    char *pos;
    memset(CronStrTemp, 0, sizeof(CronStrTemp));
    memcpy(CronStrTemp, CronStr, strLen);
    start = CronStrTemp;
    for(i = 0; i < 4; i++)
    {
        pos = strchr(start, ' ');
        if(pos == NULL)
        {
            return;
        }
        tokens[i] = start;
        tokens[i][pos-start] = '\0';
        start = pos + 1;
    }
    tokens[4] = start;
    memset((char *)cronLine, 0, sizeof(CronLine));
    ParseField(cronLine->cl_Mins, 60, tokens[0]);
    ParseField(cronLine->cl_Hrs, 24, tokens[1]);
    ParseField(cronLine->cl_Days, 32, tokens[2]);
    ParseField(cronLine->cl_Mons, 13, tokens[3]);
    ParseField(cronLine->cl_Dow, 7, tokens[4]);
    FixDayDow(cronLine);

}

应用代码:应用代码:

//定时线程,不同时间点触发运行任务策略
UINT RTC_Strategy_TimePointSwitch(void)
{
    BYTE iLoop, cronLoop;
    CronLine cronLine;
    Strategy *pStrategy;
    ScaleTime pTime;
    INT CurStrategyID,CurCronID;
    UINT Ret = ERR_NO_DATA;
    Sys_GetTime((ScaleTime *)&pTime);  //获取当前时间
    if((pTime.Hour >= 18) &&( pTime.Hour < 20))  //时间在18-20点,运行18点的任务
    {
        pTime.Hour = 18;
    }
    else if((pTime.Hour >= 20) &&( pTime.Hour < 22))  //时间在20-22点,运行20点的任务
    {
        pTime.Hour = 20;
    }
    else if((pTime.Hour >= 22) &&( pTime.Hour<=23))//时间在22-23点,运行22点的任务
    {
        pTime.Hour = 22;
    }
    else if((pTime.Hour >= 0) &&( pTime.Hour< 2)) //时间在0-2点,运行0点的任务
    {
        pTime.Hour = 0;
    }
    for(iLoop = 0; iLoop < MAX_STRATEGY_NUM; iLoop++)  //任务编号越大,优先级越高
    {
        if(STG_Open(iLoop, CRON_O_RDONLY) == NULL)
        {
            continue;
        }
        pStrategy  = STG_Read(iLoop);
        if(pStrategy == NULL)
        {
            continue;
        }
        for(cronLoop = 0; cronLoop < pStrategy->CronSum; cronLoop++) //多个时间点
        {
            Sync_CronTime((char *)pStrategy->CronData[cronLoop].CronStr, pStrategy->CronData[cronLoop].Cron_Strlen, (CronLine *)&cronLine);

            if(cronLine.cl_Mons[pTime.Mon] && cronLine.cl_Days[pTime.Day] && cronLine.cl_Hrs[pTime.Hour]) //&&cronLine.cl_Mins[pTime.Min]
            {
                CurStrategyID = iLoop;
                CurCronID = cronLoop;
                Ret = ERR_NULL;
                break;
            }
        }
    }
    if( Ret == ERR_NULL)
    {
        if((g_CurStrategyID == CurStrategyID) && (g_CurCronID == CurCronID))
        {
            Ret = ERR_NO_DATA;
        }
        else
        {
            g_CurStrategyID = CurStrategyID;
            g_CurCronID = CurCronID;
        }
    }
    return Ret;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
cron表达式是一种用于指定定时任务执行时间的语法,通常用于Linux系统中的计划任务。它由5个或6个空格分隔的字段组成,每个字段表示定时任务执行的不同时间维度,如分钟、小时、日、月、星期。以下是一个标准的cron表达式格式: ``` * * * * * - - - - - | | | | | | | | | +----- day of the week (0 - 6) (Sunday=0) | | | +---------- month (1 - 12) | | +--------------- day of the month (1 - 31) | +-------------------- hour (0 - 23) +------------------------- min (0 - 59) ``` 每个字段的取值范围如下: - 分钟:0~59 - 小时:0~23 - 日:1~31 - 月:1~12 - 星期:0~6,0表示周日,1~6表示周一到周六 在每个字段中,可以使用以下特殊字符: - `*`:表示匹配任意值,例如`*`在分钟字段中表示每分钟都触发 - `,`:表示枚举值,例如`1,3,5`在星期字段中表示周一、周三和周五都触发 - `-`:表示范围,例如`10-20`在小时字段中表示从10点到20点都触发 - `/`:表示步长,例如`*/5`在分钟字段中表示每隔5分钟触发一次 - `?`:在日和星期中用于占位,代表任意值,例如`0 0 ? * *`表示每天0点0分执行 此外,cron表达式还支持一些特殊关键字: - `@yearly`:表示每年执行一次,等同于`0 0 1 1 *` - `@monthly`:表示每月执行一次,等同于`0 0 1 * *` - `@weekly`:表示每周执行一次,等同于`0 0 * * 0` - `@daily`或`@midnight`:表示每天执行一次,等同于`0 0 * * *` - `@hourly`:表示每小时执行一次,等同于`0 * * * *` 这些特殊关键字可以简化cron表达式的编写,但不是所有的cron实现都支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺水城子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值