Cron 表达式怎么写:五个字段一次读懂,附高频实例

「每天早上 9 点跑一次报表」「每周一凌晨清理日志」——这些需求写成 Cron 表达式只需要 5 个字段,但符号规则不熟悉时,写出来的任务不是不跑就是狂跑。这篇按字段拆开讲,配 12 个直接可用的实例。

一、五字段结构:分 时 日 月 周

位置含义取值范围
第 1 位分钟0–59
第 2 位小时0–23
第 3 位日1–31
第 4 位月1–12
第 5 位星期0–7(0 和 7 都是周日)

符号规则:* 任意值;, 枚举;- 区间;/ 步长(*/15 在分钟位 = 每 15 分钟)。0 9 * * 1-5 读作「周一到周五,每天 9:00」——这就是最经典的工作日早晨定时。

二、12 个高频实例

  1. */5 * * * * — 每 5 分钟(监控探活);
  2. 0 * * * * — 每小时整点(数据同步);
  3. 30 8 * * * — 每天 8:30(晨报推送);
  4. 0 9 * * 1-5 — 工作日 9:00(站会提醒);
  5. 0 2 * * * — 每天凌晨 2:00(数据库备份);
  6. 0 3 * * 0 — 每周日凌晨 3:00(全量清理);
  7. 0 0 1 * * — 每月 1 号零点(账单结算);
  8. 0 10 15 * * — 每月 15 号 10:00(月度中检查);
  9. 0 0,12 * * * — 每天 0 点和 12 点各一次(双高峰任务);
  10. 0 9-18 * * * — 每天 9 点到 18 点的每个整点(工作时段巡检);
  11. 0 0 * * 1,4 — 每周一和周四零点(双周任务日的合写);
  12. 59 23 28-31 * * — 每月最后几天末尾跑一次,脚本内自判是否为月末(Cron 本身难表达「月末」,这是惯用变通)。

三、三大经典踩坑

  1. 时区错位:Cron 按服务器本地时间执行。云服务器默认 UTC,北京时间早 9 点 = UTC 凌晨 1 点,写 0 9 * * * 实际在北京时间 17:00 跑。要么改系统时区,要么按 UTC 换算后再写;
  2. 「日 + 星期」同时限制:少数实现里日和周同时非 * 时是「或」关系(1 号或周一都会跑),而不是直觉上的「且」。不确定就只用其中一个字段,另一个保持 *;
  3. 漏配环境:Cron 任务的环境变量极简,PATH 里没有你熟悉的目录。脚本里用绝对路径,或显式 export 所需变量,能消灭一大半「手动跑没问题、Cron 跑就挂」的灵异事件。

四、设计定时任务的三个好习惯

  1. 幂等优先:任务可能因重启、超时被重复触发,脚本设计成「跑两次和跑一次结果一样」——写入用覆盖或 upsert,不用追加。这一条能消灭大半「数据重复」事故;
  2. 错峰排布:把备份、清理、统计类任务按 13、17、23 这类错开的分钟数排布,避免全站任务挤在同一分钟造成 IO 尖峰,也避免互相抢锁;
  3. 失败要出声:Cron 本身不报错,任务挂了只有日志知道。给关键任务加最简告警——末尾接一行通知(邮件/IM webhook),或用「心跳监控」平台检测任务超时未执行。跑了半年的备份任务悄悄挂掉三个月,是最常见的真实事故。

另外记住一个排障利器:系统日志里记录了每次触发时间(Ubuntu 在 /var/log/syslog,搜 CRON)。任务「没跑」还是「跑了但失败」,先查这里再改代码。

⏰ Cron 表达式解析:粘贴表达式立即翻译成人类语言,显示未来几次执行时间,写之前先验证语义。

常见问题

问:为什么有 5 字段和 6 字段两种说法?
经典 Unix Cron 是 5 字段;Quartz(Java 生态)等用 6 字段,第 1 位是秒,且「星期」从 1 开始。跨平台复制表达式前先确认格式。

问:想表达「工作日 9 点到 18 点每半小时」?
*/30 9-18 * * 1-5——分钟位步长 30,小时位限 9–18,周位限工作日。