Должен ли MySQL иметь часовой пояс UTC?

149

Дополнительный вопрос /server/191331/should-servers-have-their-timezone-set-to-gmt-utc

Должен ли часовой пояс MySQL быть установлен на UTC или он должен быть таким же, как сервер или PHP? (Если это не UTC)

Каковы плюсы и минусы?

Тимо Хуовинен
источник
stackoverflow.com/a/1650406/175071 приводит веские причины для использования UTC
Тимо Хуовинен,
UTC не является часовым поясом. UTC - это стандарт, GMT - часовой пояс. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev
Еще одна веская причина использовать UTC dba.stackexchange.com/questions/161416/…
Тимо Хуовинен

Ответы:

533

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

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

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

MySQL Часовой пояс Cheatsheet

Ноты:

  1. Изменение часового пояса не изменит сохраненную дату и время , но выберет другую дату и время из столбцов отметки времени.
  2. Предупреждение! UTC имеет високосные секунды, они выглядят как «2012-06-30 23:59:60» и могут быть добавлены случайным образом, с предварительным уведомлением за 6 месяцев, из-за замедления вращения Земли
  3. GMT сбивает с толку секунды, поэтому был изобретен UTC.

  4. Предупреждение! разные региональные часовые пояса могут давать одно и то же значение даты и времени из-за перехода на летнее время

  5. Столбец отметки времени поддерживает только даты с 1970-01-01 00:00:01 до 2038-01-19 03:14:07 UTC из- за ограничения .
  6. Внутренне столбец метки времени MySQL хранится как UTC, но при выборе даты MySQL автоматически преобразует его в текущий часовой пояс сеанса.

    При сохранении даты в метке времени MySQL предполагает, что дата находится в текущем часовом поясе сеанса, и преобразует ее в UTC для хранения.

  7. MySQL может хранить частичные даты в столбцах datetime, они выглядят как «2013-00-00 04:00:00»
  8. MySQL сохраняет «0000-00-00 00:00:00», если для столбца даты и времени задано значение NULL, если только вы специально не задали для столбца разрешение на пустое значение при его создании.
  9. Прочитайте это

Чтобы выбрать столбец отметки времени в формате UTC

независимо от того, в каком часовом поясе находится текущий сеанс MySQL:

SELECT 
CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime` 
FROM `table_name`

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

SELECT `timestamp_field` FROM `table_name`

Чтобы выбрать текущую дату и время в формате UTC:

SELECT UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP;
SELECT CONVERT_TZ(NOW(), @@session.time_zone, '+00:00');

Пример результата: 2015-03-24 17:02:41

Чтобы выбрать текущую дату и время в часовом поясе сеанса

SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_TIMESTAMP();

Чтобы выбрать часовой пояс, который был установлен при запуске сервера

SELECT @@system_time_zone;

Возвращает "MSK" или "+04: 00" для московского времени, например, есть (или была) ошибка MySQL, когда, если задано числовое смещение, она не будет корректировать переход на летнее время

Чтобы узнать текущий часовой пояс

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Он вернется 02:00:00, если ваш часовой пояс +2: 00.

Чтобы получить текущую метку времени UNIX (в секундах):

SELECT UNIX_TIMESTAMP(NOW());
SELECT UNIX_TIMESTAMP();

Чтобы получить столбец отметки времени как отметку времени UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Чтобы получить столбец даты и времени UTC в качестве метки времени UNIX

SELECT UNIX_TIMESTAMP(CONVERT_TZ(`utc_datetime`, '+00:00', @@session.time_zone)) FROM `table_name`

Получить текущую дату и время часового пояса из положительного целого числа UNIX

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Получить дату в формате UTC из метки времени UNIX

SELECT CONVERT_TZ(FROM_UNIXTIME(`unix_timestamp_int`), @@session.time_zone, '+00:00') 
FROM `table_name`

Получить текущую дату и время часового пояса из отрицательного целого числа UNIX

SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND) 

Есть 3 места, где часовой пояс может быть установлен в MySQL:

Примечание: часовой пояс может быть установлен в 2 форматах:

  1. смещение от UTC: «+00: 00», «+10: 00» или «-6: 00»
  2. в качестве названного часового пояса: «Европа / Хельсинки», «США / Восточный» или «MET»

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

в файле "my.cnf"

default_time_zone='+00:00'

или

timezone='UTC'

@@ global.time_zone переменная

Чтобы увидеть, какое значение они установлены

SELECT @@global.time_zone;

Чтобы установить для него значение, используйте один из них:

SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET @@global.time_zone='+00:00';

переменная @@ session.time_zone

SELECT @@session.time_zone;

Чтобы установить его, используйте любой из них:

SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET @@session.time_zone = "+00:00";

«@@ global.time_zone variable» и «@@ session.time_zone variable» могут возвращать «SYSTEM», что означает, что они используют часовой пояс, установленный в «my.cnf».

Чтобы имена часовых поясов работали (даже для часовых поясов по умолчанию), необходимо настроить таблицы данных о часовых поясах, которые необходимо заполнить: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support. HTML

Примечание: вы не можете сделать это, так как он вернет NULL:

SELECT 
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime` 
FROM `table_name`

Настройка таблиц часовых поясов mysql

Чтобы CONVERT_TZработать, вам нужно заполнить таблицы часовых поясов

