HOWTO · MySQL

在 MySQL 中设置时区

在本教程中,我们将学习如何在 MySQL 服务器中更改时区。

本页内容

MySQL 时区设置会影响与时区相关的行为,包括 NOW() 和 TIMESTAMP 值的转换;但这不代表所有日期和时间类型(例如 DATETIME)都会按会话时区转换。要选择合适的设置,请先查看全局值和当前会话值,再决定更改是否需要在服务器重启后继续生效、是否应应用于新连接,还是只影响当前连接。如果 MySQL 中有相应的时区数据,像 Europe/Budapest 这样的命名时区可以使用夏令时规则;数字偏移量则是固定值,不包含这些规则。

查看 MySQL 中的当前时区

NOW() 返回按当前会话时区计算的当前日期和时间。仅凭这个值无法确定已配置的时区;还应查看全局设置和会话设置:

SELECT NOW(), @@GLOBAL.time_zone, @@SESSION.time_zone, @@system_time_zone;

@@GLOBAL.time_zone 是服务器范围内的默认值,用于初始化连接的会话设置。@@SESSION.time_zone 是当前连接使用的值,可能与全局值不同。如果其中任一设置为 SYSTEM,MySQL 就会在该作用范围内使用操作系统的时区。system_time_zone 报告服务器检测到的系统时区名称;它不表示通过 MySQL 设置选择的命名时区。

更改设置前,应结合这些值进行判断。如果会话设置与全局设置不同,修改服务器默认值不会改变已分配给现有连接的时区。

在 MySQL 配置中设置默认时区

若要让默认时区在服务器重启后继续生效,请在 MySQL 服务器配置中设置 default-time-zone。找到当前安装所使用的配置文件,然后在该文件的 [mysqld] 部分添加设置。例如,default-time-zone = "+00:00" 会选择固定的 UTC 偏移量。配置文件的位置和服务名称因操作系统及安装方式而异,请使用适用于当前环境的文件路径和重启流程。

如果文件中没有 [mysqld] 部分,请先添加该部分,再添加设置。重启 MySQL 服务后,配置更改才会生效。重启并不能让某个地区的时区选择更持久:如果需要使用会随时间变化的夏令时规则,并且服务器有相应的时区数据,请改用命名时区。

在运行时更改全局时区

运行时更改全局设置会更新服务器的全局 time_zone 值,无须编辑配置文件。例如,SET GLOBAL time_zone = '+00:00'; 会选择固定的 UTC 偏移量。如果 MySQL 时区表中有相应数据,也可以通过 SET GLOBAL time_zone = 'Europe/Budapest'; 设置命名时区。

该设置会影响分配给新连接的默认值,但不会更改已经打开的连接的会话设置;它也不是持久的配置更改,服务器重启后会恢复为配置文件中的默认值。操作人员必须具有更改全局变量所需的访问权限;具体要求可能因 MySQL 版本和环境而异。

如果需要固定偏移量,数字偏移量很有用。不要将某个地区的偏移量作为命名时区的永久替代方案:一个地区的偏移量可能在一年中发生变化,而 -04:00 这样的固定值不包含夏令时规则。

为当前会话设置时区

如果只需让当前连接以不同方式解释时间,请为该连接设置 time_zone。例如,SET time_zone = '+00:00'; 会将会话时区设为固定的 UTC 偏移量。如果要使用某个地区的规则,可以设置受支持的命名值,例如 SET time_zone = 'Europe/Budapest';。

此时,@@SESSION.time_zone 会反映当前连接的值,而 @@GLOBAL.time_zone 保持不变。更改只在该连接的生命周期内有效,并非持续到服务器重启为止。新连接会从当前全局设置初始化自己的会话值,除非该连接另行更改会话值。

排查命名时区和夏令时问题

如果指定 Europe/Budapest 这样的名称后,MySQL 报告 Unknown or incorrect time zone,服务器可能没有可用的时区表数据,或者这些数据已经过时。数字偏移量不需要查询命名时区,但也无法表示夏令时转换。请检查提供的值,并确认服务器的时区表已根据当前环境完成填充和维护。

请参阅 MySQL 关于填充时区表的文档,了解受支持的操作流程。时区数据可用后,请重新设置命名时区,并在预期的作用范围内检查 @@SESSION.time_zone 和 @@GLOBAL.time_zone。命名时区是否应用夏令时规则,取决于服务器可用的时区数据;本文无法判断某个具体安装中的数据是否为最新版本。