文档首页
MySQL 8.4 参考手册
8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

MySQL 8.4 参考手册 / 7 MySQL 服务器管理 / 7.1 MySQL 服务器 / 7.1.15 MySQL 服务器时区支持
中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

7.1.15 MySQL 服务器时区支持7.1.15 MySQL Server Time Zone Support

本节描述了 MySQL 所维护的时区设置,如何加载支持命名时区所需的系统表,如何保持时区更新,以及如何启用闰秒支持。This section describes the time zone settings maintained by MySQL, how to load the system tables required for named time support, how to stay current with time zone changes, and how to enable leap-second support.

插入的日期时间值也支持时区偏移;有关更多信息,请参阅 第 13.2.2 节,“日期、日期时间和时间戳类型”。Time zone offsets are also supported for inserted datetime values; see Section 13.2.2, “The DATE, DATETIME, and TIMESTAMP Types”, for more information.

有关复制设置中的时区设置的信息,请参阅 第 19.5.1.14 节,“复制和系统函数” 和 第 19.5.1.33 节,“复制和时区”。For information about time zone settings in replication setups, see Section 19.5.1.14, “Replication and System Functions” and Section 19.5.1.33, “Replication and Time Zones”.

时区变量Time Zone Variables

MySQL 服务器维护多个时区设置:MySQL Server maintains several time zone settings:

  • 服务器系统时区。当服务器启动时,它会尝试确定主机的时区,并使用该时区设置system_time_zone系统变量。The server system time zone. When the server starts, it attempts to determine the time zone of the host machine and uses it to set the system_time_zone system variable.

    要在启动 MySQL 服务器时显式指定系统时区,请在启动 mysqld 之前设置 TZ 环境变量。如果使用 mysqld_safe 来启动服务器,其 --timezone 选项提供了另一种设置系统时区的方法。TZ 和 --timezone 的允许值依赖于系统。请查阅您的操作系统文档以了解可接受的值。To explicitly specify the system time zone for MySQL Server at startup, set the TZ environment variable before you start mysqld. If you start the server using mysqld_safe, its --timezone option provides another way to set the system time zone. The permissible values for TZ and --timezone are system dependent. Consult your operating system documentation to see what values are acceptable.

  • 服务器当前的时区。全局 time_zone 系统变量表示服务器当前正在使用的时区。初始 time_zone 值为 'SYSTEM',这表明服务器时区与系统时区相同。The server current time zone. The global time_zone system variable indicates the time zone the server currently is operating in. The initial time_zone value is 'SYSTEM', which indicates that the server time zone is the same as the system time zone.

    Note

    如果设置为 SYSTEM,每个需要进行时区计算的 MySQL 函数调用都会调用系统库以确定当前的系统时区。此调用可能受到全局互斥锁保护,从而导致竞争。If set to SYSTEM, every MySQL function call that requires a time zone calculation makes a system library call to determine the current system time zone. This call may be protected by a global mutex, resulting in contention.

    可以在启动时通过命令行中的 --default-time-zone 选项显式指定初始全局服务器时区值,或者可以在选项文件中使用以下行:The initial global server time zone value can be specified explicitly at startup with the --default-time-zone option on the command line, or you can use the following line in an option file:

    default-time-zone='timezone'
    

    如果您拥有 SYSTEM_VARIABLES_ADMIN 权限(或已弃用的 SUPER 权限),您可以在运行时使用以下语句设置全局服务器时区值:If you have the SYSTEM_VARIABLES_ADMIN privilege (or the deprecated SUPER privilege), you can set the global server time zone value at runtime with this statement:

    SET GLOBAL time_zone = timezone;
    
  • 每个会话的时区。每个连接的客户端都有自己的会话时区设置,由会话 time_zone 变量提供。最初,会话变量的值取自全局 time_zone 变量,但客户端可以使用以下语句更改自己的时区:Per-session time zones. Each client that connects has its own session time zone setting, given by the session time_zone variable. Initially, the session variable takes its value from the global time_zone variable, but the client can change its own time zone with this statement:

    SET time_zone = timezone;
    

