Cron 解析器

探测语法并预测执行时间

正在加载工具…

关于 Cron 表达式解析

Cron 表达式解析器会判断一条表达式属于哪种方言 —— Unix 5 段、以秒开头的 6 段,还是 Quartz 7 段 —— 逐段标注含义,并按你指定的时区推算出接下来 8 次执行时间。真正有用的正是这份预览:cron 表达式写起来只要几秒,读懂却要好几分钟,唯一可靠的检查手段就是看一串真实日期。

cron 并不是一种语言。经典 Unix cron 有 5 个字段,而且当「日」和「星期」同时被限定时,两者是「或」而不是「且」;Quartz 在最前面加了秒、最后面加了年,并引入了 ?、L、W、# 四个符号;Spring 的 @Scheduled 同样用 6 个字段,长得和 Quartz 一样,星期编号却沿用 Unix。此外每条表达式都要在某个时区里求值 —— 那是调度器的时区,通常不是你的 —— 而这个时区一年还会挪动两次。方言、时区和夏令时几乎承包了 cron 的全部故障,语法本身反倒很少出问题。

如何使用这个开发者工具

  1. 先选择与调度器一致的格式,也可以直接粘贴表达式,让字段数量替你选。
  2. 既可以在整行输入框里改表达式,也可以在下方带标签的分段框里逐段改。两个视图始终同步,切换格式时已填好的字段会被带过去。
  3. 把时区设置成调度器实际运行的时区,而不是你所在的时区。任何 IANA 时区名都可以填。
  4. 先看识别出的语法标签,再看日期。被标注为「与 Quartz 存在歧义」的 6 段表达式里没有出现 ?、L、W、#,工具无法判断你想用哪种方言。
  5. 8 条执行时间要全看,不要只看第一条。每行给出所选时区的本地时间、同一时刻的 ISO 8601 写法,以及距今多久;重点看周末和跨月那几行。

实例:工作日上午的定时任务

一条 Quartz 6 段表达式,在 Asia/Shanghai 时区下预览,参考时刻取 2026 年 9 月 21 日(周一)10:00 —— 比当天那次执行晚了 10 分钟。

表达式、时区、参考时刻
0 0 9 ? * MON-FRI
Asia/Shanghai
2026-09-21T10:00:00+08:00
后续 8 次执行时间
1  周二 2026-09-22 09:00:00   2026-09-22T01:00:00Z
2  周三 2026-09-23 09:00:00   2026-09-23T01:00:00Z
3  周四 2026-09-24 09:00:00   2026-09-24T01:00:00Z
4  周五 2026-09-25 09:00:00   2026-09-25T01:00:00Z
5  周一 2026-09-28 09:00:00   2026-09-28T01:00:00Z
6  周二 2026-09-29 09:00:00   2026-09-29T01:00:00Z
7  周三 2026-09-30 09:00:00   2026-09-30T01:00:00Z
8  周四 2026-10-01 09:00:00   2026-10-01T01:00:00Z

这份列表说出了表达式本身没说的三件事。9 月 21 日不在列表里,因为当天 09:00 已经过去;26 日和 27 日不在,因为那是周末;而每一条 ISO 时刻都是 01:00Z,因为 Asia/Shanghai 的 09:00 就是 UTC 的 01:00 —— 真正跑在 UTC 下的调度器,按它自己的钟是在 01:00 触发。

字段顺序,以及在不同方言间会变味的符号

从左到右,Unix 5 段依次是分钟、小时、日、月、星期。Quartz 6 段在最前面多一个秒,7 段再在最后多一个年。本工具会给 5 段表达式在前面补一个值为 0 的秒字段,因此 0 9 * * 1 实际按 0 0 9 * * 1 求值。

符号含义实例
*该字段允许的每一个值* * * * * 每分钟执行一次
,一组互不相邻的取值0 9,13,17 * * * 在 09:00、13:00、17:00 各执行一次
-闭区间范围0 0 9 ? * MON-FRI 周一到周五 09:00 执行
/步长,从它前面那个范围的起点开始数*/15 * * * * 在第 0、15、30、45 分钟执行
?仅 Quartz:不指定具体值,且「日」和「星期」中必须恰好有一个填 ?0 0 9 ? * MON-FRI 不对「日」加任何约束
L最后:在「日」里是当月最后一天,在「星期」里是当月最后一个该星期几0 0 0 L * * 在 1 月 31、2 月 28、3 月 31 日执行;0 0 0 * * FRIL 在当月最后一个周五执行
W仅 Quartz:离该日最近的工作日2026 年 8 月的 15W 落在 8 月 14 日周五,因为 15 日是周六
#仅 Quartz:当月第 n 个该星期几0 0 0 * * SAT#3 在 2026-10-17、2026-11-21、2026-12-19 执行

常见问题排查

任务在你从未指定的日子里触发了。

