from_unixtime 默认按 mysql 服务器当前 time_zone 系统变量解释时间戳,不感知时区;其输出时区即 session.time_zone 值,如 +00:00 或 +08:00,非固定 utc 或本地时区。

FROM_UNIXTIME 默认输出什么时区?
FROM_UNIXTIME 函数本身不感知时区,它只是把传入的 Unix 时间戳(秒数)按 MySQL 服务器当前的 time_zone 系统变量解释后转成 datetime。也就是说,FROM_UNIXTIME(1717027200) 输出什么时间,完全取决于你连接的 MySQL 实例当前的 time_zone 设置——可能是 +00:00,也可能是 +08:00,甚至 SYSTEM(即系统本地时区)。
想指定输出时区,必须先改会话时区
MySQL 没有类似 FROM_UNIXTIME(timestamp, '%Y-%m-%d', '+09:00') 这样的内置时区参数。要让结果按目标时区显示,得在调用前临时切换当前会话的时区:
- 用
SET time_zone = '+09:00';切到东京时区,再执行FROM_UNIXTIME(1717027200),结果就是2024-05-31 09:00:00 - 用
SET time_zone = 'Asia/Shanghai';(需系统支持命名时区且已加载),效果等同于+08:00 - 切完记得恢复?不需要自动恢复,但要注意:该设置只对当前连接有效,断开重连就回到默认值
为什么不能直接在 FROM_UNIXTIME 里加时区偏移?
因为 FROM_UNIXTIME 的第二个参数仅接受格式化字符串(如 '%Y-%m-%d %H:%i'),不接受时区信息。如果你强行写成 FROM_UNIXTIME(1717027200, '%Y-%m-%d %H:%i %T %Z'),%Z 会输出空或乱码——MySQL 不从函数内部推导时区名,它只按当前 time_zone 解释时间戳,再套格式。
常见误操作:
- 以为
CONVERT_TZ(FROM_UNIXTIME(ts), '+00:00', '+08:00')能绕过问题 → 错,FROM_UNIXTIME先按当前时区解释,可能已错一步 - 在 UTC 存储时间戳、却用
SET time_zone = '+08:00'后查,结果看似“正确”,实则掩盖了逻辑混乱:你本应统一用 UTC 处理,不该依赖会话时区漂移
更稳妥的做法:用 CONVERT_TZ + UNIX_TIMESTAMP 配合
如果业务明确要求“把某个 UTC 时间戳转成上海时间显示”,推荐跳过 FROM_UNIXTIME,直接用:
SELECT CONVERT_TZ(FROM_UNIXTIME(1717027200, '+00:00'), '+00:00', '+08:00');
但注意:FROM_UNIXTIME(..., '+00:00') 是 MySQL 8.0.19+ 才支持的可选时区参数(仅用于指定输入时间戳的原始时区),不是输出控制。真正可控的是 CONVERT_TZ:
-
CONVERT_TZ(utc_datetime, '+00:00', '+08:00')—— 把已知是 UTC 的 datetime 转为东八区 - 所以完整链路是:
CONVERT_TZ(FROM_UNIXTIME(1717027200), @@session.time_zone, '+08:00'),前提是你知道当前会话时区是什么 - 最稳的写法其实是:
CONVERT_TZ(FROM_UNIXTIME(1717027200, '+00:00'), '+00:00', '+08:00'),显式声明输入是 UTC,避免会话时区干扰
别忘了检查 mysql.time_zone_name 表是否存在,否则命名时区(如 'Asia/Shanghai')会报错。











