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

Дополнительный вопрос https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc

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

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

6 ответов

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

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

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

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

Заметки:

  1. Изменение часового пояса не изменит сохраненную дату и время, но выберет другую дату и время из столбцов отметки времени.
  2. UTC не использует переход на летнее время, GMT (регион) использует, GMT (часовой пояс) не использует (GMT также вводит в заблуждение определение секунд, поэтому был изобретен UTC).
  3. Предупреждение! У UTC есть дополнительные секунды, они выглядят как "2012-06-30 23:59:60" и могут быть добавлены случайным образом, с предварительным уведомлением за 6 месяцев, из-за замедления вращения Земли.
  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, если только вы специально не установили для столбца значение 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/)

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

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 час и оба не изменятся с DST.

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

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

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

Источники:

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

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

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

jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow

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

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

Как насчет того, чтобы ваше приложение не зависело от часового пояса сервера?

По любому из этих возможных сценариев:

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

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

Идея состоит в том, чтобы всегда создавать даты в формате UTC перед их сохранением в базе данных, а также всегда заново создавать их из сохраненных значений в формате UTC. Таким образом, вычисления времени никогда не будут неправильными, потому что они всегда в формате UTC. Этого можно добиться, явно указав DateTimeZone параметр при создании PHP DateTime объект.

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

Например, при сохранении даты в базе данных вместо использования NOW() функция MySQL, создайте строку отметки времени в формате UTC следующим образом:

      // Storing dates
$date = new DateTime('now', new DateTimeZone('UTC'));
$sql = 'insert into table_name (date_column) values ("' . $date . '")';

// Retreiving dates
$sql = 'select date_column from table_name where condition';
$dateInUTC = new DateTime($date_string_from_db, new DateTimeZone('UTC'));

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

Проверить часовой пояс

ВЫБЕРИТЕ @@system_time_zone как System_tz,@@global.time_zone как MYSQL_timeZone, NOW() как timenow_bymysql;

УСТАНОВИТЕ ГЛОБАЛЬНУЮ часовую_зону = '+05:30';

ИЛИ

измените часовой пояс системы, затем перезапустите MariaDB/MYSQL

и снова проверьте часовой пояс

Другие вопросы по тегам