Keeper 中的 Cron 表达式
Cron 表达式是用于任务调度中表示时间计划的行业标准,几乎能够满足所有与时间有关的调度设置需求。如每天的凌晨
1
点执行或每小时执行一次等,都可以用 Cron 表达式来表示。Keeper 对标准的 Cron 表达式进行了一些扩展,以满足更多应用场景的需要。
标准的的 Cron 表达式一共
7
位,从左到右分别是:
秒 分钟 小时 天 月 星期 年
,每个时间位之间使用半角空格隔开。几个例子:
每天凌晨
02:30
分执行
0 30 2 * * ? *
每小时整点执行
0 0 * * * ? *
从
0
分开始每隔
5
分钟执行一次
0 0/5 * * * ? *
周一到周五每天中午12点执行
0 0 12 ? * MON-FRI *
仅工作日的
9
点到下午
18
点每小时的
15
分执行一次执行
0 15 * W * ? *
每周的第一个休息日
0
点执行
0 0 0 ? * FR *
每个时间位的取值、支持的符号和关键词如下:
秒
取值
0
到
59
,支持符号
*
,
-
/
。各个符号的意义见下面的介绍。
分钟
取值
0
到
59
,支持符号
*
,
-
/
小时
取值
0
到
23
,支持符号
*
,
-
/
天
取值
1
到
31
,支持符号
*
,
-
/
?
,支持关键字
F
、
L
、
W
、
R
、
FW
、
FR
、
LW
、
LR
。有的关键词是 Keeper 进行的扩展,各个关键词的介绍见下面的说明。
月
取值
1
到
12
,支持符号
*
,
-
/
,支持关键字
JAN
、
FEB
、
MAR
、
APR
、
MAY
、
JUN
、
JUL
、
AUG
、
SEP
、
OCT
、
NOV
、
DEC
,分别代表
1
到
12
月。
星期
取值
1
到
7
,分别代表周一到周日,与标准的 Cron 表达式不同(1 表示周日,2 表示周一,依次类推),支持符号
*
,
-
+
#
?
,支持关键字
MON
、
TUE
、
WED
、
THU
、
FRI
、
SAT
、
SUN
,分别对应周一到周日。也支持关键字
F
、
L
、
W
、
R
、
FW
、
FR
、
LW
、
LR
。
年
取值
1970
到
2100
,支持符号
*
,
-
/
特别注意,在 Keeper 中,秒位始终为
0
。有的应用场景中,Cron 表达式的位数不是
7
位,如
crontab
中会省略
秒
和
年
。Keeper 中支持
1
到
7
位的 Cron 表达式,见下面的说明。
在上面已经见到了好几个特殊符号,现将每个符号代表的意义说明如下:
*
表示
全部
,代表每次都执行,如在分钟位表示
0
到
59
每分钟都执行,年位一般都设置成
*
。
-
表示
区间
,如在小时位的
5-10
表示
5
点到
10
点每小时都执行。
,
表示
列举
,如在星期位的
MON,FRI,SAT
,表示在
周一
、
周五
和
周六
执行。由逗号分隔的项中仍支持使用其他符号。
/
表示
间隔
,如在天位的
1/2
,表示从
1
号开始每隔
2
天执行一次。在分钟位的
0/10
表示从每小时的
0
分开始,每隔
10
分钟执行一次。注意 Keeper 不支持
*/2
类似的设置,表示从当前时间开始每隔多少时间执行一次,但在其他应用如
crontab
中支持。星期位不支持间隔设置,可使用列举全部列出来。
?
表示
互斥
,仅在天位和星期位支持,如果设置了天位,则星期位要设置成
?
,如果设置了星期位,则天位要设置成
?
。如果两个都设置了值,则优先天位的设置。
#
表示
第几周
,仅出现在星期位中,如
MON#2
表示每月第
2
周的
周一
。
+
表示
和
,仅出现在星期位中且
#
号前面。如
MON-WED+FRI-SUN#2
表示每月第
2
周的
周一到周三加上周五到周日
。
;
表示
分隔
,在 Keeper 中,分号用来分隔多个 Cron 表达式,见下面的说明。
@
表示
属于
,在 Keeper 中,用于设置无限循环任务在不同时间段的时间间隔,见下面的说明。
特别的,有些情况下设置等价,例如:
如
*
在秒位、分钟位、小时位等价于
0/1
在星期位
*
等价于
1/1
等价于
1,2,3,4,5,6,7
等价于
MON,TUE,WED,THU,FRI,SAT,SUN
周
名称关键字和
月
名称关键字只支持
3
位的英文单词缩写,下面主要对其他的关键字进行介绍。
F
表示第一个,如每月第一天、每月第一周、每月第一个周一等
L
表示最后一个,如每月最后一天、每月最后一周、每月倒数第几天,每月最后一个周五等
W
表示工作日,一般为周一到周五,特殊工作日见下面的说明
R
表示休息日,一般为周六和周日,特殊休息日如法定节假日的设置见后面的说明
FW
表示第一个工作日,如每月或每周的第一个工作日
FR
表示第一个休息日,如每月或每周的第一个休息日
LW
表示最后一个工作日,如每月或每周的最后一个工作日
LR
表示最后一个休息日,如每月或每周的最后一个休息日
特别的,关键字不区分大小写。上面的
F
和
L
关键字还可以和其他的值组合,见天设置和星期设置。
在 Cron 表达式中的天设置相对复杂一些,有一些特殊的情况,比如每月的天数不固定、有工作日和节假日的区分等。分别举例说明如下:
每月第一天,即
1
号,用
1
或
F
表示
每月第一个工作日,用
FW
表示
每月第一个休息日,用
FR
表示
每月最后一个工作日,用
LW
表示
每月最后一个休息日,用
LR
表示
每月最后一天,用
L
表示
每月倒数第二天,用
L2
或
2L
表示,倒数第
3
天为
L3
,依次类推
指定日期执行,使用确定的数字,如
10
号和
11
号执行,用
11,12
表示
指定日期区间执行,使用区间符号,如
1
到
10
号执行,用
1-10
表示
间隔几天执行一次,使用间隔符号,如从
2
号开始双日执行,用
2/2
表示;从
1
号开始单日执行为
1/2
可以混合使用,如
1,9-15,16-24/2,25-L
,其中第三段表示
16
号到
24
号每隔
2
天执行一次
在 Cron 表达式设置中,星期的设置应该是最复杂的。分别举例说明如下:
每周一,用
MON
中
1
表示,依次类推
设置多天,可以用列举如
MON,FRI,SUN
或区间如
MON-FRI
每周第一个工作日,用
FW
表示
每周第一个休息日,用
FR
表示
每周最后一个工作日,用
LW
表示
每周最后一个休息日,用
LR
表示
每周的工作日,用
W
表示,由于法定节假日的原因,工作日和周一到周五的意义不同。
每周的休息日,用
R
表示,由于法定节假日的原因,休息日和周六周日的意义不同。
每月第一周每天执行,用
#1
或
#F
表示
每月第一周指定某一天执行,如
MON#F
表示第一周的周一、
W#F
表示第一周的工作日
每月第二周用
#2
表示,依次类推。每月第三周的周一到周五,用
1-5#3
表示
逗号的优先级比较低,如每月第四周的周一和周三,用
1#4,3#4
或
1+3#4
表示而不是
1,3#4
(表示每周一和第四周的周三)
加号仅在有井号时做连接操作,如
1+2#2
表示第二周的周一和周二、
1-3+5-6#3
表示第三周的除周四外的其他几天
每月最后一周用
#L
表示,前面可以添加星期。 因为有的月份有
6
周,有的月份有
5
周,最少有
4
周,所有用L表示最后一周。
MON#F
、
WED#6
、
SUN#L
第一周和最后一周的设置有一些客观问题,即如果第一周或最后一周不存在指定的日期,如第一周不存在周一、最后一周不存在周日、甚至当月没有第六周。这种情况下本月不会有匹配结果,继续下一个月,直到找到匹配项。但是像
SAT#6
,
SUN#6
永远不会有匹配结果,一定注意。
每月第一个周一,用
F1
或
FMON
表示,注意不能用
1#1
、
MON#1
、
1#F
、
MON#F
表示,前者表示第一个周一,后者表示第一周的周一
每月最后一个周五,用
L5
或
LFRI
表示,注意不能用
5#L
或
FRI#L
表示,两者的意义不同,一个表示最后一个周五,另一个表示最后一周的周五。
最后一周第一个工作日,用
FW#L
表示
第二个星期三用
2WED
或
23
表示,依次类推,最大值应该是
5X
。
可以混合使用,如
FMON,F7,#2,1-5#3,FW#L,R#L
,每一段分别表示第一个周一,第一个周日,第二周的每天,第三周的周一到周五,最后一周的第一个工作日,最后一周的所有休息日
用数字还是英文单词缩写表示星期依照个人习惯即可。
在日常使用中,月份一般为
*
号。特殊情况下可以使用关键词或数字进行设置。
每月都执行用
*
表示
每季度第一月,用
1/3
表示
每季度最后一月,用
3/3
表示
指定连续的几个月,如
MAR-JUL
或
3-7
表示
3
月到
7
月。
指定某几个月,如
4,6,8,10
或
APR,JUN,AUG,OCT
表示
4
月、
6
月、
8
月或
10
月。
特殊工作日和休息日设置
每年都有一些法定节假日,也有一些公司的放假安排与法定节假日不同,比如春节法定节假日为
7
天,有的公司可以放
15
天。由于以上两种情况,所以在工作日
W
和节假日
R
设置时,不能完全按照周一到周五为工作日、周六和周日为休息日的来进行任务调度。
系统管理员或调度管理员可以在
Master 管理平台
的“系统设置”->“Keeper 监控”->“工作日历”中进行设置。Keeper 会按照这个设置进行特殊工作日和特殊休息日的区分,如果没有设置,则仍然默认周一到周五为工作日、周六和周日为休息日。
上面提到 Keeper 支持
1
到
7
位的 Cron 表达式格式设置,是由于有的时间位字段值不会变,如秒位始终为
0
,年位和月位一般都为
*
等。下面分别说明一下不同位数格式都简化了什么:
1
位,仅表示分钟位,如
30
等价于
0 30 * * * ? *
,表示每小时的
30
分执行
2
位,仅表示分钟和小时位,如
0 2
等价于
0 0 2 * * ? *
,表示每天凌晨
2
点整执行
3
位,仅表示分钟、小时和天位,如
0 9 W
等价于
0 0 9 W * ? *
,表示每月的工作日的
9
点整执行
4
位,省略了秒、星期和年位
5
位,省略了秒和年位,这两位一般情况下都不需要设置
6
位,省略了秒位,在Keeper中秒位必须为
0
除了标准的 Cron 表达式格式外,Keeper 还支持另外两种易读的表达式格式。
第一种格式和地址查询字符中类型,如
HOUR=2&MINUTE=0
表示每天凌晨
2
点执行,等价于
0 2
。支持的参数名如下:
SECOND
秒
MINUTE
分钟
HOUR
小时
DAY
天
MONTH
月
WEEK
周
YEAR
年
使用
=
号对某一位进行设置,不同位设置之间使用
&
号隔开。在这种格式中,仅需要设置需要的时间位,其他不需要设置的位可以省略。这种格式忽略设置的顺序,也可以规避错位的问题。
另一种格式更加易读,主要提供给非技术人员使用,如
DAILY 12:00
表示每天中午
12
点执行。常见的格式如下:
MINUTELY
表示每分钟执行,等价于
0 * * * * ? *
HOUR 30
表示每小时
30
分执行,等价于
0 30 * * * ? *
HOUR 15,45
表示每小时
15
分和
45
分执行,等价于
0 15,45 * * * ? *
DAILY 01:00
表示每天凌晨1点执行,等价于
0 0 1 * * ? *
,每日任务在日常生产中最常见
DAILY 9:30; 10:45
表示每天
9:30
和
10:45
(在标准 Cron 表达式中,不能通过一条表达式实现这个配置),等价于
0 30 9 * * ? *; 0 45 10 * * ? *
DAILY 0-3,13:00
或
DAILY 7,20:0/5
,可以理解为冒号左边是小时,右边是分钟,设置规则等同于标准的 Cron 表达式
WEEKLY MONDAY 09:00
表示每周一早晨
9
点执行,注意这里支持完整的星期名称
MONTHLY WORKDAY 18:30
表示每个工作日的
18:30
分钟执行,这里支持完整的关键字列表
YEARLY JULY 1 12:00
表示每年的
7
月
1
日中午
12
点执行,不过按年设置调度计划的情况非常之少
这种格式支持非常多的关键词,这些关键词主要集中在
WEEKLY
、
MONTHLY
和
YEARLY
三种模式中,简单列表如下:
星期关键词:
MONDAY
,
TUESDAY
,
WEDNESDAY
,
THURSDAY
,
FRIDAY
,
SATURDAY
,
SUNDAY
星期关键词简写:
MON
,
TUE
,
WED
,
THU
,
FRI
,
SAT
,
SUN
月份关键词:
JANUARY
,
FEBRUARY
,
MARCH
,
APRIL
,
MAY
,
JUNE
,
JULY
,
AUGUST
,
SEPTEMBER
,
OCTOBER
,
NOVEMBER
,
DECEMBER
月份关键词简写:
JAN
,
FEB
,
MAR
,
APR
,
MAY
,
JUN
,
JUL
,
AUG
,
SEP
,
OCT
,
NOV
,
DEC
工作日和休息日:
WORKDAY
,
HOLIDAY
组合关键词:
FIRST-DAY
,
LAST-DAY
,
FIRST-WORKDAY
,
LAST-HOLIDAY
,
FIRST-HOLIDAY
,
LAST-HOLIDAY
第几周关键词:
FIRST-WEEK
,
SECOND-WEEK
,
THIRD-WEEK
,
FOURTH-WEEK
,
FIFTH-WEEK
,
SIX-WEEK
,
LAST-WEEK
,表示这一周的任意一天
第几周关键词后缀:
-OF-FIRST-WEEK
,
-OF-SECOND-WEEK
,
-OF-THIRD-WEEK
,
-OF-FOURTH-WEEK
,
-OF-FIFTH-WEEK
,
-OF-SIXTH-WEEK
,
-OF-LAST-WEEK
。前面可以使用
FIRST-WORKDAY
,
FIRST-HOLIDAY
,
WORKDAY
,
HOLIDAY
或星期名,如
WORKDAY-OF-FIRST-WEEK
,
MONDAY-OF-FIRST-WEEK
第几个周几关键词前缀:
FIRST-
,
SECOND-
,
THIRD-
,
FOURTH-
,
FIFTH-
,
LAST-
。可以接星期关键词,如
FIRST-MONDAY
,
LAST-SUNDAY
等
连接词
-TO-
,如
MONDAY-TO-FRIDAY-OF-LAST-WEEK
,表示最后一周的周一到周五
连接词
-AND-
,如
MONDAY-AND-FRIDAY-OF-LAST-WEEK
,表示最后一周的周一和周五。可以和
TO
混用,如
MONDAY-TO-WEDNESDAY-AND-FRIDAY-OF-SECOND-WEEK
,表示第二周的周一到周三和周五
同样的,以上关键字不区分大小写。
设置多个表达式
业务需求是复杂多变的,Cron 表达式虽然强大,但仍然不能完全涵养所有的需求。如业务要求任务在
09:30
和
10:45
各执行一次,这时一个表达式根本不能解决问题。Keeper 给出的解决方案是设置两个表达式,如
30 9; 45 10
或
DAILY 09:30; 10:45
。同样的,可以设置两个以上的表达式,多个表达式之间使用分号
;
隔开即可,分号两端有没有空格都没关系。
无限循环任务
Keeper 中支持无限循环任务,主要为数据准实时计算或数据大屏准备,比如每
2
秒钟更新一次数据。但是这种实时更新是相对的,比如在工作时间早
9
点到晚
7
点有人看大屏的时候可以计算频繁一点,晚上非工作时间没人看的时候计算间隔设置长一些,以释放服务器的计算资源,供其他任务使用,特别是在晚上
0
点到凌晨的计算高峰期。
Keeper 的解决方案是可以分段设置无限循环任务的时间间隔,如
60; 2@* 9-18; 8@* 19-23
表示在
9
点到
18
点之间每隔
2
秒执行一次,在
19
点到
23
点之间每隔
8
秒执行一次,其他时间每隔
60
秒执行一次。也可以不设置默认值,即在非指定的时间段不执行任务,如
2@* 9-18; 8@* 19-23
,即在
0
点到
8
点之间不执行任务。
在
PQL 的依赖包
中,提供了几个类用于 Cron 表达式的解析,包路径为
io.qross.time
。
ChronExp
类,传递任意格式的表达式,
详情点击
CronExp
类,用于标准格式的 Cron 表达式解析,
详情点击
DateTime
类,基础的日期时间类,
详情点击
以上几个类属于
DataHub 框架
的一部分。在 PQL 中,同样提供了对应的
Sharp 表达式
用于 Cron 表达式操作,详细
点击这里
。
Keeper 中的调度作业
DataHub 开发框架