Spec-Zone.ru › MySQL 5.7

5.1.13 Поддержка часовых поясов в MySQL Server

В данном разделе описываются настройки часовых поясов, поддерживаемые MySQL, как загрузить системные таблицы, необходимые для поддержки именованных часовых поясов, как оставаться в курсе изменений часовых поясов и как включить поддержку високосных секунд.

Сведения о настройках часовых поясов в конфигурациях репликации см. в разделе 16.4.1.15 «Репликация и системные функции» и разделе 16.4.1.31 «Репликация и часовые пояса».

  • Переменные часового пояса

  • Заполнение таблиц часовых поясов

  • Отображение изменений часовых поясов

  • Поддержка високосных секунд часового пояса

Переменные часового пояса

MySQL Server поддерживает несколько настроек часовых поясов:

  • Системный часовой пояс сервера. При запуске сервера он пытается определить часовой пояс хост-машины и использует его для установки системной переменной system_time_zone. После этого значение не изменяется.

    Чтобы явно указать системный часовой пояс для MySQL Server при запуске, установите переменную среды TZ перед запуском mysqld. Если вы запускаете сервер с помощью mysqld_safe, его параметр --timezone предоставляет другой способ установки системного часового пояса. Допустимые значения для TZ и --timezone зависят от операционной системы. Обратитесь к документации вашей операционной системы, чтобы узнать допустимые значения.

  • Текущий часовой пояс сервера. Глобальная системная переменная time_zone указывает часовой пояс, в котором сервер работает в данный момент. Начальное значение time_zone равно 'SYSTEM', что означает, что часовой пояс сервера совпадает с системным часовым поясом.

    Примечание

    Если установлено значение SYSTEM, каждый вызов функции MySQL, требующий расчета часового пояса, делает системный вызов библиотеки для определения текущего системного часового пояса. Этот вызов может быть защищён глобальным мьютексом, что приводит к конфликтам.

    Начальное глобальное значение часового пояса сервера можно указать явно при запуске с помощью параметра --default-time-zone в командной строке или использовать следующую строку в файле параметров:

    default-time-zone='timezone'
    

    Если у вас есть привилегия SUPER, вы можете установить глобальное значение часового пояса сервера во время выполнения с помощью следующего оператора:

    SET GLOBAL time_zone = timezone;
    
  • Часовые пояса для каждой сессии. Каждый подключённый клиент имеет свою настройку часового пояса сессии, задаваемую переменной сессии time_zone. Изначально переменная сессии принимает значение из глобальной переменной time_zone, но клиент может изменить свой часовой пояс следующим оператором:

    SET time_zone = timezone;
    

Настройка часового пояса сессии влияет на отображение и хранение значений времени, чувствительных к часовому поясу. Это включает значения, отображаемые функциями, такими как NOW() или CURTIME(), и значения, хранящиеся в и извлекаемые из столбцов TIMESTAMP. Значения для столбцов TIMESTAMP преобразуются из часового пояса сессии в UTC для хранения и из UTC в часовой пояс сессии для извлечения.

Настройка часового пояса сессии не влияет на значения, отображаемые функциями, такими как UTC_TIMESTAMP(), или значения в DATE, TIME, или DATETIME столбцах. Также значения в этих типах данных не хранятся в UTC; часовой пояс применим к ним только при преобразовании из значений TIMESTAMP. Если вам нужна арифметика, зависящая от локали, для DATE, TIME или DATETIME значений, преобразуйте их в UTC, выполните арифметические операции и затем преобразуйте обратно.

Текущие глобальные и сессионные значения часового пояса могут быть получены следующим образом:

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

Значения timezone могут быть заданы в нескольких форматах, ни один из которых не чувствителен к регистру:

  • Как значение 'SYSTEM', указывающее, что часовой пояс сервера совпадает с системным часовым поясом.

  • Как строка, указывающая смещение от UTC в формате [H]H:MM, с префиксом + или -, например, '+10:00', '-6:00' или '+05:30'. Для значений часов меньше 10 можно использовать необязательный ведущий ноль; MySQL добавляет ведущий ноль при хранении и извлечении значения в таких случаях. MySQL преобразует '-00:00' или '-0:00' в '+00:00'.

    Смещение часового пояса должно быть в диапазоне от '-12:59' до '+13:00' включительно.

  • Как имя часового пояса, например, 'Europe/Helsinki', 'US/Eastern', 'MET' или 'UTC'.

    Примечание

    Именованные часовые пояса могут быть использованы только в том случае, если таблицы информации о часовых поясах в базе данных mysql были созданы и заполнены. В противном случае использование именованного часового пояса приводит к ошибке:

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

