CRON定时任务表达式

CRON 表达式用来描述“一个任务什么时候执行”。

它常见于 Linux 定时任务、后端任务调度、Spring、Quartz、Node.js 定时任务库、云函数、CI/CD 定时流水线、Kubernetes CronJob 等场景。

但学习 CRON 时,最容易卡住的不是符号,而是不同平台的表达式格式不完全一样。

所以不要一上来就背 *,/。更好的学习顺序是:

先确认平台格式

再拆字段含义

理解特殊符号

套常见时间模板

最后检查时区和运行环境

一、先识别 CRON 方言

同样是“每天 9 点执行”,不同平台可能写成不同形式。

平台类型表达式字段结构
Linux crontab0 9 * * *5 位,没有秒
带秒的任务库0 0 9 * * *6 位,第一位是秒
Quartz / Spring 常见写法0 0 9 * * ?6 位,支持 ?
Quartz 带年份0 0 9 * * ? 20267 位,最后一位是年

写 CRON 前,先问一个问题:当前平台到底要几位?

这是最重要的一步。字段数量错了,后面每一位都会错位。

二、三种常见格式

1. Linux crontab:5 位

Linux crontab 的经典格式是:

分钟 小时 日 月 星期

示例:

30 2 * * *

含义:

每天 2:30 执行

Linux crontab 没有秒字段。如果想做秒级任务,通常要用其他调度系统,或者在脚本内部循环处理。

2. 带秒格式:6 位

一些后端框架、Node.js 定时任务库、云函数平台会使用 6 位格式:

秒 分钟 小时 日 月 星期

示例:

0 30 2 * * *

含义:

每天 2:30:00 执行

这个格式最容易和 Linux crontab 混淆,因为它只是多了最前面的秒字段。

3. Quartz 风格:6 位或 7 位

Quartz 常见格式是:

秒 分钟 小时 日 月 星期 [年]

年字段通常可选。

示例:

0 30 2 * * ? 2026

含义:

2026 年每天 2:30:00 执行

Quartz 的特点是支持更多特殊符号,比如 ?LW#

不要把 Linux crontab、Quartz、Spring、云函数、GitHub Actions、Kubernetes CronJob 的表达式直接互相复制。先确认字段数量、星期编号、特殊符号和时区规则。

三、字段地图

以 Quartz 7 位格式为例:

秒 分钟 小时 日 月 星期 年
位置字段常见取值例子
10-590 表示第 0 秒
2分钟0-5930 表示第 30 分钟
3小时0-239 表示上午 9 点
41-311 表示每月 1 号
51-12JAN-DEC1JAN
6星期平台差异较大,也可用 SUN-SATMON-FRI
7常见为可选2026

如果是 Linux crontab,就只保留:

分钟 小时 日 月 星期

四、符号不是孤立背的

CRON 的特殊符号可以按“表达意图”来记。

想表达什么符号示例含义
任意值**该字段的所有值
固定几个值,9,12,189、12、18
一段范围-9-189 到 18
每隔一段时间/*/5每 5 个单位
不指定日或星期??Quartz 中常用
最后一个LL最后一天或最后一个星期几
最近工作日W15W离 15 号最近的工作日
第几个星期几#MON#2每月第二个周一

注意:Linux crontab 通常不支持 ?LW#。看到这些符号,大概率是在 Quartz 或类似平台里。

五、用模板理解常见时间

比起背语法,更实用的方法是记模板。

模板 1:每隔 N 分钟

Linux crontab:

*/5 * * * *

含义:

每 5 分钟执行一次

Quartz:

0 0/5 * * * ?

含义:

每 5 分钟的第 0 秒执行一次

模板 2:每天固定时间

每天凌晨 2 点:

0 2 * * *

Quartz:

0 0 2 * * ?

每天 9 点、12 点、18 点:

0 9,12,18 * * *

Quartz:

0 0 9,12,18 * * ?

模板 3:工作日固定时间

Linux crontab:

0 9 * * 1-5

含义:

周一到周五每天 9:00 执行

Quartz:

0 0 9 ? * MON-FRI

这里 Quartz 用 ? 放在“日”字段,表示不指定每月第几天,只按星期判断。

模板 4:每月固定日期

每月 1 号 10 点:

0 10 1 * *

Quartz:

0 0 10 1 * ?

每月 1 号和 15 号 10 点:

0 10 1,15 * *

Quartz:

0 0 10 1,15 * ?

模板 5:每年固定日期

每年 1 月 1 日 0 点:

0 0 1 1 *

Quartz:

0 0 0 1 1 ?

模板 6:秒级任务

Linux crontab 本身不支持秒级调度。

Quartz 每 10 秒执行一次:

0/10 * * * * ?

一些 6 位 Node.js 任务库可能写成:

*/10 * * * * *

这类表达式一定要看库文档,因为不同库对秒字段和特殊符号的支持不同。

六、“日”和“星期”要单独讲

CRON 中最容易产生误解的是“日”和“星期”两个字段。

看这个 Linux crontab:

0 9 1 * 1

它很容易被理解成:

每月 1 号,并且这一天是周一时执行

但很多传统 crontab 实现会按“或”的关系处理:

