MySQL的NOW()返回服务器本地时区时间,受system_time_zone和time_zone共同影响,默认跟随系统时区;PostgreSQL的NOW()默认返回事务启动时的UTC时间(timestamptz类型)。
MySQL 的 NOW() 返回的是服务器本地时区时间
你查出来的 now() 值,不是 utc,也不是客户端时区,就是 mysql 服务进程所在操作系统的当前时区时间。它受 system_time_zone 和 time_zone 两个变量共同影响,但默认情况下完全跟随系统时钟和系统时区设置。
常见错误现象:NOW() 和你本地电脑显示时间不一致,或者和应用日志里记录的 UTC 时间差 8 小时(或其它整数小时),就说明时区没对齐。
-
SELECT NOW(), SYSDATE(), UTC_TIMESTAMP();—— 这三个函数行为不同:NOW()和SYSDATE()都返回会话时区时间(默认即系统时区),但SYSDATE()是执行时刻实时取值,NOW()在语句开始时就固定了;UTC_TIMESTAMP()总是返回 UTC 时间,不受任何时区变量影响 - 检查当前会话时区:
SELECT @@session.time_zone;,返回SYSTEM表示用系统时区;返回具体值如'+08:00'或'Asia/Shanghai'则以该时区为准 - 检查系统时区:
SELECT @@global.system_time_zone;,这个值在 MySQL 启动时读取一次,改系统时区后必须重启 MySQL 才生效
PostgreSQL 中 NOW() 默认返回事务启动时的 UTC 时间
和 MySQL 完全相反:PostgreSQL 的 NOW()(等价于 CURRENT_TIMESTAMP)默认返回的是带时区的 UTC 时间戳(timestamptz 类型),且值在事务开始时就确定,不会随系统时间漂移。
使用场景:如果你的应用依赖“统一时间基线”,PostgreSQL 这个行为反而更可靠;但如果你习惯按本地时间写业务逻辑(比如“今天凌晨以来的数据”),直接用 NOW() 可能导致跨时区用户看到不一致结果。
- 想转成北京时间再比较:
NOW() AT TIME ZONE 'Asia/Shanghai' - 确认当前会话时区:
SHOW TIME ZONE;,返回UTC是默认行为;可运行SET TIME ZONE 'Asia/Shanghai';临时切换(仅当前会话) - 注意:即使设了
TIME ZONE,NOW()返回值仍是timestamptz类型,只是显示格式和解释方式变了;底层存储始终是 UTC
如何安全地比对数据库时间与服务器真实时钟
不能只靠 NOW() 输出看一眼,因为终端显示、客户端驱动、连接层都可能做隐式时区转换。真正可靠的比对,得让数据库和系统走同一套时间源,并验证输出是否可逆。
容易踩的坑:用 Python 或 Java 应用连上去查 NOW(),结果被 JDBC/connector 自动转成本地时区,你以为数据库慢了 2 小时,其实是驱动在帮你“修正”。
- 最简验证法:在数据库服务器本机执行
date(Linux/macOS)或time /t(Windows),再立刻连上数据库跑SELECT NOW();,对比两者字符串输出(注意格式统一到秒级) - 排除客户端干扰:用
mysql -h 127.0.0.1 -u root -p --default-character-set=utf8mb4这类原生命令行连接,避免 GUI 工具自动格式化 - 如果发现偏差 > 1 秒:检查服务器 NTP 是否同步(
timedatectl status或ntpq -p),MySQL/PostgreSQL 自身不维护独立时钟,它完全依赖 OS 系统调用
时区配置改错会导致已有数据语义错乱
修改 time_zone 参数不会改变已存数据,但会改变后续所有时间函数的解释逻辑。尤其当字段类型是 DATETIME(MySQL)或 TIMESTAMP WITHOUT TIME ZONE(PostgreSQL)时,问题更隐蔽。
性能影响不大,但兼容性风险极高——同一个 NOW() 插入语句,在不同时区配置下,含义完全不同。
- MySQL 中,
DATETIME类型存的是“字面量”,不带时区信息;TIMESTAMP类型存的是 UTC,读取时按当前time_zone转换显示 —— 所以别轻易把time_zone从SYSTEM改成'+00:00',否则历史TIMESTAMP查询结果全偏了 - PostgreSQL 中,
TIMESTAMP WITHOUT TIME ZONE也是纯字面量;只有TIMESTAMP WITH TIME ZONE(即timestamptz)才真正带时区语义 —— 如果你用now()插入到timestamp字段,等于主动丢弃时区上下文 - 上线前务必确认:ORM 框架(如 Django、Rails、MyBatis)是否强制覆盖了连接时区;有些框架默认设
time_zone=+00:00,和 DBA 设置冲突
NOW() 输出,到底是数据库原始返回值,还是客户端渲染后的结果。连错一个参数,时间就偏掉几小时,而且很难一眼发现。

