Заполнение таблиц часовых поясов

В базе данных системы mysql существуют несколько таблиц для хранения информации о часовых поясах (см. раздел 5.3, «База данных системы mysql»). Процедура установки MySQL создаёт таблицы часовых поясов, но не загружает их. Для загрузки используйте следующие инструкции.

Примечание

Загрузка информации о часовых поясах не является однократной операцией, так как информация время от времени меняется. Когда такие изменения происходят, приложения, использующие старые правила, становятся устаревшими, и вам может потребоваться перезагрузить таблицы часовых поясов, чтобы информация, используемая сервером MySQL, была актуальной. См. Сохранение актуальности данных о часовых поясах.

Если ваша система имеет собственную базу данных zoneinfo (набор файлов, описывающих часовые поясы), используйте программу mysql_tzinfo_to_sql для загрузки таблиц часовых поясов. Примерами таких систем являются Linux, macOS, FreeBSD и Solaris. Вероятное расположение этих файлов — каталог /usr/share/zoneinfo. Если в вашей системе нет базы данных zoneinfo, вы можете использовать загружаемый пакет, как описано позже в этом разделе.

Для загрузки таблиц часовых поясов из командной строки передайте путь к каталогу zoneinfo в программу mysql_tzinfo_to_sql и передайте вывод в программу mysql. Например:

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

Команда mysql, показанная здесь, предполагает, что вы подключаетесь к серверу с помощью учетной записи, такой как root, которая имеет права на изменение таблиц в базе данных системы mysql. Измените параметры подключения по мере необходимости.

mysql_tzinfo_to_sql считывает файлы часовых поясов вашей системы и генерирует SQL-запросы на их основе. mysql обрабатывает эти запросы для загрузки таблиц часовых поясов.

mysql_tzinfo_to_sql также может использоваться для загрузки одного файла часового пояса или генерации информации о високосных секундах:

  • Для загрузки одного файла часового пояса tz_file, соответствующего имени часового пояса tz_name, вызовите mysql_tzinfo_to_sql следующим образом:

    mysql_tzinfo_to_sql tz_file tz_name | mysql -u root -p mysql
    

    При таком подходе необходимо выполнить отдельный запрос для загрузки файла часового пояса для каждого именованного пояса, о котором должен знать сервер.

  • Если ваш часовой пояс должен учитывать високосные секунды, инициализируйте информацию о високосных секундах следующим образом, где tz_file — имя файла вашего часового пояса:

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

После выполнения mysql_tzinfo_to_sql перезапустите сервер, чтобы он не продолжал использовать кэшированные данные о часовых поясах.

Если в вашей системе нет базы данных zoneinfo (например, Windows), вы можете использовать пакет, содержащий SQL-запросы, доступный для загрузки на MySQL Developer Zone:

https://dev.mysql.com/downloads/timezones.html
Предупреждение

Не используйте загружаемый пакет часовых поясов, если у вашей системы есть база данных zoneinfo. Используйте утилиту mysql_tzinfo_to_sql вместо этого. В противном случае вы можете вызвать различие в обработке дат и времени между MySQL и другими приложениями на вашей системе.

Чтобы использовать пакет с SQL-запросами для часовых поясов, который вы загрузили, распакуйте его, затем загрузите содержимое распакованного файла в таблицы часовых поясов:

mysql -u root -p mysql < file_name

Затем перезапустите сервер.

Предупреждение

Не используйте загружаемый пакет часовых поясов, содержащий MyISAM таблицы. Он предназначен для более ранних версий MySQL. MySQL 5.7 и более поздние версии используют InnoDB для таблиц часовых поясов. Попытка заменить их таблицами MyISAM приводит к проблемам.