会话时区设置会影响时区敏感的时间值的显示和存储。这包括诸如 NOW() 或 CURTIME() 这样的函数显示的值,以及存储在 TIMESTAMP 列中并从中检索的值。TIMESTAMP 列的值在存储时会从会话时区转换为 UTC,在检索时会从 UTC 转换为会话时区。The session time zone setting affects display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), and values stored in and retrieved from TIMESTAMP columns. Values for TIMESTAMP columns are converted from the session time zone to UTC for storage, and from UTC to the session time zone for retrieval.

会话时区设置不会影响诸如 UTC_TIMESTAMP() 之类函数显示的值,也不会影响 DATE、TIME 或 DATETIME 列中的值。这些数据类型中的值也不会以 UTC 存储;时区仅在从 TIMESTAMP 值转换时才适用。如果您希望对 DATE、TIME 或 DATETIME 值进行基于本地的运算,请先将它们转换为 UTC,执行运算,然后再转换回本地时间。The session time zone setting does not affect values displayed by functions such as UTC_TIMESTAMP() or values in DATE, TIME, or DATETIME columns. Nor are values in those data types stored in UTC; the time zone applies for them only when converting from TIMESTAMP values. If you want locale-specific arithmetic for DATE, TIME, or DATETIME values, convert them to UTC, perform the arithmetic, and then convert back.

当前的全局和会话时区值可以这样获取:The current global and session time zone values can be retrieved like this:

SELECT @@GLOBAL.time_zone, @@SESSION.time_zone;

timezone 值可以以几种格式给出,且不区分大小写:timezone values can be given in several formats, none of which are case-sensitive:

  • 作为值 'SYSTEM',表示服务器时区与系统时区相同。As the value 'SYSTEM', indicating that the server time zone is the same as the system time zone.

  • 作为一个字符串,表示与 UTC 的偏移量,格式为 [H]H:MM,前缀为 + 或 -,例如 '+10:00'、'-6:00' 或 '+05:30'。小时值小于 10 时,可选择性地使用前导零;在这种情况下,MySQL 在存储和检索值时会自动加上前导零。MySQL 会将 '-00:00' 或 '-0:00' 转换为 '+00:00'。As a string indicating an offset from UTC of the form [H]H:MM, prefixed with a + or -, such as '+10:00', '-6:00', or '+05:30'. A leading zero can optionally be used for hours values less than 10; MySQL prepends a leading zero when storing and retrieving the value in such cases. MySQL converts '-00:00' or '-0:00' to '+00:00'.

    该值必须在 '-13:59' 到 '+14:00' 的范围内(含)。This value must be in the range '-13:59' to '+14:00', inclusive.

  • 作为一个命名的时区,例如 'Europe/Helsinki'、'US/Eastern'、'MET' 或 'UTC'。As a named time zone, such as 'Europe/Helsinki', 'US/Eastern', 'MET', or 'UTC'.

    Note

    只有在 mysql 数据库中的时区信息表已经创建并填充后,才能使用命名时区。否则,使用命名时区将导致错误:Named time zones can be used only if the time zone information tables in the mysql database have been created and populated. Otherwise, use of a named time zone results in an error:

    mysql> SET time_zone = 'UTC';
    ERROR 1298 (HY000): Unknown or incorrect time zone: 'UTC'
    

填充时区表Populating the Time Zone Tables

mysql 系统模式中存在几个表用于存储时区信息(参见 7.3 节,“mysql 系统模式”)。MySQL 安装程序会创建时区表,但不会加载它们。要手动加载,请使用以下说明。Several tables in the mysql system schema exist to store time zone information (see Section 7.3, “The mysql System Schema”). The MySQL installation procedure creates the time zone tables, but does not load them. To do so manually, use the following instructions.

Note

加载时区信息不一定是一次性的操作,因为这些信息会偶尔发生变化。当发生此类变化时,使用旧规则的应用程序会变得过时,您可能需要重新加载时区表以保持 MySQL 服务器使用的信息是最新的。请参阅 保持时区信息最新。Loading the time zone information is not necessarily a one-time operation because the information changes occasionally. When such changes occur, applications that use the old rules become out of date and you may find it necessary to reload the time zone tables to keep the information used by your MySQL server current. See Staying Current with Time Zone Changes.

