使用 Cron 触发器
引言
cron 是一个存在已久的 UNIX 工具,其调度能力强大且经过验证。CronTrigger 类正是基于 cron 的调度能力构建的。
CronTrigger 使用“cron 表达式”,能够创建如“每周一至周五上午 8 点”或“每月最后一个周五的 1:30am”这样的触发时间表。
cron 表达式功能强大,但也可能相当令人困惑。本教程旨在揭开创建 cron 表达式的一些神秘面纱,为用户提供一个参考资料,以便在不得不在论坛或邮件列表中提问之前可以查阅。
格式
cron 表达式是一个由 6 或 7 个字段组成,字段间以空格分隔的字符串。字段可以包含任何允许的值,以及该字段允许的各种特殊字符组合。这些字段如下:
字段名 | 必填 | 允许的值 | 允许的特殊字符 |
---|---|---|---|
秒钟 | 是 | 0-59 | , - * / |
分钟 | 是 | 0-59 | , - * / |
小时 | 是 | 0-23 | , - * / |
月份中的日期 | 是 | 1-31 | , - * ? / L W |
月份 | 是 | 1-12 或 JAN-DEC | , - * / |
星期中的哪天 | 是 | 1-7 或 SUN-SAT | , - * ? / L # |
年份 | 否 | 空、1970-2099 | , - * / |
因此,cron 表达式可以很简单,如:* * * * ? *
或者更复杂,如:0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010
特殊字符
*
(“所有值”)- 用于选择字段内的所有值。例如,分钟字段中的*
表示 “每分钟”。?
(“无特定值”)- 当需要在一个字段中指定某些内容,但在另一个允许该字符的字段中不关心时很有用。例如,如果我希望触发器在每个月的特定一天(比如 10 号)触发,但不在乎这一天是周几,我会在日-月字段中放10
,而在星期中放?
。见下方示例以澄清。-
- 用于指定范围。例如,小时字段中的10-12
意味着“10 点、11 点和 12 点”。,
- 用于指定额外的值。例如,星期中的哪天字段中的MON,WED,FRI
意味着 “周一、周三、周五”。/
- 用于指定递增。例如,秒字段中的0/15
意味着“0 秒、15 秒、30 秒和 45 秒”。而秒字段中的5/15
意味着 “5 秒、20 秒、35 秒和 50 秒”。你也可以在 “字符-” 之后指定/
,在这种情况下相当于在/
前有0
。日-月字段中的1/3
意味着 “每月的第 1 天开始每隔 3 天触发一次”。L
(“最后”)- 在其允许的两个字段中具有不同的意义。例如,日-月字段中的L
表示 “月份的最后一天” —— 1 月的 31 日,非闰年的 2 月的 28 日。如果单独在星期中的哪天字段使用,它简单表示 “7” 或 “周六”。但如果在星期中的哪天字段的其他值之后使用,它意味着 “月份的最后一个 xxx 天” —— 例如6L
表示 “月份的最后一个周五”。你还可以指定离每月最后一天的偏移量,如L-3
意味着日历月的倒数第三天。使用L
选项时,重要的是不要指定值的列表或范围,否则你会得到令人困惑/意外的结果。W
(“工作日”)- 用于指定给定日期最近的工作日(周一至周五)。例如,如果在日-月字段中指定15W
,含义是:“接近当月 15 日的工作日”。所以如果 15 日是周六,触发器会在 14 日周五触发。如果 15 日是周日,触发器将在 16 日周一触发。如果 15 日是周二,则它将在 15 日周二触发。然而,如果你指定日-月字段的值为1W
,并且 1 日是周六,触发器将触发在 3 日周一,因为它不会“跨越”一个月天数的边界。字符W
只能在日-月字段指定单个日期时使用,不能是范围或日期列表。
提示:字符
L
和W
也可以在日-月字段中组合使用,形成LW
,这表示 “每月的最后一个工作日”。
#
- 用于指定 “每月的第 n 个” 某天。例如,星期中的哪天字段中的值6#3
意味着 “每月的第三个周五”(天 6=周五,#3
= 该月的第三个)。其他示例:2#1
= 每月的第一个周一,4#5
= 每月的第五个周三。注意,如果你指定#5
,而该月没有给定的星期几的第 5 个,那么那个月就不会发生触发。
提示:合法字符、月份和星期几的名称不区分大小写。MON 与 mon 相同。
示例
以下是一些完整的示例:
表达式 | 含义 |
---|---|
0 0 12 * * ? |
每天中午 12 点触发 |
0 15 10 ? * * |
每天上午 10:15 触发 |
0 15 10 * * ? |
每天上午 10:15 触发 |
0 15 10 * * ? * |
每天上午 10:15 触发 |
0 15 10 * * ? 2005 |
2005 年每天上午 10:15 触发 |
0 * 14 * * ? |
每天下午 2 点开始,每分钟触发,直到 2:59,每天 |
0 0/5 14 * * ? |
每天下午 2 点开始,每 5 分钟触发,直到 2:55,每天 |
0 0/5 14,18 * * ? |
每天下午 2 点和 6 点开始,每 5 分钟触发,分别直到 2:55 和 6:55 |
0 0-5 14 * * ? |
每天下午 2 点开始,每分钟触发,直到 2:05,每天 |
0 10,44 14 ? 3 WED |
每年三月的每个周三,在下午 2:10 和 2:44 触发 |
0 15 10 ? * MON-FRI |
每周一至周五上午 10:15 触发 |
0 15 10 15 * ? |
每月 15 日上午 10:15 触发 |
0 15 10 L * ? |
每月最后一天上午 10:15 触发 |
0 15 10 L-2 * ? |
每月倒数第二天上午 10:15 触发 |
0 15 10 ? * 6L |
每月最后一个周五上午 10:15 触发 |
0 15 10 ? * 6L 2002-2005 |
2002 年至 2005 年,每月最后一个周五上午 10:15 触发 |
0 15 10 ? * 6#3 |
每月第三个周五上午 10:15 触发 |
0 0 12 1/5 * ? |
每月第一天开始,每隔 5 天的中午 12 点触发,每月 |
0 11 11 11 11 ? |
每年 11 月 11 日上午 11:11 触发 |
提示:注意
?
和*
在星期中的哪天和日-月字段中的效果!
注意
警告:
同时指定星期中的哪天和日-月的具体值的支持并不完整(目前你需要在这两个字段中的一个使用
同时指定星期中的哪天和日-月的具体值的支持并不完整(目前你需要在这两个字段中的一个使用
?
字符)。
警告:
在本地实行 “夏令时” 变更的早上时间段内设置触发时间要小心(对于美国地区,通常是凌晨 2 点前后的一小时——因为时间的调整可能导致跳过或重复,取决于时间是向前还是向后移动。你可能会发现维基百科的这个条目有助于了解适用于你的 时区 的详细信息。
在本地实行 “夏令时” 变更的早上时间段内设置触发时间要小心(对于美国地区,通常是凌晨 2 点前后的一小时——因为时间的调整可能导致跳过或重复,取决于时间是向前还是向后移动。你可能会发现维基百科的这个条目有助于了解适用于你的 时区 的详细信息。