成因 经典 Unix cron 在「日」和「星期」都被限定时,用的是「或」而不是「且」。只要两个字段都不是 *,任何一个命中都会触发。

解决办法 两者只限定其中一个。0 0 12 13 * FRI 并不是「13 号且周五」,它每个周五执行、每月 13 号也执行。真要取两者的交集,请写 0 0 12 13 * *,再在任务内部判断星期。

每年总有一两次,某一次执行消失或者重复了。

成因 夏令时切换。在 America/New_York,2026 年 3 月 8 日本地时钟从 02:00 直接跳到 03:00,0 30 2 * * * 那天根本没有 02:30 可以落脚;11 月 1 日 01:00 这一小时会重放,于是 01:30 出现了两次。

解决办法 本工具在跳变那天把被跳过的时刻归到本地 03:30,重复的时刻只列一次。真实调度器做法并不一致:Vixie cron 会在时钟跳变时补跑一次,Quartz 走它的 misfire 策略,还有些运行时会把那一小时跑两遍。关键任务请排在 UTC 下,或避开本地 01:00 到 03:00。

Quartz 表达式的预览整体晚了一天。

成因 Quartz 的星期编号是 1 = 周日 到 7 = 周六。本工具对数字星期沿用 Unix 编号,即 0 = 周日 到 6 = 周六,同时接受 7 表示周日。Quartz 的 6 是周五,在这里 6 是周六。

解决办法 把数字换成星期名。MON、FRI、MON-FRI 在所有方言里含义一致,多敲这几个字母换来的就是这份确定性。

预览完全正确,线上却在错误的小时触发。

成因 表达式实际求值的时区和你预览时用的不是同一个。Kubernetes CronJob 在未设置 .spec.timeZone 时按 UTC 运行,JVM 调度器用 JVM 默认时区,crond 用系统时区或 CRON_TZ。

解决办法 查清调度器所在的时区,把它填进时区框,重新看一遍预览。如果两份列表不一致,那是调度配置错了,而不是工具算错了。

适合用这个工具的场景

  • 在发布之前证明:刚写的这条调度,确实落在你想要的那些日子上。
  • 用 8 个具体日期终结代码评审里关于字段顺序的争论。
  • 检查调度在周末、跨月和闰日上的表现 —— 人工推算恰恰在这些地方悄悄出错。
  • 只改时区框,把同一条表达式在两个时区下的结果放在一起比对。

应该换用别的工具的场景

  • 把预览里的某个时刻换算到别的时区或换成 Unix 时间戳。请把 ISO 值复制到日期与时间戳转换工具。
  • 校验调度器的私有扩展。@daily 之类的简写、Quartz 的 L-3、systemd 的 OnCalendar= 都不是 cron 表达式,在这里会被拒绝。
  • 判断任务到底有没有跑成功。漏跑、重叠执行、重试和 misfire 策略属于调度器和你的监控。

隐私与数据处理

表达式的解析和执行时间的推算都在当前浏览器标签页内完成,用的是浏览器通过 Intl 自带的时区数据库。没有任何内容被上传,也不会跨访问保存。表达式本身通常不敏感,但人们粘贴时顺手带上的任务名和故障备注往往敏感,因此截图分享前请把输入精简到只剩表达式。

相关开发者工具

常见问题

为什么我的表达式会在多余的日子触发?

几乎总是因为「日」和「星期」同时被限定,而 Unix cron 把这种情况当作「或」。把两者之一留成 *(Quartz 里写 ?),意外就消失了。

预览用的是哪个时区?

用时区框里填的那个,通过浏览器自带的 IANA 数据库解析。它默认填你的本地时区,这既方便又是最常见的错误来源,因为调度器很少和你在同一个时区。

0 9 * * 1 是周一还是周日?

在本工具采用的 Unix 编号下,0 是周日、1 是周一,所以它是每周一 09:00。而在 Quartz 里同样的数字表示周日,因为 Quartz 的一周从 1 = 周日 开始。写成 MON 就能同时消除两边的歧义。

为什么我的 6 段表达式被标成有歧义?

6 个字段既可能是 Quartz,也可能是 Spring @Scheduled 这类「秒在最前」的 Unix 变体,两者星期编号并不一致。出现 ?、L、W、# 时可以确定是 Quartz;没有这些字符时,工具选择提示你而不是替你猜。

7 段形式真的会考虑年份吗?

会。前 6 个字段照常求值,每个候选时刻再拿去和年份字段比对,因此 0 0 0 1 1 ? 2027-2029 会给出 3 次执行然后停下。年份字段同样支持列表、范围和步长。

多出来的秒字段代价是什么?

在表达式里代价极小,在运维上代价不小。像 0/30 * * * * ? 这样的调度每天要跑 2880 次,任何偶尔超时的任务都会开始自己叠自己。缩短间隔之前,先加上分布式锁或并发策略。