如果您的系统有自己的 zoneinfo 数据库(描述时区的文件集合),请使用 mysql_tzinfo_to_sql 程序来加载时区表。此类系统的例子有 Linux、macOS、FreeBSD 和 Solaris。这些文件的一个可能位置是 /usr/share/zoneinfo 目录。如果您的系统没有 zoneinfo 数据库,您可以使用可下载的包,如本节后面所述。If your system has its own zoneinfo database (the set of files describing time zones), use the mysql_tzinfo_to_sql program to load the time zone tables. Examples of such systems are Linux, macOS, FreeBSD, and Solaris. One likely location for these files is the /usr/share/zoneinfo directory. If your system has no zoneinfo database, you can use a downloadable package, as described later in this section.

要从命令行加载时区表,请将 zoneinfo 目录路径名传递给 mysql_tzinfo_to_sql,并将输出发送到 mysql 程序。例如:To load the time zone tables from the command line, pass the zoneinfo directory path name to mysql_tzinfo_to_sql and send the output into the mysql program. For example:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

这里显示的 mysql 命令假定您使用如 root 这样的帐户连接到服务器,该帐户具有修改 mysql 系统模式中表的权限。根据需要调整连接参数。The mysql command shown here assumes that you connect to the server using an account such as root that has privileges for modifying tables in the mysql system schema. Adjust the connection parameters as required.

mysql_tzinfo_to_sql 读取系统的时区文件并从中生成 SQL 语句。mysql 处理这些语句以加载时区表。mysql_tzinfo_to_sql reads your system's time zone files and generates SQL statements from them. mysql processes those statements to load the time zone tables.

mysql_tzinfo_to_sql 也可以用于加载单个时区文件或生成闰秒信息:mysql_tzinfo_to_sql also can be used to load a single time zone file or generate leap second information:

  • 要加载与时区名称 tz_name 对应的单个时区文件 tz_file,请像这样调用 mysql_tzinfo_to_sql:To load a single time zone file tz_file that corresponds to a time zone name tz_name, invoke mysql_tzinfo_to_sql like this:

    mysql_tzinfo_to_sql tz_file tz_name | mysql -u root -p mysql
    

    使用这种方法,您必须为服务器需要了解的每个命名时区执行单独的命令来加载时区文件。With this approach, you must execute a separate command to load the time zone file for each named zone that the server needs to know about.

  • 如果您的时区需要考虑闰秒,请像这样初始化闰秒信息,其中tz_file是您的时区文件的名称:If your time zone must account for leap seconds, initialize leap second information like this, where tz_file is the name of your time zone file:

    mysql_tzinfo_to_sql --leap tz_file | mysql -u root -p mysql
    

运行mysql_tzinfo_to_sql后,重启服务器以确保不继续使用任何先前缓存的时区数据。After running mysql_tzinfo_to_sql, restart the server so that it does not continue to use any previously cached time zone data.

如果您的系统没有 zoneinfo 数据库(例如 Windows),您可以使用包含 SQL 语句的包,该包可以从 MySQL 开发者专区下载:If your system has no zoneinfo database (for example, Windows), you can use a package containing SQL statements that is available for download at the MySQL Developer Zone:

https://dev.mysql.com/downloads/timezones.html
Warning

执行在多线程系统中如果您的系统有 zoneinfo 数据库,请使用可下载的时区包。请使用mysql_tzinfo_to_sql工具。否则,可能会导致 MySQL 与系统上其他应用程序的日期时间处理出现差异。Do not use a downloadable time zone package if your system has a zoneinfo database. Use the mysql_tzinfo_to_sql utility instead. Otherwise, you may cause a difference in datetime handling between MySQL and other applications on your system.

要使用您已下载的 SQL 语句时区包,请解压它,然后将解压后的文件内容加载到时区表中:To use an SQL-statement time zone package that you have downloaded, unpack it, then load the unpacked file contents into the time zone tables:

mysql -u root -p mysql < file_name

然后重启服务器。Then restart the server.

Warning

执行在多线程系统中使用包含MyISAM表的可下载时区包。这是针对旧版本 MySQL 的。MySQL 现在使用InnoDB来管理时区表。尝试用MyISAM表替换它们会导致问题。Do not use a downloadable time zone package that contains MyISAM tables. That is intended for older MySQL versions. MySQL now uses InnoDB for the time zone tables. Trying to replace them with MyISAM tables causes problems.