Сохранение актуальности данных о часовых поясах

Когда правила часовых поясов изменяются, приложения, использующие старые правила, устаревают. Для сохранения актуальности необходимо убедиться, что ваша система использует актуальную информацию о часовых поясах. Для MySQL нужно учитывать несколько факторов:

  • Временные настройки операционной системы влияют на значения времени, используемые сервером MySQL, если его часовой пояс установлен на SYSTEM. Убедитесь, что ваша операционная система использует самую последнюю информацию о часовых поясах. Для большинства операционных систем последнее обновление или пакет обновления подготавливает вашу систему к изменениям во времени. Проверьте веб-сайт поставщика вашей операционной системы на наличие обновления, которое устраняет эти изменения.

  • Если вы заменяете системный файл часового пояса /etc/localtime версией, использующей правила, отличающиеся от тех, которые действовали при запуске mysqld, перезапустите mysqld, чтобы он использовал обновлённые правила. В противном случае mysqld может не заметить, когда система изменит время.

  • Если вы используете именованные часовые пояса с MySQL, убедитесь, что таблицы часовых поясов в базе данных mysql актуальны:

    • Если ваша система имеет собственную базу данных zoneinfo, перезагружайте таблицы часовых поясов MySQL всякий раз, когда база данных zoneinfo обновляется.

    • Для систем, у которых нет собственной базы данных zoneinfo, проверьте MySQL Developer Zone на предмет обновлений. При наличии нового обновления загрузите его и используйте для замены содержимого текущих таблиц часовых поясов.

    Инструкции для обоих методов см. в разделе «Заполнение таблиц часовых поясов». mysqld кеширует информацию о часовых поясах, которую ищет, поэтому после обновления таблиц часовых поясов перезапустите mysqld, чтобы убедиться, что он не продолжает выдавать устаревшие данные о часовых поясах.

Если вы не уверены, доступны ли именованные часовые пояса, для использования либо в качестве часового пояса сервера, либо клиентами, устанавливающими свой собственный часовой пояс, проверьте, не пустые ли ваши таблицы часовых поясов. Следующий запрос определяет, содержит ли таблица, содержащая имена часовых поясов, какие-либо строки:

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

Значение ноль указывает на то, что таблица пустая. В этом случае ни одно приложение в настоящее время не использует именованные часовые пояса, и вам не нужно обновлять таблицы (если вы не хотите включить поддержку именованных часовых поясов). Значение, большее нуля, указывает на то, что таблица не пуста и её содержимое доступно для использования в поддержке именованных часовых поясов. В этом случае обязательно перезагрузите таблицы часовых поясов, чтобы приложения, использующие именованные часовые пояса, получали правильные результаты запросов.

Чтобы проверить, правильно ли обновлено ваше приложение MySQL для изменения правил летнего времени, используйте тест, подобный следующему. В примере используются значения, подходящие для изменения DST в 2007 году на 1 час в США 11 марта в 2:00.

Тест использует следующий запрос:

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').

Перед обновлением таблиц часовых поясов вы видите неверный результат, подобный этому:

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

После обновления таблиц вы должны увидеть правильный результат:

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

Поддержка високосных секунд в часовых поясах

Значения високосных секунд возвращаются со временной частью, которая заканчивается :59:59. Это означает, что такая функция, как NOW(), может возвращать одинаковое значение в течение двух или трех последовательных секунд во время високосной секунды. Остаётся справедливым, что буквальные временные значения с временной частью, заканчивающейся :59:60 или :59:61, считаются недопустимыми.

Если необходимо искать значения TIMESTAMP за секунду до високосной секунды, могут быть получены аномальные результаты, если вы используете сравнение со значениями 'YYYY-MM-DD hh:mm:ss'. Следующий пример демонстрирует это. Он изменяет часовой пояс сессии на UTC, так что нет разницы между внутренними значениями TIMESTAMP (которые находятся в UTC) и отображаемыми значениями (которые имеют применённую коррекцию часового пояса).

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, хранящемся в столбце, с применённой поправкой на высокосную секунду:

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)

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/time-zone-support.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API