EventBridge cron 表达式的写法:? 的含义、星期数字、日本时间的指定与从 crontab 改写
在 AWS 上定时运行 Lambda 或 ECS 任务时使用的 EventBridge cron 表达式,看起来和 Linux 的 crontab 很像,但字段数量、? 的用法、星期数字和时区都略有不同。按 crontab 的习惯写成“0 9 * * 1-5”会报错,直接照搬星期数字会差一天,时间按 UTC 解读又会差 9 小时,绊脚的地方接二连三。本文整理了 EventBridge cron 表达式的 6 个字段与 ? 的规则、星期数字、L、W、# 的用法、与 rate 表达式的区别、规则和 Scheduler 中日本时间的处理,以及与 crontab、Kubernetes、Spring、systemd 的改写对照表。
EventBridge 的 cron 表达式是用 cron( ) 括起来的“6 个字段”
EventBridge 的计划用 cron( ) 或 rate( ) 之一来写。cron( ) 中用空格分隔排列 6 个值:在 crontab 的 5 个字段之外再加上“年”。年字段不能省略,所以即使不限年份,也要在末尾写 *。
| 顺序 | 字段 | 可写的值 | 可用的符号 |
|---|---|---|---|
| 第 1 个 | 分 | 0-59 | , - * / |
| 第 2 个 | 时 | 0-23 | , - * / |
| 第 3 个 | 日 | 1-31 | , - * ? / L W |
| 第 4 个 | 月 | 1-12 或 JAN-DEC | , - * / |
| 第 5 个 | 星期 | 1-7 或 SUN-SAT | , - * ? L # |
| 第 6 个 | 年 | 1970-2199 | , - * / |
例如“工作日(周一至周五)的 0:00(UTC)”是“cron(0 0 ? * MON-FRI *)”。与 crontab 的“0 0 * * 1-5”相比,日期字段变成了 ?,星期变成了英文缩写,最后还多了年的 *。这 3 处就是从 crontab 移过来时必须修改的地方。
? 的规则:日期或星期必须有一方为 ?
EventBridge 中最容易报错的是 ? 的用法。? 表示“这个字段不指定(由另一个字段决定)”,必须恰好写在日期(第 3 个)或星期(第 5 个)其中一方。两者都写 * 不行,两者都写 ? 也不行。
| 想做的事 | 正确写法 | 常见错误 |
|---|---|---|
| 每天 9:00 | cron(0 9 * * ? *) | cron(0 9 * * * *)(两者都是 *) |
| 工作日 9:00 | cron(0 9 ? * MON-FRI *) | cron(0 9 * * MON-FRI *)(日期是 *) |
| 每月 1 日 9:00 | cron(0 9 1 * ? *) | cron(0 9 1 * * *)(星期是 *) |
| 每周一 9:00 | cron(0 9 ? * MON *) | cron(0 9 ? * ? *)(两者都是 ?) |
记法很简单:“按星期决定就把日期设为 ?,按日期决定就把星期设为 ?,每天就把日期设为 *、星期设为 ?”。由于这个机制,像 crontab 那样的“日期或星期其中之一(OR)”和 Spring 那样的“两者都满足(AND)”,都无法用一条规则写出。“每月 1 日和每周五”这样的指定,要拆成按日期的规则和按星期的规则两条。
星期数字 1 是周日:与 crontab 差一位
在 crontab 中 0 是周日、1 是周一,而在 EventBridge 中 1 是周日、2 是周一……7 是周六。照抄数字的话,所有星期都会提前一天。
| 星期 | crontab | EventBridge | 英文缩写 |
|---|---|---|---|
| 周日 | 0(也可写 7) | 1 | SUN |
| 周一 | 1 | 2 | MON |
| 周二 | 2 | 3 | TUE |
| 周三 | 3 | 4 | WED |
| 周四 | 4 | 5 | THU |
| 周五 | 5 | 6 | FRI |
| 周六 | 6 | 7 | SAT |
| 工作日(周一至周五) | 1-5 | 2-6 | MON-FRI |
把 crontab 的“1-5”原样写进 EventBridge,就会变成周日至周四(SUN-THU),出现周一的处理在周日运行、周五却不运行这种难以察觉的问题。在 EventBridge 中用 MON-FRI 这样的英文缩写书写,就不必在意数字的偏差,推荐这样写。
用 L、W、# 写月末、工作日和第 n 个星期几
EventBridge 的 cron 表达式可以直接表示 crontab 写不出的“月末”“第 n 个星期几”等。这些在每日、每月的批处理中很常用,记住代表性的写法会很方便。
| 写法 | 含义 | 表达式示例 | 2026 年 10 月以后的执行日期 |
|---|---|---|---|
| 日期的 L | 该月最后一天 | cron(0 0 L * ? *) | 10/31、11/30、12/31、1/31、2/28 |
| 日期的 L-3 | 最后一天的前 3 天 | cron(0 9 L-3 * ? *) | 10/28、11/27、12/28 |
| 日期的 15W | 离 15 日最近的工作日 | cron(0 9 15W * ? *) | 10/15(周四)、11/16(周一)、12/15(周二) |
| 日期的 LW | 该月最后一个工作日 | cron(0 18 LW * ? *) | 10/30(周五)、11/30(周一)、12/31(周四) |
| 星期的 3#2 | 第 2 个周二(3 是周二) | cron(0 10 ? * 3#2 *) | 10/13、11/10、12/8 |
| 星期的 6L | 最后一个周五(6 是周五) | cron(0 18 ? * 6L *) | 10/30、11/27、12/25 |
# 和 L 要与星期数字组合使用,所以这里同样要注意“1 是周日”的偏差。按 crontab 的习惯把第 2 个周二写成“2#2”,就会变成第 2 个周一。W 表示“指定的日子如果是周六日,就在同一个月内离它最近的工作日”运行,不会跨月。2026 年 11 月 15 日是周日,所以 15W 会在次日 16 日(周一)运行。
与 rate 表达式的区别:“每隔”是从开始的时间算起
如果只是简单的间隔,也可以用 rate( ) 代替 cron。像 rate(5 minutes)、rate(1 hour)、rate(7 days) 这样写上数字和单位(minute、hour、day)。
- 数值为 1 时用单数,2 以上用复数。rate(1 hours) 或 rate(5 minute) 会报错
- 间隔从创建(或启用)规则的时间开始计算,所以无法对齐到“每小时 0 分”这样的时间
- 想在“每小时 0、15、30、45 分整”运行,不要用 rate(15 minutes),而要用 cron(0/15 * * * ? *)
- 没有周和月的单位,每周、每月的处理要用 cron 写
在 EventBridge 的 cron 表达式中,一般把间隔的起点写成“0/15”这样的数字(与“*/15”含义相同)。日志汇总这类时间对齐后更便于处理的工作用 cron,健康检查这类只看间隔的工作用 rate,这样区分使用比较好。
按日本时间运行:规则用 UTC,Scheduler 可以选择时区
EventBridge 有两种创建计划的方式:一直以来的“EventBridge 规则(Rules)”和 2022 年新增的“EventBridge Scheduler”。cron 表达式的写法相同,但时区的处理不同。
| EventBridge 规则 | EventBridge Scheduler | |
|---|---|---|
| cron 表达式的时区 | 固定为 UTC | 用 ScheduleExpressionTimezone 指定(Asia/Tokyo 等) |
| 工作日 9:00(日本时间)的写法 | cron(0 0 ? * MON-FRI *) | cron(0 9 ? * MON-FRI *) + 时区 Asia/Tokyo |
| 只运行一次 | 不可以 | 可以用 at(2026-12-01T09:00:00) 指定 |
| 有夏令时的地区 | 需要自己调整时间 | 按时区自动调整 |
用规则对齐日本时间时,与 GitHub Actions 一样,写上减去 9 小时的 UTC 时间。日本时间 0 点到 8 点多是 UTC 的前一天,所以星期也要退回一格。例如日本时间工作日 8:00 是 UTC 周日至周四的 23:00,写成“cron(0 23 ? * SUN-THU *)”。具体换算步骤在让 GitHub Actions 的 cron 按日本时间运行的方法中有详细讲解。新建的话,用可以指定时区的 Scheduler 不会出现时差计算错误,更安全。
与 crontab、Kubernetes、Spring、systemd 的改写对照表
下面把同一个计划按各常用系统的写法排列。时间均为各系统所指定时区的时间(EventBridge 规则和 GitHub Actions 为 UTC)。
| 计划 | crontab、Kubernetes | EventBridge | Spring @Scheduled | systemd OnCalendar |
|---|---|---|---|---|
| 每天 3:30 | 30 3 * * * | cron(30 3 * * ? *) | 0 30 3 * * * | *-*-* 03:30:00 |
| 工作日 9:00 | 0 9 * * 1-5 | cron(0 9 ? * MON-FRI *) | 0 0 9 * * MON-FRI | Mon..Fri *-*-* 09:00:00 |
| 每 15 分钟 | */15 * * * * | cron(0/15 * * * ? *) | 0 */15 * * * * | *-*-* *:00/15:00 |
| 每月 1 日 0:00 | 0 0 1 * * | cron(0 0 1 * ? *) | 0 0 0 1 * * | *-*-01 00:00:00 |
| 每月最后一天 23:00 | 写不出(28-31 + 判断) | cron(0 23 L * ? *) | 0 0 23 L * * | *-*~01 23:00:00 |
| 第 2 个周二 10:00 | 写不出(8-14 + 判断) | cron(0 10 ? * 3#2 *) | 0 0 10 ? * TUE#2 | Tue *-*-08..14 10:00:00 |
- Kubernetes CronJob 与 crontab 一样是 5 个字段。1.27 起可以用 spec.timeZone: Asia/Tokyo 指定日本时间,不能在 schedule 中写 CRON_TZ=
- Spring 是开头带秒字段的 6 个字段。可以像 @Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Asia/Tokyo") 这样用 zone 指定时区
- systemd timer 的 OnCalendar 是“星期 年-月-日 时:分:秒”的形式。~01 表示“从月末倒数第 1 天”,也就是最后一天
在 cron 表达式检查器中把写法种类选为 AWS EventBridge 并粘贴表达式,就会提示漏写 ? 或星期数字的偏差,并显示释义和下次执行时间。输入 crontab 的表达式,还能一次查看改写成 EventBridge、Kubernetes、Spring、systemd 写法的结果。涉及日期与星期 OR 区别的移植,请一并查看cron 日期与星期的 OR 规则及第 n 个星期几、月末的写法。
常见问题
- EventBridge cron 表达式中的 ? 是什么意思?
- 意思是“这个字段不指定”,必须写在日期或星期其中一方。按星期决定就把日期设为 ?,按日期决定就把星期设为 ?。每天运行就像 cron(0 9 * * ? *) 这样把日期设为 *、星期设为 ?。两者都是 * 或都是 ? 会报错。
- EventBridge 怎样在日本时间 9 点运行?
- EventBridge 规则按 UTC 解读,所以减去 9 小时写成 cron(0 0 * * ? *)。如果用 EventBridge Scheduler,写成 cron(0 9 * * ? *) 并把时区(ScheduleExpressionTimezone)指定为 Asia/Tokyo,就会在日本时间 9:00 运行。
- EventBridge 的星期数字中哪个是周一?
- 1 是周日,2 是周一……7 是周六。与 crontab(0 是周日,1 是周一)差一位,所以工作日是 2-6。为避免弄错数字,推荐用 MON-FRI 这样的英文缩写书写。
- EventBridge 每 5 分钟运行一次,用 cron 还是 rate 好?
- 只看间隔的话,rate(5 minutes) 最简单。但 rate 从创建规则的时间开始计算,执行时间不会对齐到每小时 0、5、10 分。想对齐时间就用 cron(0/5 * * * ? *)。
- crontab 的“0 9 * * 1-5”在 EventBridge 中怎么改写?
- 把日期设为 ?、星期设为 MON-FRI(用数字则是 2-6),最后加上年的 *,写成 cron(0 9 ? * MON-FRI *)。另外,EventBridge 规则按 UTC 解读,所以想在日本时间 9:00 运行,要把小时改为 0,写成 cron(0 0 ? * MON-FRI *)。
本文介绍的工具
相关文章
让 GitHub Actions 的 cron 按日本时间运行:UTC 换算速查表与星期偏移、延迟的对策
在 GitHub Actions 的 schedule 里写了“0 9 * * 1-5”,工作流却在日本时间傍晚 6 点才运行。这并不是写错了,而是因为 GitHub Actions 的 cron 一律按 UTC(协调世界时)解读。本文整理了把日本时间(JST)换算成 UTC cron 表达式的方法和速查表、指定早上 0 点到 8 点时出现的“星期和日期退回前一天”问题、一行写不下时如何拆成两行,以及 schedule 延迟或不运行的原因与对策。
阅读文章 →crontab 的写法与速查表:5 个字段与符号的含义、常用示例和注册命令
“每天 3 点备份”“每 5 分钟运行一次监控脚本”这类定时任务,在 Linux 上只要在 crontab 里写一行就能设置。不过“分 时 日 月 星期”这 5 个字段与 * , - / 这些符号的组合,刚开始很容易看错,常会出现 1 小时运行 60 次、本想每 7 分钟一次却出现 4 分钟间隔之类的事故。本文以示例为主,讲解 crontab 写法的基础和符号含义、可直接套用的速查表、crontab -e、-l、-r 的用法,以及编写命令部分时的注意事项。
阅读文章 →cron 的日期与星期是 OR 关系:第 2 个周一、月末、最后一个周五、隔周的正确写法
想表示“每月第 1 个周一 9 点”而写成“0 9 1-7 * 1”,结果除了每周一之外,每月 1 到 7 日每天都运行了。cron 中这个非常常见的失误,源于 cron 特有的规则:同时指定日期和星期时,只要符合“其中之一”就会运行。本文结合实际执行日期的示例,讲解日期与星期构成 OR 的机制及其例外,在 crontab 中正确运行第 n 个星期几、月末、最后一个周五、隔周的写法,以及 AWS EventBridge 和 Spring 中可用的 L、#、W 的写法。
阅读文章 →