本文约 5,177 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:时间不对会引发一堆怪事
服务器时间不准导致的症状千奇百怪,而且很难联想到是时间问题:
- 设置了”明天 9 点发布”的文章,一直显示”错过计划”(Missed schedule);
- 评论时间显示 8 小时前,其实是刚刚发的;
- 后台「工具 – 站点健康」提示”计划任务未运行”;
- 备份文件名日期错乱,自动清理脚本删错了文件;
- SSL 证书明明没过期却报”证书尚未生效”或”已过期”;
- 阿里云、腾讯云、AWS 的 API 报
SignatureDoesNotMatch; - CDN 缓存刷新接口返回时间戳错误。
后两条尤其关键:云厂商的 API 签名普遍带时间戳,服务器时间偏差超过 15 分钟,所有签名请求都会失败。
原理分析:WordPress 时间的三层来源
第一层:Linux 系统时间
date
# Mon Mar 10 14:30:00 CST 2025
这是最底层,PHP 的 time()、date() 都取自这里。Linux 有两个时钟:
- 系统时钟(System Clock):内核维护的软件时间,开机时从硬件时钟读取;
- 硬件时钟(RTC):主板电池供电的时钟,关机也走,但精度差(一天可能差几秒)。
两者都可能不准。
第二层:PHP 时区
; php.ini
date.timezone = Asia/Shanghai
关键区别:time() 返回的是 UTC 时间戳(与时区无关,全球一致),但 date() 格式化时才应用时区。所以时区设错的表现是”显示差 8 小时”,而不是”时间戳错了”。
第三层:WordPress 时区
后台「设置 – 常规 – 时区」,可选 UTC+8、Asia/Shanghai 等。WordPress 内部一律以 UTC 存储时间戳,显示时按设置转换——所以改时区不会破坏已有数据。
三层的正确关系:
| 层 | 影响范围 | 正确值 |
|---|---|---|
| 系统时间 | 所有程序、日志、证书校验、API 签名 | 准确(时区配置正确) |
| PHP 时区 | date() 输出、插件日志 |
Asia/Shanghai |
| WordPress 时区 | 前台显示、定时发布计算 | Asia/Shanghai 或 UTC+8 |
系统时间是根,它错了其他两层怎么设都没用。
保姆级实操
第一步:检查当前状态
date
sudo hwclock --show
timedatectl
典型输出:
Local time: Mon 2025-03-10 14:30:00 CST
Universal time: Mon 2025-03-10 06:30:00 UTC
RTC time: Mon 2025-03-10 06:30:00
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes ← 关键
NTP service: active ← 关键
RTC in local TZ: no
如果 System clock synchronized: no 或 NTP service: inactive,就是没同步。
timedatectl timesync-status # systemd-timesyncd
chronyc tracking # chrony
ntpstat # 老 ntpd
第二步:设置时区
timedatectl list-timezones | grep -i shanghai
sudo timedatectl set-timezone Asia/Shanghai
date
无 systemd 的老系统:
sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo "Asia/Shanghai" | sudo tee /etc/timezone
第三步:配置 NTP 自动同步
方案 A:systemd-timesyncd(Ubuntu 默认,轻量)
sudo timedatectl set-ntp true
sudo systemctl enable --now systemd-timesyncd
编辑 /etc/systemd/timesyncd.conf:
[Time]
NTP=ntp.aliyun.com time.cloudflare.com pool.ntp.org
FallbackNTP=ntp1.aliyun.com ntp2.aliyun.com
sudo systemctl restart systemd-timesyncd
timedatectl timesync-status
方案 B:chrony(推荐,精度更高,CentOS 默认)
sudo apt install chrony -y # Debian/Ubuntu
sudo dnf install chrony -y # CentOS/Rocky
sudo systemctl enable --now chronyd
编辑 /etc/chrony/chrony.conf:
server ntp.aliyun.com iburst
server ntp1.aliyun.com iburst
server time.cloudflare.com iburst
server ntp.tencent.com iburst
pool pool.ntp.org iburst
# 允许查询的客户端(仅内网服务器需要)
# allow 192.168.0.0/16
# 记录时钟漂移
driftfile /var/lib/chrony/drift
# 启动时如果偏差大于 1 秒,立即步进校正(前 3 次)
makestep 1.0 3
rtcsync
sudo systemctl restart chronyd
chronyc sources -v # 看时间源状态
chronyc tracking # 看偏差
chronyc sources 输出里,行首是 ^* 表示当前正在使用的时间源。
第四步:手动强制同步(偏差大时)
# chrony
sudo chronyc -a makestep
# systemd-timesyncd
sudo systemctl stop systemd-timesyncd
sudo timedatectl set-ntp false
sudo timedatectl set-ntp true
# 老式 ntpdate(需安装)
sudo ntpdate -u ntp.aliyun.com
偏差超过 1000 秒时 NTP 默认不会平滑校正,需要 makestep 强制跳变。
第五步:同步硬件时钟
sudo hwclock --systohc # 系统时间写入硬件时钟
sudo hwclock --show
第六步:配置 PHP 时区
php -i | grep "date.timezone"
如果没有值,编辑 php.ini:
date.timezone = Asia/Shanghai
宝塔面板:软件商店 → PHP 设置 → 配置文件,搜索 date.timezone 修改。
sudo systemctl restart php8.2-fpm
php -r 'echo date("Y-m-d H:i:s T");'
第七步:核对 WordPress 时区
wp option get timezone_string --allow-root
wp option get gmt_offset --allow-root
或后台「设置 – 常规」。推荐用城市名(Asia/Shanghai)而不是 UTC+8,因为城市会自动处理夏令时(虽然中国没有夏令时,但规范上更好)。
命令行设置:
wp option update timezone_string 'Asia/Shanghai' --allow-root
第八步:验证定时发布
# 查看当前的计划任务
wp cron event list --allow-root
# 手动触发一次(看是否正常执行)
wp cron event run --due-now --allow-root
# 查看 WordPress 认为的当前时间
wp eval 'echo current_time("mysql"), " | UTC: ", gmdate("Y-m-d H:i:s");' --allow-root
两个时间应该相差正好 8 小时。如果不是,说明时区配置有问题。
常见踩坑
- Docker 容器时间不同步:容器默认共享宿主机内核时钟,不能在容器里改时间。时区可以通过挂载解决:
yaml
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
environment:
TZ: Asia/Shanghai
时间同步必须在宿主机上做。
- PHP-FPM 缓存了时区:改了 php.ini 没重启 FPM,还是旧的。必须 restart php-fpm,不是 reload。
- 案例:某站定时发布一直失败,显示”错过计划”。排查发现服务器时区是 UTC,WordPress 时区设的是 UTC+8,
wp_next_scheduled计算出的时间戳和实际差 8 小时,cron 判断”还没到”。把系统时区和 PHP 时区统一改成Asia/Shanghai后解决。三层必须一致。 - 虚拟机时间漂移:VMware/KVM 虚拟机的时钟容易漂移(尤其 CPU 负载高时)。VMware 装
open-vm-tools,KVM 用chrony+ptp或启用kvm-clock。虚拟机更应该开 NTP。 - NTP 端口被封:NTP 用 UDP 123。有些云安全组/机房防火墙封了这个端口,导致同步失败。用
chronyc sources看状态是?或x说明不可达。改用 HTTP 时间服务或联系机房。 - “Missed schedule” 的其他原因:即使时间对了,
wp-cron是伪定时任务(靠访问触发),低流量站点也会”错过计划”。真正的解法是关掉 WP-Cron 改用系统 cron:
php
// wp-config.php
define( 'DISABLE_WP_CRON', true );
bash
# 系统 crontab,每 5 分钟触发
*/5 * * * * cd /var/www/mimangfei && wp cron event run --due-now --allow-root > /dev/null 2>&1
- 改时区后历史数据显示错乱:不用担心,数据库存的是 UTC,改时区只影响显示。
总结
时间问题排查顺序:timedatectl 看是否同步 → date 看时区 → php -i 看 PHP 时区 → WordPress 后台看站点时区 → wp eval 对比 current_time 和 gmdate 是否差 8 小时。修好后开 NTP(chrony 优先),把 hwclock --systohc 写入硬件时钟,并把 NTP 状态纳入监控。顺带一提,如果你发现”定时发布不准”,除了时间问题还要确认 WP-Cron 是否正常工作——低流量站建议按上面第 6 条改成系统 cron 驱动。日常巡检可以把时间检查加进WordPress 月度安全巡检清单,而站点健康里的”计划任务”提示正是这个问题的常见表现(另见WordPress 站点健康故障排除模式)。
