时区设置:日志时间别乱

VPS时区设不对,日志时间、定时任务全乱套。小够讲清楚UTC和本地时区怎么选,timedatectl设置方法,以及Docker和应用的时区坑。

我是小够。今天聊一个小到经常被忽略、大到能坑你半天的问题:VPS 的时区设置。日志里的时间对不上、定时任务半夜不执行,十有八九是时区在作怪。

为什么时区重要

三个地方直接依赖系统时区:

  1. 日志时间戳:排查问题看日志,日志时间是错的,你根本对不上"用户反馈 21:00 出问题"到底对应哪行日志。
  2. 定时任务(cron):cron 按系统时间执行。系统是 UTC 时间,你以为的"每天凌晨 3 点备份",实际是北京时间 11 点——正好是业务高峰。
  3. 证书和会话有效期:SSL 证书、登录 token 的有效期校验都和时间相关,时间错乱会导致诡异的登录失败。

新机器默认时区通常是 UTC(有些商家是机房当地时间),第一件事就是把它设成你想要的。

设置方法:一行命令

timedatectl set-timezone Asia/Shanghai

执行完 date 看一眼,显示 CST(中国标准时间)就是成功了。想看所有可用时区:timedatectl list-timezones | grep -i shanghai。

改时区不需要重启,立即生效。但已经在跑的程序(比如 Java 应用)可能缓存了旧时区,改完最好重启一下关键服务。

UTC 还是本地时间:怎么选

这是个有争议的话题,小够的建议分场景:

面向国内业务、团队都在国内:设 Asia/Shanghai。日志时间就是你手表的时间,排查问题不用心算时差,cron 写"3 点备份"就是凌晨 3 点。对中小团队来说,可读性压倒一切。

国际化业务、多时区团队:用 UTC。UTC 是全球统一的"普通话",跨国协作、写技术文档、和云厂商工单沟通都用 UTC,避免" 你说的 3 点是哪个 3 点"的混乱。应用层再按用户时区展示。

怎么选都不亏的底线:一台机器一个标准,别混用。最怕的是:系统 UTC、数据库 Shanghai、应用又写死了一个时区,三层各说各话,查问题查到怀疑人生。

NTP 时间同步:别漏了

时区对了,时间准不准是另一回事。VPS 的系统时钟会慢慢漂移,要用 NTP 保持同步。Debian/Ubuntu 上:

timedatectl set-ntp true

然后 timedatectl status 确认 NTP synchronized: yes。云厂商一般都有内网 NTP,延迟低,优先用。时间漂移超过几分钟,HTTPS 握手、API 签名都可能失败——别小看这行命令。

三个常见的时区坑

坑一:Docker 容器时区。 容器默认是 UTC,不管宿主机设的什么。解决办法:启动时挂载宿主机的时区文件 -v /etc/localtime:/etc/localtime:ro,或者在 Dockerfile 里设 ENV TZ=Asia/Shanghai。日志对不上时,先查容器时区。

坑二:数据库时区。 MySQL 的 time_zone 默认是 SYSTEM(跟系统),但有些云数据库默认 UTC。建表用 TIMESTAMP 还是 DATETIME,行为还不一样。建站初期就把这事定下来,别等数据乱了再改。

坑三:应用层写死时区。 PHP 的 date.timezone、Python 的 naive datetime、Node 的 moment 时区……应用和系统时区不一致,表现就是"数据库里存的时间和页面显示的时间差 8 小时"。排查顺序:应用配置 → 数据库 → 系统,一层层看。

cron 和时区的小技巧

写 cron 任务时,在注释里写明时区,比如:

# 每天凌晨3点(Asia/Shanghai)备份数据库
0 3 * * * /root/backup.sh

半年后你自己回来看,一眼就知道当初定的什么时间。跨时区的团队协作,这个注释能省掉无数扯皮。

各发行版设置方法

上面讲的是 Debian/Ubuntu(timedatectl)。其他发行版:

  • CentOS/Rocky/AlmaLinux:同样用 timedatectl set-timezone Asia/Shanghai,systemd 系通用。
  • Alpine:默认没装 tzdata,先 apk add tzdata,再 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime。
  • 老式 SysV 系统:直接 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime。2026 年了,这种系统建议直接换掉。

chrony vs systemd-timesyncd:用哪个

时间同步有两个主流方案:

  • systemd-timesyncd:轻量,timedatectl set-ntp true 开的就是它。个人 VPS 完全够用。
  • chrony:更精确,断网重连后追时更快,适合对时间敏感的业务(金融、分布式系统)。

