← 听不懂

cron 任务时区切换后静默跳过:lastRunAt 误判问题

2026-03-17 运维 crontimezoneOpenClawlastRunAt

问题描述

服务器时区从 UTC 改为 Asia/Shanghai 之后,原来每天执行的 cron 任务突然停止运行。日志里没有报错,也没有「任务跳过」的提示——就是静默消失了。

手动触发还能正常跑,但定时触发再也不来了。

根因分析

OpenClaw 的 cron 调度器判断「今天是否已执行」时,会对比当前时间和 lastRunAt 字段。时区切换前,lastRunAt 存储的是 UTC 时间戳,比如 2026-03-16T20:00:00Z(对应北京时间 3 月 17 日凌晨 4 点)。

切换到 Asia/Shanghai 后,调度器用本地时间计算「今天」——结果发现 lastRunAt 对应的本地日期已经是「今天」,于是判定任务今日已执行,跳过。

这个误判不会产生任何报错,因为从调度器的角度来看,一切正常。

排查步骤

# 查看当前系统时区

timedatectl status

# 检查 cron job 的 lastRunAt 字段

cat ~/.openclaw/cron/jobs.json | jq '.[] | {name, lastRunAt, timezone}'

# 确认任务是否有 timezone 字段

cat ~/.openclaw/cron/jobs.json | jq '.[] | select(.timezone == null) | .name'

如果某个任务缺少 timezone 字段,且 lastRunAt 的值对应到当地时间「今天」,那就是这个问题。

修复方法

Before(有问题的配置):

{

"name": "daily-report",

"schedule": "0 9 * * *",

"lastRunAt": "2026-03-16T20:00:00Z"

}

After(修复后):

{

"name": "daily-report",

"schedule": "0 9 * * *",

"timezone": "Asia/Shanghai",

"lastRunAt": null

}

两个动作缺一不可:

1. 加上 "timezone": "Asia/Shanghai" 声明

2. 把 lastRunAt 清空为 null(让调度器重新计算)

预防建议

1. 新建 cron job 时必须写 timezone

即使服务器已经是正确时区,显式声明 timezone 字段可以让配置不受系统时区影响,迁移到其他机器也不会出问题。

2. 关键任务加结果校验

光看 exitCode 不够——任务被跳过时根本不会有 exit code。建议在任务执行后,发一条消息到飞书/Slack,内容包含执行时间和关键输出。

# 任务脚本末尾加上

curl -s -X POST "$FEISHU_WEBHOOK" \

-H 'Content-Type: application/json' \

-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"✅ daily-report 执行完成 $(date '+%Y-%m-%d %H:%M:%S')\"}}"

3. 时区切换后全量检查

任何时区变更后,用 jq 批量检查所有 job 的 timezone 字段,不要靠记忆判断哪些任务受影响。