Чи повинен MySQL встановити часовий пояс на UTC?


149

Слідкуйте за питанням /server/191331/should-servers-have-their-timezone-set-to-gmt-utc

Чи слід встановити часовий пояс MySQL на UTC або він повинен бути таким же часовим поясом, що і сервер або PHP? (Якщо це не UTC)

Які плюси і мінуси?


stackoverflow.com/a/1650406/175071 ділиться добрими причинами для використання UTC
Timo Huovinen

UTC - не часовий пояс. UTC - це стандарт, GMT - часовий пояс. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev

Ще одна чудова причина використовувати UTC dba.stackexchange.com/questions/161416/…
Тимо Хуовінен

Відповіді:


533

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

З іншого боку, якщо ви маєте контроль над часовими поясами серверів, з якими працюєте, то ви можете мати все, що встановлено на UTC внутрішньо, і ніколи не турбуватися про часові пояси та DST.

Ось декілька зауважень, які я зібрав про те, як працювати з часовими поясами як формою шпаргалки для себе та інших, які можуть впливати на те, який часовий пояс людина вибере для свого сервера та як він / вона буде зберігати дату та час.

Шпаргалка часових поясів MySQL

Примітки:

  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 може зберігати часткові дати в стовпцях дати, вони виглядають як "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:

Примітка. Часовий пояс можна встановити у двох форматах:

  1. зміщення від UTC: '+00: 00', '+10: 00' або '-6: 00'
  2. як названий часовий пояс: "Європа / Гельсінкі", "США / Схід" або "МЕТ"

Названі часові пояси можна використовувати лише в тому випадку, якщо таблиці даних часового поясу в базі даних 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", і "@@ session.time_zone змінна" можуть повернути "SYSTEM", що означає, що вони використовують часовий пояс, встановлений у "my.cnf".

Щоб імена часових поясів спрацьовували (навіть для часового поясу за замовчуванням), ви повинні налаштувати таблиці даних про часовий пояс, які потрібно заповнити: http://dev.mysql.com/doc/refman/5.1/uk/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

(переконайтеся, що правила домену ваших серверів актуальні 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 година, і обидва не змінюватимуться за DST.

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

Детальніше про роботу з DST ви можете прочитати тут

пов'язані питання:

Джерела:


Тож якщо у мене тип стовпця встановлений на часову позначку. І мій time_zone становить +12: 00, і я хочу оновити стовпчик, використовуючи дату / час, заснований на utc, чи є якийсь спосіб включити часовий пояс у оператор оновлення, чи я повинен використовувати convert_tz. Напр. update tableset modified= '2016-07-07 08:10 +00: 00'
bumperbox

2
@bumperbox mysql завжди передбачає, що дата, якій ви надаєте стовпець часової позначки, знаходиться в тому ж часовому поясі, що і сервер mysql, тому для оновлення вам потрібно перетворити дату з часового поясу +12: 00 у ваш часовий пояс сервера mysql. Ось чому я використовую UTC на сервері mysql і конвертую будь-яку дату в UTC, перш ніж зберігати його.
Тімо Хуовінен

5
Один з найкращих, найінформативніших відповідей, з якими я стикався за роки використання SO. Дякую.
Мітя

УВАГА!!! Будь-яке використання або перетворення місцевого часу в часовому поясі DST буде неправильним щогодини на годину наприкінці літнього часу. Це впливає UNIX_TIMESTAMP(NOW());також на всі ваші використання того, CONVERT_TZ()де одним із параметрів є @ @ session.time_zone. Щоб надійно перетворити дату часу UTC в часові позначки UNIX, вам потрібно спочатку встановити часову зону сеансу.
Зробити

1
@Flimm абсолютно прав, я забув виправити це деякий час тому.
Тімо Хуовінен

3

Це робочий приклад:

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

2

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

Прочитайте цей підручник: Як синхронізувати часові пояси PHP та MySQL


Це в основному два рядки коду: date_default_timezone_set("America/Los_Angeles");і mysql_query("SET time_zone='" . date('P', time()) . "'");працювали дуже елегантно!
Номенон

3
@Noumenon Обережно з цим! Я чухаю голову сьогодні вранці, тому що саме це я і робив, а деякі мої часи закінчуються вже на годину. Я підозрюю, що використання названого часового поясу є більш точним при участі DST. Якщо ви використовуєте America / New_York, MySQL знає про DST і зберігатиме дати відповідно. Якщо ви просто встановите його до -04: 00, як у вас тут, він не враховує розрахунок DST.
Натанб

1
Перевірте, чи mysql правильно знає DST, правила DST регулярно оновлюються, а відповідні таблиці mysql також потребують оновлення (див. Вище внизу моєї відповіді)
Timo Huovinen

1

Плюси і мінуси майже однакові. Це залежить від того, хочете ви цього чи ні.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.