每月 1 号执行,或者每周一执行

Quartz 为了避免这个歧义,引入了 ?

需求Quartz 写法
每月 1 号 9 点0 0 9 1 * ?
每周一 9 点0 0 9 ? * MON

记法很简单:

指定“日”时,“星期”用 ?
指定“星期”时,“日”用 ?

七、速查表

Linux crontab

需求表达式
每分钟* * * * *
每 5 分钟*/5 * * * *
每小时整点0 * * * *
每天 0 点0 0 * * *
每天 2
30 2 * * *
工作日 9 点0 9 * * 1-5
每天 9 点和 18 点0 9,18 * * *
每月 1 号 0 点0 0 1 * *
每年 1 月 1 日 0 点0 0 1 1 *

Quartz

需求表达式
每 10 秒0/10 * * * * ?
每 5 分钟0 0/5 * * * ?
每小时整点0 0 * * * ?
每天 0 点0 0 0 * * ?
每天 2
0 30 2 * * ?
工作日 9 点0 0 9 ? * MON-FRI
每月 1 号 9 点0 0 9 1 * ?
每月第一个周一 9 点0 0 9 ? * MON#1
每月最后一天 18 点0 0 18 L * ?

八、在 Linux crontab 中落地

Linux crontab 不只是一个表达式,它还要跟命令一起写。

编辑当前用户的定时任务:

crontab -e

查看当前用户的定时任务:

crontab -l

删除当前用户的全部定时任务:

crontab -r

一个完整任务:

0 2 * * * /usr/bin/node /app/scripts/backup.js >> /var/log/backup.log 2>&1

结构拆开看:

片段含义
0 2 * * *每天 2 点
/usr/bin/node使用绝对路径调用 Node
/app/scripts/backup.js要执行的脚本
>> /var/log/backup.log追加标准输出到日志
2>&1把错误输出也写进同一个日志

如果脚本依赖项目目录,可以显式 cd

0 2 * * * cd /app && /usr/bin/pnpm run backup >> /var/log/backup.log 2>&1

九、时区是隐藏坑

CRON 写对了,任务仍然可能在“错误时间”执行。

常见原因是时区:

环境常见情况
Linux 服务器取决于系统时区
Docker 容器默认可能是 UTC
云函数可能固定使用 UTC
CI/CD常见为 UTC
Kubernetes CronJob新版本可配置 timeZone

先看当前机器时间:

date

Kubernetes CronJob 如果支持 timeZone,可以显式配置:

spec:
  timeZone: Asia/Shanghai
  schedule: "0 2 * * *"

如果平台不支持时区配置,就要把本地时间换算成平台使用的时区。

十、排错清单

1. 字段数量是否正确

这是第一优先级。

你写的放错平台后的风险
0 9 * * *在 6 位平台中可能字段不足或含义错位
*/5 * * * * *在 6 位平台表示每 5 秒,不是每 5 分钟

如果平台要求 6 位,每天 9 点通常应写成:

0 0 9 * * *

Quartz 通常写成:

0 0 9 * * ?

2. 星期编号是否符合平台规则

星期字段差异很大:

可能规则含义
0周日
1周一
1周日
7周日
MON-FRI周一到周五

能写英文缩写时,MON-FRI 通常比 1-5 更清楚。

3. “日”和“星期”是否同时指定

Quartz 中建议用 ? 避免歧义:

0 0 9 1 * ?

表示每月 1 号 9 点。

0 0 9 ? * MON

表示每周一 9 点。

4. 命令是否能在非交互环境执行

手动执行成功,crontab 失败,常见原因不是表达式,而是环境不同。

重点检查:

  • 命令是否使用绝对路径;
  • 工作目录是否正确;
  • 环境变量是否存在;
  • 当前用户是否有权限;
  • 是否把日志输出到文件;
  • 脚本是否依赖交互式 shell。

5. 是否真的到了执行时间

调试时不要只盯着表达式,可以手动推演接下来三次执行时间。

例如:

0 0 9 ? * MON-FRI

翻译成自然语言:

周一到周五每天 9:00:00 执行

如果现在是周五 10 点,下一次执行应该是下周一 9 点。

十一、学习 CRON 的检查方法

每写一个表达式,都按下面的问题过一遍:

  1. 这个平台要 5 位、6 位还是 7 位?
  2. 第一位是不是秒?
  3. 是否支持 ?LW#
  4. 星期字段从哪一天开始编号?
  5. “日”和“星期”有没有同时指定?
  6. 平台使用哪个时区?
  7. 命令本身有没有日志、权限和环境变量问题?

这比单纯背表达式更可靠。

十二、总结

CRON 可以分成四层理解:

  1. 格式层:先确认 5 位、6 位还是 7 位。
  2. 字段层:明确每一位代表分钟、小时、日、月、星期,还是秒和年。
  3. 符号层:用 *,-/? 表达任意、枚举、范围、间隔和空置。
  4. 运行层:检查平台差异、时区、命令路径、环境变量和日志。

只要先判断方言,再套模板,最后检查运行环境,CRON 表达式就不会只是几串难背的星号,而会变成一套可以稳定落地的时间规则。

按下 K 进行搜索