初识 cron
cron 表达式是一个字符串,分为 6 或 7 个域,每个域都会代表一个含义。
语法格式
6 个域:second minute hour day month week
7 个域:second minute hour day month week year
由上可见,7 个域与 6 个域的语法只差了 year,一般情况下,我们使用 6 个域的结构。
cron表达式结构
cron 从左到右(中间用空格隔开):秒 分 小时 月份中的日 月份 星期中的日期 年份
各个字段的含义
位置 | 时间域名 | 允许值 | 允许的特殊字符 |
---|---|---|---|
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点执行一次 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。