共计 3250 个字符,预计需要花费 9 分钟才能阅读完成。
初识 corn
corn 表达式是一个字符串,分为 6 或 7 个域,每个域都会代表一个含义。
语法格式
6 个域:second minute hour day month week
7 个域:second minute hour day month week year
由上可见,7 个域与 6 个域的语法只差了 year,一般情况下,我们使用 6 个域的结构。
corn 表达式结构
corn 从左到右(中间用空格隔开):秒 分 小时 月份中的日 月份 星期中的日期 年份
各个字段的含义
位置 | 时间域名 | 允许值 | 允许的特殊字符 |
---|---|---|---|
1 | 秒 | 0-59 | , - * / |
2 | 分 | 0-59 | , - * / |
3 | 小时 | 0-23 | , - * / |
4 | 日 | 1-31 | , - * ? / L W C |
5 | 月 | 0-12 | , - * / |
6 | 星期 | 1-7 | , - * ? / L C # |
7 | 年(可选) | 1970-2099 | , - * / |
代码示例
声明:本次的 cron 讲解结合了 springboot 框架。由于只是讲解 cron 表达式,所以就不在介绍 springboot 中如何使用 @Scheduled 注解的相关配置了
秒的位置允许值为 0-59,如果写 60,将会报错
/* 以下代码在 springboot 启动时会抛出异常 */
@Scheduled(cron="60 * * * * * ?")
public void executeSchedule() {//TODO}
异常信息:Range exceeds maximum (60) |’60’ in expression “60 ?”
意思就是说,表达式中的 60 已经超出了最大范围。
秒
/* 每分钟的第 8 秒执行 */
@Scheduled(cron="8 * * * * ?")
public void executeSchedule() {//TODO}
以上表达式含义为:每分钟的第 8 秒执行 executeSchedule 方法。秒后面的时间域是分钟,*(星号)表示 每...
,这里表示 每分钟
。 注意: 是每分钟的第 8 秒,不是每隔 8 秒
秒 + 分
/* 每小时的 20 分 8 秒时执行 */
@Scheduled(cron="8 20 * * * ?")
public void executeSchedule() {//TODO}
以上表达式含义为:每小时的第 20 分,第 8 秒执行 executeSchedule 方法。分钟后的时间域是小时,由于是 *(星号),所以代表每小时。
秒 + 分 + 小时
/* 每天中午 12 点 20 分 8 秒执行 */
@Scheduled(cron="8 20 12 * * ?")
public void executeSchedule() {//TODO}
以上表达式含义为:每天中午 12 点 20 分 8 秒执行 executeSchedule 方法。小时后的时间域是天,*(星号)表示每天。注意:时间的范围是 0-23,即 24 时制。所以 12 表示中午 12 点,如果表示午夜 12 点,表达式应该为:cron=8 20 0 * * ?
秒 + 分 + 小时 + 日
/* 每月 31 号中午 12 点 20 分 8 秒执行 */
@Scheduled(cron="8 20 12 31 * ?")
public void executeSchedule() {//TODO}
以上表达式含义为:每个月的 31 号中午 12 点 20 分 8 秒执行 executeSchedule 方法。注意:
1、如果某个月份中不包含 31 号,则不执行
2、如果表达式为 cron="8 20 12 31 4 ?",启动项目时将会报错:4 月份没有 31 号,此表达式永远都不会执行,所以月份与日要配合使用
秒 + 分 + 小时 + 日 + 月
/* 4 月 30 号中午 12 点 20 分 8 秒执行 */
@Scheduled(cron="8 20 12 30 4 ?")
public void executeSchedule() {//TODO}
以上表达式含义为:4 月 30 号中午 12 点 20 分 8 秒执行 executeSchedule 方法。
秒 + 分 + 小时 + 日 + 月 + 星期
星期域具有特殊性,它由 1-7 组成,1 表示星期日(一周的开始),7 表示星期六(一周的最后一天);星期的定义与日和月同时表示,有可能会有冲突。
例子:cron="8 20 12 30 4 3"
以上表达式,看着好像是 星期二 4 月 30 号 中午 12 点 20 分 8 秒
这个意思,但实际上并不一定,原因很简单,你怎么就知道 4 月 30 号正好是星期二呢?所以这样定义表达式是存在问题的,也就是说 星期
和日
在某种程度上是有 冲突
的。所以一般要在 星期
和日
之间作出 取舍
。即 定义了星期,就不定义日;定义了日,就不定义星期。不需要定义的时候使用
? 占位,舍弃谁谁就用
? 代替
。
例子:cron="8 20 12 ? 4 2"
以上表达式含义为:4 月份的每个星期 1 的中午 12 点 20 分 8 秒
特殊字符
- 星号(*):可用在所有时间域中,表示对应时间域的每一个时刻。例如,用于分钟域时,表示每分钟
表达式 | 含义 |
---|---|
cron=”8 20 12 * 4 ?” | 4 月份每天中午 12 点 20 分 8 秒 |
cron=”8 * 18 * 4 ?” | 4 月份每天下午 6 点的每分钟的第 8 秒 |
- 问号(?):该字符只在
星期域
和日期域
中使用,它通常指定为无意义的值
,相当于占位符 - 减号(-):表达一个范围(range),如,用在
小时域
,16-20
表示从下午 4 点到晚上 8 点
,即 16,17,18,19,20
表达式 | 含义 |
---|---|
cron=”8 20 7-9 * 2 ?” | 2 月份每天 7 点,8 点,9 点的 20 分 8 秒 |
- 逗号(,):表示列表值,如,用在
星期域
,“1,3,5”,表示星期日,星期二,星期四
表达式 | 含义 |
---|---|
cron=”2,59 20 3 * 2 ?” | 2 月份每天凌晨 3 点 20 分的第 2 秒和第 59 秒 |
- 正斜杠(/):表达一个等步长序列,x 为起始值,y 为增量步长值。如在
分钟域
中使用0/25
,表示 0,25,50 秒。也可以使用*/y
,同等于0/y
表达式 | 含义 |
---|---|
cron=”2,59 0/25 3 * 2 ?” | 2 月份每天凌晨 3 点的第 2 秒和第 59 秒,3 点 25(0+25)分的第 2 秒和第 59 秒,3 点 50(25+25)分的第 2 秒和第 59 秒 |
cron=”* 15/20 14 * 2 ?” | 2 月份每天下午 2 点 15 分的每一秒,3 点 35(15+20)分每一秒,3 点 55(35+20)分的每一秒 |
- L:该字符只在
日期域
和星期域
中使用,代表Last
的意思,但它在两个域中的意义不同。
域 | 含义 |
---|---|
日期 | 当前月份的最后一天,如 1 月 31 日,非闰年 2 月 28 日 |
星期 | 表示星期六,同等于 7。但如果出现在星期域中,而且在前面还有一个数值 X,则表示“这个月的最后 X 天”,例如:5L 表示该月的最后星期四 |
- W:该字符只能出现在
日期域
中, 是对前导日期的修饰,表示离该日期最近的工作日。例如12W
表示离该月12 号
最近的工作日
,如果该月的12 号
是星期六
,则匹配11 号星期五
;如果12 号
是星期日
,则匹配13 号星期一
;如果12 号
是星期三
,那结果就是星期三
。但必须注意关联的匹配日期不能够跨月
,如指定1W
, 如果1 号
是星期六
,那么结果就是3 号星期一
,而非上个月的最后的那天。W
只能指定单一日期,而不能指定日期范围。 - LW 组合:在日期域可以使用
LW
, 含义是当月的最后一个工作日
- 井号(#):该字符只能在
星期域
中使用,表示当月某个工作日
。
表达式 | 含义 |
---|---|
6#3 | 当月的第三个星期五(6 表示星期五,#3 表示当前的第三个) |
4#5 | 当月的第五个星期三。假设当月没有第五个星期三,则忽略不触发 |
- C: 该字符只在
日期域
和星期域
中使用,代表Calendar
的意思。意义为计划所关联的日期
。如果日期没有被关联,则相当于日历中的所有日期。如。5C
在日期域
中就相当于日历 5 日以后的第一天
,1C
在星期域
中相当于星期日后的第一天
。
cron 表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
cron 表达式在线生成器:http://cron.qqe2.com/
小例子
表达式 | 含义 |
---|---|
@Scheduled(cron=”0 0 1 1 1 ?”) | 每年 1 月 1 号的凌晨 1 点执行一次 |
@Scheduled(cron=”0 0 1 1 1,6 ?”) | 1 月和 6 月的 1 号的凌晨 1 点执行一次 |
@Scheduled(cron=”0 0 1 1 1,4,7,10 ?”) | 每个季度的第 1 个月的 1 号的凌晨 1 点执行一次 |
@Scheduled(cron=”0 0 1 1 * ?”) | 每月 1 号凌晨 1 点执行一次 |
@Scheduled(cron=”0 0 1 *”) | 每天凌晨 1 点执行一次 |