Должен ли MySQL иметь часовой пояс UTC?
Дополнительный вопрос https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc
Должен ли часовой пояс MySQL быть установлен на UTC или он должен быть таким же, как сервер или PHP? (Если это не UTC)
Каковы плюсы и минусы?
6 ответов
Кажется, что не имеет значения, какой часовой пояс находится на сервере, если у вас есть время, установленное для текущего часового пояса, вы знаете часовой пояс столбцов даты и времени, которые вы храните, и знаете о проблемах с переходом на летнее время.
С другой стороны, если у вас есть контроль над часовыми поясами серверов, с которыми вы работаете, тогда вы можете настроить внутреннее время на UTC и не беспокоиться о часовых поясах и летнем времени.
Вот некоторые заметки, которые я собрал, о том, как работать с часовыми поясами в виде формы для себя и других, которые могут повлиять на то, какой часовой пояс выберет человек для своего сервера и как он / она будет хранить дату и время.
MySQL Часовой пояс Cheatsheet
Заметки:
- Изменение часового пояса не изменит сохраненную дату и время, но выберет другую дату и время из столбцов отметки времени.
- UTC не использует переход на летнее время, GMT (регион) использует, GMT (часовой пояс) не использует (GMT также вводит в заблуждение определение секунд, поэтому был изобретен UTC).
- Предупреждение! У UTC есть дополнительные секунды, они выглядят как "2012-06-30 23:59:60" и могут быть добавлены случайным образом, с предварительным уведомлением за 6 месяцев, из-за замедления вращения Земли.
- Предупреждение! разные региональные часовые пояса могут давать одно и то же значение даты и времени из-за перехода на летнее время
- Столбец отметки времени поддерживает только даты с 1970-01-01 00:00:01 до 2038-01-19 03:14:07 UTC из- за ограничения.
Внутренне столбец метки времени MySQL хранится как UTC, но при выборе даты MySQL автоматически преобразует его в текущий часовой пояс сеанса.
При сохранении даты в метке времени MySQL предполагает, что дата находится в текущем часовом поясе сеанса, и преобразует ее в UTC для хранения.
- MySQL может хранить частичные даты в столбцах datetime, они выглядят как "2013-00-00 04:00:00"
- MySQL сохраняет "0000-00-00 00:00:00", если для столбца даты и времени задано значение NULL, если только вы специально не установили для столбца значение null при его создании.
- Прочитай это
Чтобы выбрать столбец отметки времени в формате 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 форматах:
- смещение от UTC: "+00:00", "+10:00" или "-6:00"
- в качестве названного часового пояса: "Европа / Хельсинки", "США / Восточный" или "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 здесь
связанные вопросы:
- Как мне установить часовой пояс MySQL?
- MySql - ВЫБРАТЬ столбец TimeStamp в формате UTC
- Как получить метку времени Unix в MySQL от времени UTC?
- Преобразование сервера MySQL TimeStamp в UTC
- https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp
- Как мне узнать текущий часовой пояс MySQL?
- Поля даты и времени MySQL и летнее время - как я могу сослаться на "дополнительный" час?
- Преобразование отрицательных значений из FROM_UNIXTIME
Источники:
- https://bugs.mysql.com/bug.php?id=68861
- http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html
- http://dev.mysql.com/doc/refman/5.1/en/datetime.html
- http://en.wikipedia.org/wiki/Coordinated_Universal_Time
- http://shafiqissani.wordpress.com/2010/09/30/how-to-get-the-current-epoch-time-unix-timestamp/
- https://web.ivy.net/~carton/rant/MySQL-timezones.txt
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
и снова проверьте часовой пояс