保持时区更改的最新状态Staying Current with Time Zone Changes

当时区规则改变时,使用旧规则的应用程序就会过时。为了保持最新,有必要确保您的系统使用当前的时区信息。对于 MySQL,有多个因素需要考虑以保持最新:When time zone rules change, applications that use the old rules become out of date. To stay current, it is necessary to make sure that your system uses current time zone information is used. For MySQL, there are multiple factors to consider in staying current:

  • 操作系统时间会影响 MySQL 服务器使用的时间值,如果其时区设置为 SYSTEM。请确保您的操作系统使用的是最新的时区信息。对于大多数操作系统,最新的更新或服务包可以使系统适应时间的变化。请查看操作系统供应商的网站以获取解决时间变化问题的更新。The operating system time affects the value that the MySQL server uses for times if its time zone is set to SYSTEM. Make sure that your operating system is using the latest time zone information. For most operating systems, the latest update or service pack prepares your system for the time changes. Check the website for your operating system vendor for an update that addresses the time changes.

  • 如果你用一个使用规则与 mysqld 启动时生效的规则不同的版本替换系统的 /etc/localtime 时区文件,请重启 mysqld 以使用更新后的规则。否则,mysqld 可能不会注意到系统时间的变化。If you replace the system's /etc/localtime time zone file with a version that uses rules differing from those in effect at mysqld startup, restart mysqld so that it uses the updated rules. Otherwise, mysqld might not notice when the system changes its time.

  • 如果你在 MySQL 中使用命名时区,请确保 mysql 数据库中的时区表是最新的:If you use named time zones with MySQL, make sure that the time zone tables in the mysql database are up to date:

    • 如果您的系统拥有自己的 zoneinfo 数据库,每当 zoneinfo 数据库更新时,请重新加载 MySQL 时区表。If your system has its own zoneinfo database, reload the MySQL time zone tables whenever the zoneinfo database is updated.

    • 对于没有自己 zoneinfo 数据库的系统,请查看 MySQL 开发者专区的更新。当有新更新可用时,下载它并用其内容替换当前时区表的内容。For systems that do not have their own zoneinfo database, check the MySQL Developer Zone for updates. When a new update is available, download it and use it to replace the content of your current time zone tables.

    有关两种方法的说明,请参见 填充时区表。mysqld 会缓存它查找的时区信息,因此在更新时区表后,请重启 mysqld 以确保它不继续提供过时的时区数据。For instructions for both methods, see Populating the Time Zone Tables. mysqld caches time zone information that it looks up, so after updating the time zone tables, restart mysqld to make sure that it does not continue to serve outdated time zone data.

如果您不确定命名时区是否可用,无论是用作服务器的时区设置还是由设置自己时区的客户端使用,请检查您的时区表是否为空。以下查询可确定包含时区名称的表是否有任何行:If you are uncertain whether named time zones are available, for use either as the server's time zone setting or by clients that set their own time zone, check whether your time zone tables are empty. The following query determines whether the table that contains time zone names has any rows:

mysql> SELECT COUNT(*) FROM mysql.time_zone_name;
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+

计数为零表示表为空。在这种情况下,目前没有应用程序使用命名时区,并且您无需更新表(除非您想启用命名时区支持)。计数大于零表示表不为空,其内容可用于命名时区支持。在这种情况下,请确保重新加载您的时区表,以便使用命名时区的应用程序可以获得正确的查询结果。A count of zero indicates that the table is empty. In this case, no applications currently are using named time zones, and you need not update the tables (unless you want to enable named time zone support). A count greater than zero indicates that the table is not empty and that its contents are available to be used for named time zone support. In this case, be sure to reload your time zone tables so that applications that use named time zones can obtain correct query results.

要检查您的 MySQL 安装是否已正确更新以适应夏令时规则的变化,请使用如下测试。示例中使用的值适用于美国在 2007 年 3 月 11 日凌晨 2 点发生的 1 小时夏令时变化。To check whether your MySQL installation is updated properly for a change in Daylight Saving Time rules, use a test like the one following. The example uses values that are appropriate for the 2007 DST 1-hour change that occurs in the United States on March 11 at 2 a.m.

测试使用以下查询:The test uses this query:

SELECT
  CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central') AS time1,
  CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central') AS time2;

