约 4 分钟阅读更新于

Cron 定时任务与时区:为什么你的任务在「错误的小时」触发

作者:Safe Local Tools 编辑组

定时任务没有「随机坏掉」——多半是按 UTC 跑了,而你心里用的是本地时间。 夏令时拨快一小时、Kubernetes 与 Linux crontab 方言不同、错位的 * 会让清理任务 每分钟 而非每月执行。

本文讲清 cron 字段、时区陷阱、平台差异,以及如何用 Safe Local Tools 在浏览器本地解析,再把表达式送进生产。

OG illustration

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 用标准五段(无秒)。还需注意:

  • concurrencyPolicyForbid / 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_timestamp
  • last_duration_seconds
  • 超过 2 × 预期间隔 无成功则告警

Cron 不响 比吵更危险——数据管道会悄悄过期。

部署前本地测试

  1. 用与生产 相同方言 解析。
  2. 打印未来 10 次(UTC + 业务时区)。
  3. 对照参考站时 确认方言一致(crontab.guru 等未必等于 K8s)。
  4. 空跑命令,无副作用。

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 表达式解析 →