Cron 表达式的正则表达式





0/5 (0投票)
可用于解析 Cron 表达式的正则表达式
引言
Cron 是类 Unix 系统中的一种基于时间的作业调度程序。它根据 crontab 文件中的规范来执行作业,该文件使用 Unix 中的 crontab 命令进行编辑。
该文件的每一行代表运行特定命令的时间计划。cron 表达式的 POSIX 标准版本分别匹配分钟、小时、月份中的日期、月份和星期几。还有扩展版本可以定义秒,并使用一些特殊字符和形式来实现更具扩展性的调度。
本文档解释了 cron 表达式的 POSIX 版本和扩展版本的完整正则表达式。它可用于轻松解析支持正则表达式的任何编程语言中的 cron 表达式。
有关 cron 的更多信息
Using the Code
POSIX 版本
^(?#minute)(\*|(?:[0-9]|(?:[1-5][0-9]))(?:(?:\-[0-9]|\-(?:[1-5][0-9]))?|
(?:\,(?:[0-9]|(?:[1-5][0-9])))*)) (?#hour)(\*|(?:[0-9]|1[0-9]|2[0-3])
(?:(?:\-(?:[0-9]|1[0-9]|2[0-3]))?|(?:\,(?:[0-9]|1[0-9]|2[0-3]))*))
(?#day_of_month)(\*|(?:[1-9]|(?:[12][0-9])|3[01])(?:(?:\-(?:[1-9]|
(?:[12][0-9])|3[01]))?|(?:\,(?:[1-9]|(?:[12][0-9])|3[01]))*)) (?#month)(\*|
(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:\-(?:[1-9]|
1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?|(?:\,(?:[1-9]|1[012]|
JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))*)) (?#day_of_week)(\*|
(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT)(?:(?:\-(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))?|
(?:\,(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))*))$
cron 表达式的 POSIX 版本如下所示
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │ 7 is also Sunday on some systems)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * <command to execute>
首先指定分钟,然后是小时、月份中的日期,依此类推。POSIX 版本允许每个字段中的多个值用逗号 (,) 分隔,或者表示为两个值之间的连字符 (-) 表示的范围。月份可以用数字 (1-12) 或 3 个字符的字符串 (JAN-DEC) 表示。星期几可以用数字 (0-6) 或 3 个字符的字符串 (SUN-SAT) 表示。
"分钟" 表达式
(?#minute)(\*|(?:[0-9]|(?:[1-5][0-9]))(?:(?:\-[0-9]|\-(?:[1-5][0-9]))?| (?:\,(?:[0-9]|(?:[1-5][0-9])))*))
(?#minute)
=> 注释\*
=> 字符 * 字面量 (任何分钟)(?:)
=> 非捕获组(?:[0-9]|(?:[1-5][0-9]))
=> 0-59(?:\-[0-9]|\-(?:[1-5][0-9]))?
=> 可能的连字符,后面跟着 0 到 59 之间的数字(?:\,(?:[0-9]|(?:[1-5][0-9])))*
=> 可能的无限次逗号,后面跟着 0 到 59 之间的数字
"小时" 表达式
(?#hour)(\*|(?:[0-9]|1[0-9]|2[0-3])(?:(?:\-(?:[0-9]|1[0-9]|2[0-3]))?| (?:\,(?:[0-9]|1[0-9]|2[0-3]))*))
(?#hour)
=> 注释\*
=> 字符 * 字面量 (任何小时)(?:)
=> 非捕获组(?:[0-9]|1[0-9]|2[0-3])
=> 0-23(?:\-(?:[0-9]|1[0-9]|2[0-3]))?
=> 可能的连字符,后面跟着 0 到 23 之间的数字(?:\,(?:[0-9]|1[0-9]|2[0-3]))*
=> 可能的无限次逗号,后面跟着 0 到 23 之间的数字
"月份中的日期" 表达式
(?#day_of_month)(\*|(?:[1-9]|(?:[12][0-9])|3[01])(?:(?:\-(?:[1-9]| (?:[12][0-9])|3[01]))?|(?:\,(?:[1-9]|(?:[12][0-9])|3[01]))*))
(?#day_of_month)
=> 注释\*
=> 字符 * 字面量 (月份中的任何日期)(?:)
=> 非捕获组(?:[1-9]|(?:[12][0-9])|3[01])
=> 1-31(?:\-(?:[1-9]|(?:[12][0-9])|3[01]))?
=> 可能的连字符,后面跟着 1 到 31 之间的数字(?:\,(?:[1-9]|(?:[12][0-9])|3[01]))*
=> 可能的无限次逗号,后面跟着 1 到 31 之间的数字
"月份" 表达式
(?#month)(\*|(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)
(?:(?:\-(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?|
(?:\,(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))*))
(?#month)
=> 注释\*
=> 字符 * 字面量 (月份中的任何日期)(?:)
=> 非捕获组(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)
=> 1-12 或 JAN-DEC(?:\-(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?
=> 可能的连字符,后面跟着 1 到 12 之间的数字或 JAN - DEC 字符串(?:\,(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))*
=> 可能的无限次逗号,后面跟着 1 到 12 之间的数字或 JAN - DEC 字符串
"星期几" 表达式
(?#day_of_week)(\*|(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT)
(?:(?:\-(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))?|(?:\,(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))*))
(?#day_of_week)
=> 注释\*
=> 字符 * 字面量 (月份中的任何日期)(?:)
=> 非捕获组(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT)
=> 0-6 或 SUN-SAT(?:\-(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))?
=> 可能的连字符,后面跟着 0 到 6 之间的数字或 SUN - SAT 字符串(?:\,(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))*
=> 可能的无限次逗号,后面跟着 0 到 6 之间的数字或 SUN - SAT 字符串
扩展版本
^(?#second)(\*|(?:\*|(?:[0-9]|(?:[1-5][0-9])))\/(?:[0-9]|(?:[1-5][0-9]))|
(?:[0-9]|(?:[1-5][0-9]))(?:(?:\-[0-9]|\-(?:[1-5][0-9]))?|(?:\,(?:[0-9]|(?:[1-5][0-9])))*))
(?#minute)(\*|(?:\*|(?:[0-9]|(?:[1-5][0-9])))\/(?:[0-9]|(?:[1-5][0-9]))|(?:[0-9]|
(?:[1-5][0-9]))(?:(?:\-[0-9]|\-(?:[1-5][0-9]))?|(?:\,(?:[0-9]|(?:[1-5][0-9])))*))
(?#hour)(\*|(?:\*|(?:\*|(?:[0-9]|1[0-9]|2[0-3])))\/(?:[0-9]|1[0-9]|2[0-3])|
(?:[0-9]|1[0-9]|2[0-3])(?:(?:\-(?:[0-9]|1[0-9]|2[0-3]))?|(?:\,(?:[0-9]|1[0-9]|2[0-3]))*))
(?#day_of_month)(\*|\?|L(?:W|\-(?:[1-9]|(?:[12][0-9])|3[01]))?|(?:[1-9]|(?:[12][0-9])|
3[01])(?:W|\/(?:[1-9]|(?:[12][0-9])|3[01]))?|(?:[1-9]|(?:[12][0-9])|3[01])
(?:(?:\-(?:[1-9]|(?:[12][0-9])|3[01]))?|(?:\,(?:[1-9]|(?:[12][0-9])|3[01]))*))
(?#month)(\*|(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)
(?:(?:\-(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?|
(?:\,(?:[1-9]|1[012]|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))*))
(?#day_of_week)(\*|\?|[0-6](?:L|\#[1-5])?|(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT)
(?:(?:\-(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))?|(?:\,(?:[0-6]|SUN|MON|TUE|WED|THU|FRI|SAT))*))
(?#year)(\*|(?:[1-9][0-9]{3})(?:(?:\-[1-9][0-9]{3})?|(?:\,[1-9][0-9]{3})*))$
扩展版本允许在第一个字段中额外指定秒,在最后一个字段中指定年。
此外,它还允许一些额外的选项
\/
=> 字符 / 字面量 - 可与秒、分钟和小时的范围结合使用,以指定步长值。例如,分钟的 10/5 意味着从第 5 分钟开始每隔 5 分钟执行一次;这与 POSIX 的较长表达式 5,10,15,20,25,30,35,40,45,50,55 相同;*/5 意味着每 5 分钟执行一次(与 0/5 相同)L
=> 与星期几一起使用,表示月份中的最后一天。例如,5L 表示月份中的最后一个星期五;或者与月份中的日期一起使用,表示月份的最后一天;可以选择使用减号来指定相对于最后一天的日期,例如 L-5 表示月份最后一天之前的第 5 天W
=> 与月份中的日期一起使用,表示最接近的工作日。例如,15W 表示最接近月中 15 日的工作日?
=> 在某些实现中,此字符用于省略月份中的日期或星期几(它们不能同时使用)#
=> 与星期几一起使用,表示月份中的第几周(1-5)。例如,5#3 表示月份中的第三个星期五;只能与数字表示法一起使用
备注
需要注意的是,这些正则表达式仅解析和捕获 cron 表达式的不同字段。一些逻辑上不允许的组合仍然可能通过,它们需要在解析正则表达式后在代码中处理。例如
0 0 0 5 * 5 *
- 在大多数实现中,不允许同时使用月份中的日期和星期几。因此,正确的用法是将字符 ? 放在月份中的日期或星期几字段(但不能两者都放在);在 POSIX 格式中,如果其中一个字段是特定值(有限制),另一个字段需要是 *;如果两者都有限制,它们都需要匹配今天,否则表达式是错误的。0 0 0 31 2 ? *
- 此表达式表示在 31.02 日期运行,当然这个日期不存在0 55-33 * * ? *
- 指定在 55 分钟到 33 分钟之间运行;范围的右侧值应始终大于左侧值0 0 0 ? FEB 4#5 2021
- 这表示 2021 年 2 月第 5 个星期三的 00:00:00 - 2021 年 2 月没有 5 周,因此此表达式意味着该命令将永远不会运行0 */26 * ? * * *
- 通常,只能使用能被最大数整除的步长;在这种情况下,我们想每 26 分钟运行一次命令,这将是合法的,但会在时间单位的末尾留下一个不均匀的短周期 - 换句话说,它不会每 26 分钟运行一次,而是会在 0:26、0:52、1:26、1:52 等时间运行。0 0 0 ? * * 2222
- 正则表达式允许 1000-9999 年,但大多数 cron 实现只允许 1970-2099 年
历史
- 2021 年 4 月 11 日:初始版本