#Симптом и границы применимости
После изменения часового пояса сервера значения TIMESTAMP выглядят сдвинутыми, хотя хранимый момент времени не менялся. В MySQL тип TIMESTAMP преобразуется при записи и чтении по time_zone сессии; DATETIME ведёт себя иначе.
#Как отличить возможные причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Изменена часовая зона сессииСоединение приложения получает отличающийся от ожидаемого time_zone. | Сдвиг TIMESTAMP при одном и том же ID | Проверить настройки соединений |
| Применён SYSTEMMySQL опирается на настройки ОС, которые могли измениться. | Сдвиг появился после изменения сервера | Согласовать UTC в приложении |
| Смешаны типыDATETIME трактуется как местное время, TIMESTAMP — момент с преобразованием. | Одинаковая строка в разных столбцах ведёт себя иначе | Уточнить тип колонок |
#Пошаговая диагностика и безопасное исправление
- 1. Запишите реальное смещение и конкретную строкуВ интерфейсе приложения найдите одну запись с известным временем события. Запишите её ID, время события по независимому источнику и значение в приложении, не меняя всю таблицу по одному примеру.
- 2. Проверьте сессию именно приложенияОткройте подключение с теми же параметрами, что использует приложение, и прочитайте time_zone, system_time_zone и текущее время. Не ориентируйтесь только на интерактивный root-клиент: у него может быть другая настройка.
- Консоль mysql: только чтение; результаты разных соединений могут отличатьсяSQLКомандаКонсоль mysql: только чтение; результаты разных соединений могут отличаться.
SELECT @@SESSION.time_zone AS session_tz, @@GLOBAL.time_zone AS global_tz, @@system_time_zone AS system_tz, NOW() AS local_now, UTC_TIMESTAMP() AS utc_now;
- 3. Сверьте определения типов полейВыполните SHOW CREATE TABLE и найдите колонку события. DATETIME не преобразуется через session time_zone при обычном чтении; TIMESTAMP преобразуется при записи и чтении.SQLКомандаЧтение; appdb.events — пример.
SHOW CREATE TABLE appdb.events;
- 4. Проведите сравнительное чтение в одной тестовой сессииВ отдельном клиентском подключении к тестовой базе прочитайте известную строку сначала при +00:00, затем при ожидаемом смещении; меняется только сессионная настройка, не данные строки.
- Дополнительная команда по темеSQLКомандаМеняет только текущую сессию; +02:00 — пример фиксированного смещения, не правило сезонного времени.
SET SESSION time_zone = '+00:00';SELECT id, happened_at FROM appdb.events WHERE id=42;SET SESSION time_zone = '+02:00';SELECT id, happened_at FROM appdb.events WHERE id=42;
- 5. Согласуйте единое правило храненияДля новых операций установите правило: хранить момент события в UTC и преобразовывать для пользователя по его региональной часовой зоне. Для автоматического сезонного перевода требуется зона с правилами и загруженные таблицы часовых зон; фиксированное +02:00 летом может ошибаться.
- 6. Настройте пул соединений и тестыУстановите ожидаемое значение time_zone при создании каждого соединения приложения либо используйте согласованную настройку сервера. Если пул переиспользует сессию, убедитесь, что приложение не оставляет чужую зону от предыдущего запроса.
- 7. Сравните отображение до и после выпускаНа копии создайте тестовые события около сезонного перевода и отобразите их из разных часовых поясов. Успех — один и тот же момент события соответствует разному локальному времени без изменения исходного UTC.
#Как проверить, что проблема устранена
Для выбранного ID UTC-момент остаётся неизменным, отображение соответствует зоне пользователя; в новых соединениях session time_zone стабилен.
#Если исправление не помогло
Если сдвиг уже записан в DATETIME, настройка соединения не восстановит исходный смысл; потребуется отдельная согласованная миграция с источником правильного времени.