MySQL 时区与 serverTimezone
TL;DR 手动为 MySQL 指定非偏移量的时区,以避免 TIMESTAMP 类型夏令时问题和时区转化性能瓶颈 TIMESTAMP 范围:‘1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ 连接 MySQL 数据库时,serverTimezone 参数用于指定数据库服务器的时区,需要设置为与 MySQL 服务端相同的时区 MySQL 时区设置影响 TIMESTAMP 类型数据和部分时间函数 MySQL 会话时区设置会影响 TIMESTAMP 和 时间函数(NOW()、CURDATE()、CURTIME()、CURRENT_TIMESTAMP()) 存储 TIMESTAMP 类型数据时,MySQL 会根据当前会话的时区将时间转换为 UTC 时间,MySQL 实际存储的是 UTC 时间。检索时 MySQL 根据会话的时区将存储的 UTC 时间转换为会话对应时区的时间。而 DATETIME 类型的字段存储的时间值是原始值,不受时区影响 MySQL 默认使用 SYSTEM 时区(即操作系统的时区),每个需要时区计算的 MySQL 函数调用都会调用系统库来确定当前系统时区。此调用可能受到全局互斥体的保护,从而导致争用,建议显式设置时区 查询当前时区 # time_zone:MySQL 使用 SYSTEM 的时区 # system_time_zone:SYSTEM 为 CST 时区 show variables like "%time_zone%"; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | SYSTEM | +------------------+--------+ 不同会话时区对 时间函数 的影响 # 当前时区 # 查看当前的全球和会话时区值 SELECT @@GLOBAL.time_zone, @@SESSION.time_zone; SELECT NOW(), CURDATE(), CURTIME(), CURRENT_TIMESTAMP(); set time_zone = 'America/New_York'; SELECT NOW(), CURDATE(), CURTIME(), CURRENT_TIMESTAMP(); 不同会话时区对 TIMESTAMP 类型的影响 # UTC +8 set time_zone = 'Asia/Shanghai'; CREATE TABLE events ( id INT AUTO_INCREMENT PRIMARY KEY, event_name VARCHAR(255) NOT NULL, event_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, event_datetime DATETIME DEFAULT CURRENT_TIMESTAMP ); INSERT INTO events (event_name, event_timestamp, event_datetime) VALUES ('10.24 15:45:00', '2022-10-24 15:45:00', '2022-10-24 15:45:00'); INSERT INTO events (event_name, event_timestamp, event_datetime) VALUES ('12.24 15:45:00', '2022-12-24 15:45:00', '2022-12-24 15:45:00'); SELECT * FROM events; +----+----------------+---------------------+---------------------+ | id | event_name | event_timestamp | event_datetime | +----+----------------+---------------------+---------------------+ | 1 | 10.24 15:45:00 | 2022-10-24 15:45:00 | 2022-10-24 15:45:00 | | 2 | 12.24 15:45:00 | 2022-12-24 15:45:00 | 2022-12-24 15:45:00 | +----+----------------+---------------------+---------------------+ 2 rows in set (0.00 sec) # 仅修改当前会话的时区 set time_zone = 'America/New_York'; SELECT * FROM events; +----+----------------+---------------------+---------------------+ | id | event_name | event_timestamp | event_datetime | +----+----------------+---------------------+---------------------+ | 1 | 10.24 15:45:00 | 2022-10-24 03:45:00 | 2022-10-24 15:45:00 | <- 夏令时,相差 12 小时 | 2 | 12.24 15:45:00 | 2022-12-24 02:45:00 | 2022-12-24 15:45:00 | <- 平时相差 13 小时 +----+----------------+---------------------+---------------------+ 2 rows in set (0.00 sec) 纽约 UTC 时差通常为 UTC-5(EST),夏令时为 UTC-4(EDT),所以将原本的会话从上海(UTC+8) 转到纽约时,TIMESTAMP 相差了 13 或 12(夏令时) 小时,所以为了自动转换夏令时,指定时区最好使用时区名词 Asia/Shanghai,避免使用偏移量:'+08:00' ...