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_filetz_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:
Не используйте загружаемый пакет часовых поясов, если у вашей системы есть база данных 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 за секунду до високосной секунды, могут быть получены аномальные результаты, если вы используете сравнение со значениями '. Следующий пример демонстрирует это. Он изменяет часовой пояс сессии на UTC, так что нет разницы между внутренними значениями YYYY-MM-DD
hh:mm:ss'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.