这两个时间值表示夏令时变化发生的时间,并且使用命名时区需要使用时区表。期望的结果是两个查询返回相同的结果(输入时间转换为 'US/Central' 时区的等效值)。The two time values indicate the times at which the DST change occurs, and the use of named time zones requires that the time zone tables be used. The desired result is that both queries return the same result (the input time, converted to the equivalent value in the 'US/Central' time zone).

在更新时区表之前,您会看到如下错误结果:Before updating the time zone tables, you see an incorrect result like this:

+---------------------+---------------------+
| time1               | time2               |
+---------------------+---------------------+
| 2007-03-11 01:00:00 | 2007-03-11 02:00:00 |
+---------------------+---------------------+

更新表之后,您应该会看到正确的结果:After updating the tables, you should see the correct result:

+---------------------+---------------------+
| time1               | time2               |
+---------------------+---------------------+
| 2007-03-11 01:00:00 | 2007-03-11 01:00:00 |
+---------------------+---------------------+

时区闰秒支持Time Zone Leap Second Support

闰秒值返回的时间部分以 :59:59 结尾。这意味着像 NOW() 这样的函数在闰秒期间可能会返回相同的值连续两到三秒。字面时间值的时间部分以 :59:60 或 :59:61 结尾仍然被视为无效。Leap second values are returned with a time part that ends with :59:59. This means that a function such as NOW() can return the same value for two or three consecutive seconds during the leap second. It remains true that literal temporal values having a time part that ends with :59:60 or :59:61 are considered invalid.

如果有必要搜索在闰秒前一秒的 TIMESTAMP 值,如果使用与 'YYYY-MM-DD hh:mm:ss' 值的比较,可能会得到异常的结果。以下示例演示了这一点。它将会话时区更改为 UTC,因此内部 TIMESTAMP 值(以 UTC 表示)与显示值(应用了时区校正)之间没有差异。If it is necessary to search for TIMESTAMP values one second before the leap second, anomalous results may be obtained if you use a comparison with 'YYYY-MM-DD hh:mm:ss' values. The following example demonstrates this. It changes the session time zone to UTC so there is no difference between internal TIMESTAMP values (which are in UTC) and displayed values (which have time zone correction applied).

mysql> CREATE TABLE t1 (
         a INT,
         ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
         PRIMARY KEY (ts)
       );
Query OK, 0 rows affected (0.01 sec)

mysql> -- change to UTC
mysql> SET time_zone = '+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> -- Simulate NOW() = '2008-12-31 23:59:59'
mysql> SET timestamp = 1230767999;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t1 (a) VALUES (1);
Query OK, 1 row affected (0.00 sec)

mysql> -- Simulate NOW() = '2008-12-31 23:59:60'
mysql> SET timestamp = 1230768000;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t1 (a) VALUES (2);
Query OK, 1 row affected (0.00 sec)

mysql> -- values differ internally but display the same
mysql> SELECT a, ts, UNIX_TIMESTAMP(ts) FROM t1;
+------+---------------------+--------------------+
| a    | ts                  | UNIX_TIMESTAMP(ts) |
+------+---------------------+--------------------+
|    1 | 2008-12-31 23:59:59 |         1230767999 |
|    2 | 2008-12-31 23:59:59 |         1230768000 |
+------+---------------------+--------------------+
2 rows in set (0.00 sec)

mysql> -- only the non-leap value matches
mysql> SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:59';
+------+---------------------+
| a    | ts                  |
+------+---------------------+
|    1 | 2008-12-31 23:59:59 |
+------+---------------------+
1 row in set (0.00 sec)

mysql> -- the leap value with seconds=60 is invalid
mysql> SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:60';
Empty set, 2 warnings (0.00 sec)

为了解决这个问题,您可以使用基于列中实际存储的 UTC 值的比较,该值已应用闰秒修正:To work around this, you can use a comparison based on the UTC value actually stored in the column, which has the leap second correction applied:

mysql> -- selecting using UNIX_TIMESTAMP value return leap value
mysql> SELECT * FROM t1 WHERE UNIX_TIMESTAMP(ts) = 1230768000;
+------+---------------------+
| a    | ts                  |
+------+---------------------+
|    2 | 2008-12-31 23:59:59 |
+------+---------------------+
1 row in set (0.00 sec)