小够的建议:个人建站、学习机用 timesyncd,零配置;跑生产业务、集群的,装 chrony。检查同步状态:timedatectl status 看 NTP synchronized,或者 chronyc tracking(chrony 用户)。

应用层时区配置实例

系统时区设对了,应用层还要逐个确认:

PHP:php.ini 里 date.timezone = Asia/Shanghai,php -i | grep timezone 验证。WordPress 用户注意:WP 后台还有个时区设置,选"上海"就行。

MySQL:SHOW VARIABLES LIKE '%time_zone%'; 看当前值。想全局设上海时间:SET GLOBAL time_zone = '+08:00';,配置文件里写 default-time-zone='+08:00' 永久生效。

Nginx 日志:默认跟系统时区走,系统对了它就对了。access_log 时间对不上,先查系统时区。

Python:naive datetime 不带时区,最容易出 bug。新项目一律用 aware datetime(带 tzinfo),存 UTC、展示转本地,这是最佳实践。

Node.js:默认跟系统时区,但 Docker 里默认 UTC——容器时区坑,前面讲过,启动时挂载 /etc/localtime。

夏令时的提醒

中国不实行夏令时,但你的业务可能涉及实行夏令时的地区(美国、欧洲)。用 Asia/Shanghai 不用管这个;用 UTC 的,应用层展示时要按用户所在地转换,库(比如 moment-timezone、pytz)会自动处理夏令时切换。手动加减小时数迟早会错,别这么干。

一个真实的排查案例

小够见过的一个经典事故:某站长的备份脚本设的是"每天凌晨 3 点",结果备份总是在中午执行,拖慢了网站。排查过程:

  1. date 一看,系统是 UTC——凌晨 3 点 UTC = 北京时间 11 点。
  2. cron 写的是 0 3 * * *,按系统时间执行,没毛病。
  3. 站长以为的"3 点"是北京时间,机器执行的"3 点"是 UTC。

解决:timedatectl set-timezone Asia/Shanghai,问题消失。教训:新机器到手第一件事就是对时区,初始化清单里永远要有这一项。

日志集中收集:时区统一是前提

机器一多,日志要集中收集(ELK、Loki 这些),时区不统一就是灾难:A 机器 Shanghai、B 机器 UTC,查一次故障要对两套时间。规范很简单:

  1. 所有机器统一时区:要么全 Shanghai,要么全 UTC,二选一。小够建议国内业务全 Shanghai,简单直接。
  2. 日志统一存 UTC 时间戳:应用打日志用 UTC 时间戳(数字,不含时区歧义),展示时再转本地。这是大厂的标准做法。
  3. NTP 全部开启:机器之间时间差超过 1 分钟,分布式追踪就全乱了。每台机器 timedatectl status 确认同步。

跨时区协作:写死规则

团队有人在国内、有人在国外,约时间、排期全是坑。定三条铁律:

  • 所有排期写 UTC+8 并标注:比如"周五 15:00(UTC+8)上线",别只写"周五下午3点"。
  • cron 注释写时区:前面讲过,再强调一次——半年后的你会感谢现在的你。
  • 故障复盘用时间线:复盘文档里的时间统一换算成 UTC+8,别让看文档的人做数学题。

Windows VPS 的时区设置

跑 Windows Server 的 VPS,时区在"设置 → 时间和语言 → 时区"里改,选"(UTC+08:00)北京"。改完注意两点:

  1. 时间同步服务:Windows 默认和 time.windows.com 同步,国内连这个源可能慢,换成国内 NTP(比如阿里云、腾讯云的 NTP)更快更稳。
  2. 计划任务:Windows 的任务计划程序和 Linux cron 一样,按系统时间执行,时区错了任务就错。改完时区,把关键任务的时间检查一遍。

时区改了,历史日志怎么办

时区一切换,历史日志的时间戳不会跟着变——以前的日志还是旧时区的时间。这会导致"切换点前后"的日志时间对不上。处理办法:

  • 短期:在日志分析时记住切换时间点,手动换算。
  • 长期:日志统一存 UTC 时间戳(前面讲过),展示层再转换,一劳永逸。

另外,数据库里已经存的时间数据,时区切换后不会自动重算。如果业务对时间敏感,切换前先备份,切换后抽查几条数据确认。

一句话总结

时区设置三步:timedatectl set-timezone 设对时区、set-ntp true 保证走时准确、全栈统一标准别混用。国内业务直接 Asia/Shanghai,简单可读;容器、数据库、应用层逐层检查。日志时间对得上,排查问题少掉一半头发。