PHP项目时间存储必须统一用UTC,所有写入数据库的时间需转为UTC时间戳或ISO 8601 UTC字符串;前端提交须带时区偏移,后端解析后显式转UTC存储;读取时按用户时区动态转换,展示层处理时区,数据层保持UTC。

PHP 项目里时间存储必须用 UTC
多时区团队协作出问题,八成卡在时间存错本地时区。PHP 默认 date_default_timezone_set() 是服务器时区(比如 Asia/Shanghai),一旦有人在纽约 deploy、有人在柏林改代码,time()、new DateTime()、strtotime() 全都会按各自环境跑,数据库里存的可能是混着 UTC、CST、EST 的乱码时间。
解决办法只有一条:所有写入数据库的时间,必须是 UTC 时间戳或 ISO 8601 UTC 字符串(如 "2024-05-20T12:00:00+00:00")。
- 入库前统一转 UTC:
$dt = new DateTime('now', new DateTimeZone('Asia/Shanghai')); $dt->setTimezone(new DateTimeZone('UTC')); - 避免用
date('Y-m-d H:i:s')直接拼字符串——它依赖当前时区设置 - Laravel 用户注意:模型的
$dates或$casts默认不自动转 UTC,得配'datetime:Y-m-d\TH:i:s.uO'并确保APP_TIMEZONE=UTC
前端传时间时要带时区偏移
用户在浏览器选了一个时间(比如 2024-05-20 15:30),JavaScript 的 new Date().toISOString() 会返回带 Z 的 UTC 字符串;但若用 new Date().toLocaleString() 或手动拼,大概率丢偏移,后端一解析就变成服务器本地时间。
后端 PHP 接收时别信 $_POST['time'] 看起来像时间就直接 strtotime() ——它没时区信息,默认按 date_default_timezone_set() 解析,结果错得离谱。
立即学习“PHP免费学习笔记(深入)”;
本文档主要讲述的是Unity3D游戏开发之Asset server服务器搭建;Asset Server是目前unity内部自带的资源版本管理工具,类似于我们平时所熟知的SVN,perForce,但对于目前的Unity,Asset Server要比SVN和perForce等版本控制软件要好用一些,因为Unity3.x版本对于SVN等软件的支持并不是很好,在多人协同工作时,经常会发生数据丢失等情况。因此,本文重点介绍一下Asser Server的搭建方法。至于日常用法,其实与SVN等软件的用法非常相似,所以在
- 前端提交必须用 ISO 8601 带偏移格式,例如
"2024-05-20T15:30:00+02:00"(柏林)或"2024-05-20T09:30:00-04:00"(纽约) - PHP 解析用
new DateTime($input, new DateTimeZone('UTC'))不行,得用new DateTime($input)让它自己识别偏移,再显式转成 UTC 存储 - 如果前端只能传时间戳(毫秒数),那是 Unix 时间戳,本质就是 UTC,PHP 直接
DateTime::createFromFormat('U', $ts / 1000)即可
显示时按用户所在时区动态转换
存是 UTC,读出来就得“翻译”成用户本地时间。不能靠 PHP 输出前临时 set timezone——因为一个请求里可能有多个用户(管理员看报表、客服看工单、用户看自己的订单),时区需求不同。
核心原则:时区转换是展示层逻辑,不是数据层逻辑。
- 把用户时区存在数据库字段(如
users.timezone)或前端传来的 token/headers 里(如X-Timezone: America/New_York) - 显示时间时才转换:
$dt->setTimezone(new DateTimeZone($userTZ)),而不是全局date_default_timezone_set() - API 返回时间字段应明确标注时区,比如返回
"created_at": "2024-05-20T12:00:00Z"(强制 UTC) + 额外字段"created_at_local": "2024-05-20T08:00:00-04:00"(按需计算)
测试和部署时最容易忽略的陷阱
本地开发用 date_default_timezone_set('Asia/Shanghai'),CI/CD 流水线跑在 Ubuntu 容器里默认是 UTC,线上服务器又可能是 America/Los_Angeles ——这些差异不会报错,只会让定时任务、日志时间、缓存过期时间悄悄错位几个小时。
- 所有 PHP 脚本开头加
assert(date_default_timezone_get() === 'UTC');(测试环境启用),或统一在php.ini设date.timezone = UTC - 不要在 CLI 脚本里用
date('Y-m-d')当“今天”,要用(new DateTime('now', new DateTimeZone('UTC')))->format('Y-m-d') - Redis 缓存 key 或过期时间含时间成分时,务必确认是否用了 UTC 时间戳——
Cache::put('report_'.date('Y-m-d'), $data, 3600)在跨时区部署下会失效