SELECT * FROM mysql.`time_zone` ;
SELECT * FROM mysql.`time_zone_leap_second` ;
SELECT * FROM mysql.`time_zone_name` ;
SELECT * FROM mysql.`time_zone_transition` ;
SELECT * FROM mysql.`time_zone_transition_type` ;

Если они пусты, заполните их, выполнив эту команду

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

если эта команда выдает ошибку « данные слишком длинные для столбца« аббревиатура »в строке 1 », то это может быть вызвано добавлением символа NULL в конце аббревиатуры часового пояса

исправление заключается в том, чтобы запустить это

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
(if the above gives error "data too long for column 'abbreviation' at row 1")
mysql_tzinfo_to_sql /usr/share/zoneinfo > /tmp/zut.sql

echo "SET SESSION SQL_MODE = '';" > /tmp/mysql_tzinfo_to.sql
cat /tmp/zut.sql >> /tmp/mysql_tzinfo_to.sql

mysql --defaults-file=/etc/mysql/my.cnf --user=verifiedscratch -p mysql < /tmp/mysql_tzinfo_to.sql

(убедитесь, что ваши dst правила сервера обновлены zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Просмотреть полную историю перехода на летнее и летнее время для каждого часового пояса

SELECT 
tzn.Name AS tz_name,
tztt.Abbreviation AS tz_abbr,
tztt.Is_DST AS is_dst,
tztt.`Offset` AS `offset`,
DATE_ADD('1970-01-01 00:00:00',INTERVAL tzt.Transition_time SECOND)  AS transition_date
FROM mysql.`time_zone_transition` tzt
INNER JOIN mysql.`time_zone_transition_type` tztt USING(Time_zone_id, Transition_type_id)
INNER JOIN mysql.`time_zone_name` tzn USING(Time_zone_id)
-- WHERE tzn.Name LIKE 'Europe/Moscow' -- Moscow has weird DST changes
ORDER BY tzt.Transition_time ASC

CONVERT_TZ также применяет любые необходимые изменения DST на основе правил в приведенных выше таблицах и даты, которую вы используете.

Примечание.
Согласно документам значение, установленное для time_zone, не изменится, например, если вы установите его как «+01: 00», тогда time_zone будет установлено как смещение от UTC, которое не следует за DST, поэтому он останется неизменным круглый год.

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

Сокращения как CETвсегда будут зимними и CESTлетними, в то время как +01: 00 всегда будут UTCвременем + 1 час, и оба не будут меняться с переходом на летнее время.

systemЧасовой пояс будет часовой пояс на хост - машине , где установлен MySQL (если MySQL не удается определить его)

Вы можете прочитать больше о работе с DST здесь

связанные вопросы:

Источники:

Тимо Хуовинен
источник
Так что, если у меня установлен тип столбца timestamp. И мой часовой пояс +12: 00, и я хочу обновить столбец, используя дату / время на основе utc, есть ли способ включить часовой пояс в оператор обновления, или я должен использовать convert_tz. Например. tableнабор обновлений modified= '2016-07-07 08:10 +00: 00'
бампербокс
2
@bumperbox mysql всегда предполагает, что дата, в которую вы указываете столбец отметки времени, находится в том же часовом поясе, что и сервер mysql, поэтому вам необходимо преобразовать дату из часового пояса +12: 00 в часовой пояс вашего сервера mysql для обновления. Вот почему я использую UTC на сервере MySQL и конвертирую любую дату в UTC перед ее сохранением.
Тимо Хуовинен
5
Один из лучших, наиболее информативных ответов, с которыми я столкнулся за годы использования SO. Спасибо.
Митя
ПРЕДУПРЕЖДЕНИЕ!!! Любое использование или преобразование из местного времени в часовом поясе DST будет неправильным на час в течение часа каждый год в конце летнего времени. Это влияет UNIX_TIMESTAMP(NOW());также на все ваши случаи использования, CONVERT_TZ()где одним из параметров является `@@ session.time_zone. Для надежного преобразования времени UTC в метки времени UNIX вам, в основном, необходимо сначала установить time_zone сессии.
Doin
1
@ Совершенно верно, я забыл исправить это некоторое время назад.
Тимо Хуовинен
3

Это рабочий пример:

jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow
Tatka
источник
2

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

Прочтите этот учебник: Как синхронизировать ваши часовые пояса PHP и MySQL


источник
Это в основном две строки кода: date_default_timezone_set("America/Los_Angeles");и mysql_query("SET time_zone='" . date('P', time()) . "'");работал очень элегантно!
Нумен
3
@ Нуменон Осторожнее с этим! Сегодня утром я почесал голову, потому что это именно то, чем я занимался, а некоторые мои часы сейчас заканчиваются на час. Я подозреваю, что использование названного часового пояса является более точным, когда задействован DST. Если вы используете America / New_York, MySQL знает о летнем времени и будет правильно хранить даты. Если вы просто установите его на -04: 00, как здесь, он не будет учитывать расчет DST.
Натанб
1
Убедитесь, что mysql знает о DST правильно, правила DST регулярно обновляются и соответствующие таблицы mysql также нуждаются в обновлении (см. Выше в нижней части моего ответа)
Timo Huovinen
1

Плюсы и минусы в значительной степени идентичны. Это зависит от того, хотите вы этого или нет.

Будьте внимательны, если часовой пояс MySQL отличается от вашего системного времени (например, PHP), сравнение времени или печати с пользователем потребует некоторой обработки.

alandarev
источник