Cron 表达式解析器 实时展示表达式的语义(“每天 3 点”等)和下次触发时间,支持 Linux(5 位)、Spring(6 位)、Quartz(7 位)三种格式自动识别。
Linux / crontab * * * * *:
| 位 | 字段 | 取值 |
|---|---|---|
| 1 | 分钟 | 0-59 |
| 2 | 小时 | 0-23 |
| 3 | 日 | 1-31 |
| 4 | 月 | 1-12 |
| 5 | 周 | 0-7(0 和 7 都是周日) |
6 / 7 字段扩展:Spring 在前面加”秒”字段得 6 位;Quartz 再加”年”(可选)得 7 位。
* — 任意值, — 枚举(1,3,5)- — 范围(9-17)/ — 步长(如 */15 表示每 15 个单位触发)? — 占位不关心(仅 Quartz、新版 Spring 的日 / 周字段)L — 最后一天(仅 Quartz、Spring ≥5.3)# — 第 N 个星期几(如 2#3 第 3 个周二,仅 Quartz)从右向左填(先决定”每周几 / 每月几号”,再填时分),或借助在线工具把中文需求直接翻译成表达式。需要秒级精度或”每月最后一天”等复杂规则时用 Spring / Quartz;简单日常调度 Linux crontab 够用。
* * * * * 到底多久执行一次?每分钟一次。Linux crontab 五个字段分别是"分 时 日 月 周",最小粒度是分钟。没有秒字段,想每秒/每 10 秒执行,用 systemd timer、脚本里 while sleep 10; do ... done,或者改用 Spring/Quartz(支持 6 位秒级格式)。
字段数即可识别——5 位是 Linux/crontab(分时日月周),6 位是 Spring(秒 + 前 5 位),7 位是 Quartz(秒分时日月周年)。另一个信号:Quartz 要求日和周字段有且仅有一个是 ?(表示"不关心"),这是它独有的语法。复制表达式前先看运行环境。
Linux cron 做不到——0 0 28-31 * * 会在 28/29/30/31 号都执行。Quartz 专门支持 L(Last):0 0 0 L * ? 就是每月最后一天 0 点。Linux 下只能在脚本里加判断:[ $(date -d tomorrow +%d) = 01 ] && do_thing,成立才执行。Spring 从 5.3 起也支持 L。
*/5 和 0/5 有什么区别?很多实现里两者都表示"按 5 的步长触发",例如分钟字段会在 0、5、10、15... 触发。区别主要在于不同引擎对写法的兼容度和官方示例习惯不完全一致。稳妥做法:优先按你所处环境的官方文档或工具示例来写,跨环境复制时重新校验一次。
最常见原因——时区:crond 默认用系统时区,容器里可能是 UTC;Spring @Scheduled 默认 JVM 时区;Quartz 可按 Job 单独设。解决:Linux 在 crontab 顶部加 CRON_TZ=Asia/Shanghai;JVM 启动加 -Duser.timezone=Asia/Shanghai。其次是夏令时切换日的偶发跳过/重复。
Linux cron 里两者是"或"关系——0 0 1 * 1 表示"每月 1 号 OR 每周一" 0 点都跑,容易出错;想"每月 1 号且是周一"需自己在脚本里判断。Quartz 要求两者中一个必须是 ?(互斥),解决了这个歧义。Spring 从 5.3 起沿用 Quartz 的 ? 规则。