应统一所有服务器的时区为Asia/Shanghai,通过启动前设置TZ环境变量(如Docker加-e TZ=Asia/Shanghai、systemd加Environment="TZ=Asia/Shanghai")并重启进程实现;process.env.TZ运行时赋值无效,Intl.DateTimeFormat可手动指定时区做格式化。
为什么 new Date().getTime() 在不同服务器上返回的值会差几分钟
时间戳不一致,往往不是时钟漂移导致的,而是服务器系统时区没对齐,或者 node.js 进程启动时没显式设置时区。比如一台服务器系统时区是 asia/shanghai,另一台是 utc,但你用 new date().gettime() 拿到的是毫秒级时间戳(本质是 utc 时间),看起来一样;可一旦调用 tolocalestring()、gethours() 或依赖 date 构造函数解析字符串(如 new date('2024-05-10')),结果就分道扬镳了。
更隐蔽的问题是:某些 Docker 镜像默认用 UTC,而宿主机是 Asia/Shanghai,容器内没挂载 /etc/localtime 或没设 TZ 环境变量,Node.js 就按 UTC 解析本地时间——这时候连日志打点、定时任务触发、JWT 过期校验都可能出错。
如何让所有服务器上的 Date 行为统一
核心原则:不依赖系统时区,强制进程级时区锁定。Node.js 从 v18 开始支持 --timezone 启动参数,但生产环境更稳妥的做法是启动时设置 TZ 环境变量,并配合代码层兜底。
- 在启动脚本或 systemd service 文件里加:
Environment="TZ=Asia/Shanghai" - Docker 中:启动容器时加
-e TZ=Asia/Shanghai,或在Dockerfile里写ENV TZ=Asia/Shanghai - 验证是否生效:运行
node -e "console.log(new Date().toString())",看输出是否带CST(而非UTC或GMT) - 注意:修改
TZ不影响已运行的进程,必须重启 Node.js 进程
process.env.TZ 设置后,哪些 Date 方法会变化
TZ 环境变量只影响 Date 对象的「本地时间」相关方法,不影响时间戳本身。也就是说:
-
new Date().getTime()、Date.now()、new Date('2024-05-10T12:00:00Z').getTime()始终返回相同值(UTC 毫秒数) -
new Date().getHours()、new Date().toLocaleString()、new Date('2024-05-10').getTime()的结果会随TZ变化 -
new Date('2024-05-10')这种无时区字符串,在不同TZ下会被解释为「当天该时区的午夜」,所以返回的时间戳不同
如果你的应用大量使用字符串构造 Date(比如解析前端传来的 "2024-05-10"),那必须确保所有服务端 TZ 一致,否则同一天的起始时间戳都不一样。
全局初始化时区的坑:别在 require 链里改 TZ
有人想在入口文件顶部写 process.env.TZ = 'Asia/Shanghai',这是无效的。Node.js 的时区逻辑在进程启动时读取 TZ,之后再赋值不会重新初始化 Date 的时区缓存。
真正生效的方式只有两种:
- 启动前通过 shell 环境或容器配置设好
TZ - 用
Intl.DateTimeFormat手动指定时区做格式化(不改变Date本身行为,但可控):new Intl.DateTimeFormat('zh-CN', { timeZone: 'Asia/Shanghai' }).format(new Date())
另外,某些云平台(如 AWS Lambda、Vercel)不支持自定义 TZ,这时只能放弃本地时间方法,全程用 UTC 时间戳 + 显式时区转换,避免隐式依赖。










