Cron 定时任务与时区:为什么你的任务在「错误的小时」触发
作者:Safe Local Tools 编辑组
定时任务没有「随机坏掉」——多半是按 UTC 跑了,而你心里用的是本地时间。 夏令时拨快一小时、Kubernetes 与 Linux crontab 方言不同、错位的 * 会让清理任务 每分钟 而非每月执行。
本文讲清 cron 字段、时区陷阱、平台差异,以及如何用 Safe Local Tools 在浏览器本地解析,再把表达式送进生产。

Cron 一句话(以及为何没有统一标准)
经典五段:分、时、日、月、周。部分系统加 秒 或 年。字段支持 *、,、-、/ 等。
不存在全球统一的 cron。 Linux crontab、Quartz、AWS EventBridge、Kubernetes CronJob 语法互有增减。跨平台复制粘贴是常见故障源。
UTC 与本地时间:选一个写进文档
服务器常跑 UTC,人脑想 Asia/Shanghai。后果包括:
- 夏令时地区春季 少一小时 的本地时刻
- 秋季 重复一小时 可能跑两次
- 「本地 9 点报表」一年偏两次
最佳实践: 配置存 UTC;界面用 IANA 时区库展示「下次运行」本地时间。
「周几」与「几号」的交互
有的实现把 day-of-month 与 day-of-week 当 OR,有的当 AND。「工作日 9 点」若字段配错,周末仍可能触发——务必打印 未来 N 次 触发时间。
*/5 陷阱
**/5 在「分」字段 = 每 5 分钟**;在「时」字段 = 每 5 小时。新人写 */5 * * * * 想要「五小时一次」,结果任务风暴。
修复: 在 Git 旁写人类可读说明;PR 必审 cron 行。
Kubernetes CronJob 要点
K8s 用标准五段(无秒)。还需注意:
- concurrencyPolicy:
Forbid/Allow/Replace决定重叠行为。 - startingDeadlineSeconds:宕机后可能 跳过 误触发,而非补跑。
- suspend 可暂停而不删 CRD。
用 kubectl create job --from=cronjob/... 做一次性验证,别干等时钟。
Quartz 与企业调度器
Java Quartz 有 ?、英文月份名等;Spring @Scheduled 又可能不同。公司若混用多套调度器,维护 方言对照表。
AWS EventBridge
rate(5 minutes) 与 cron(...) 并存,值班手册要写清用的是哪一种。
夏令时:拨快与拨回
- 春季向前: 不存在的本地时刻要有策略(跳过或顺延)。
- 秋季向后: 一小时重复,可能 双跑——用执行 id 去重。
内部一律 UTC;仅展示层本地化。
监控「静默失败」
建议指标:
last_success_timestamplast_duration_seconds- 超过
2 × 预期间隔无成功则告警
Cron 不响 比吵更危险——数据管道会悄悄过期。
部署前本地测试
- 用与生产 相同方言 解析。
- 打印未来 10 次(UTC + 业务时区)。
- 对照参考站时 确认方言一致(crontab.guru 等未必等于 K8s)。
- 空跑命令,无副作用。
Safe Local Tools 客户端解析——不必把内部调度名贴到公网工具。
文档写法示例
# 日汇总 — 02:15 UTC(美东冬令时约前一日本地)
cron: 15 2 * * *
owner: data-platform
DST 周链接 runbook。
安全:cron 即定时 RCE
控制谁能改 CronJob / crontab;限制 Job 挂载的 Secret 与出站网络。
与业务日历的边界
「每月最后一个工作日」等需求往往超出五段 cron 表达能力,需要日历库或专用调度服务。文档中应标明何时 不应 硬写 cron。
副作用任务的幂等
扣款、发信类任务应用「计划触发时间 + 租户」生成幂等键,避免夏令时回拨导致双跑。
收尾
Cron 出错多是配置,不是玄学。统一方言、内部用 UTC、合并前预览下次运行。
需要预览触发时间又不愿把内部表达式发到第三方时,试用 Cron 表达式解析 →