Британская Колумбия отменила зимнее время, и Postgres 'ломает' дату будущих встреч

Проблема возникает потому, что timestamptz в Postgres хранит UTC, а не локальное время. Если встреча была заказана как '10:00 Vancouver' до обновления tzdata, она конвертируется в UTC по старым правилам (UTC-8). После обновления tzdata система конвертирует эту UTC обратно в локальное время по новым правилам (UTC-7), и встреча приходит на 11:00 вместо 10:00. Проблема серьёзна: 5,8 млн жителей BC, и если приложение хранит будущие события (appointments, deadlines, calendar), данные расходятся с ожиданиями пользователя. Решение: dual-column pattern, хранить локальное время + timezone name + вычисленное UTC через триггер. При изменении tzdata требуется переобработка будущих событий.
Ключевые факты
- 8 марта 2026: BC перешла на постоянное UTC-7 (летнее время)
- Проблема: timestamptz хранит UTC, конвертирует туда-обратно по tzdata при вставке/извлечении
- Если tzdata обновлена, встречи на ноябрь-март 2026+ будут на 1 час позже, чем пользователь бронировал
- Решение: dual-column pattern: local_time (timestamp) + timezone_name (text) + starts_at_utc (вычисляется триггером)
- Требуется UPDATE всех будущих встреч при изменении tzdata для перепересчёта UTC по новым правилам
Ред. Провинция поменяла часовой пояс, и встречи на ноябрь честно сдвинулись на час, потому что база данных хранила то, что ей сказали, а не то, что имели в виду.
Почему это важно
Время, это не просто число. Для встреч врачей, доставок, деловых звонков локальное время, это то, что пользователь записал в календарь. Если система тайно переводит это время при изменении политики часовых поясов, возникают кризисы и потеря доверия. Проблема касается не только BC, любой регион может изменить правила DST. tzdata обновляется каждые несколько месяцев.
Ред. Классика: timestamptz годами «просто работает», ровно до того дня, когда чьё-то правительство решает отменить перевод стрелок.
Кому это важно
Разработчикам приложений с календарём, booking-системами, медицинскими платформами; DBA, отвечающим за Postgres; компаниям, работающим во многих часовых поясах (особенно с DST).
Ред. Все, кто хоть раз самоуверенно написал «да зачем нам две колонки, UTC же всё решает», сегодня перечитывают эту статью.
Как это применить
- Если цена в прошлом или UTC авторитетен (логи, финтранзакции), используйте timestamptz как есть. 2. Если локальное время авторитетно (встречи, deadlines, события календаря), используйте dual-column pattern. 3. Создайте триггер, который при вставке/обновлении пересчитывает starts_at_utc из local_time AT TIME ZONE timezone_name. 4. При обновлении tzdata запустите UPDATE для перепересчёта будущих встреч. 5. Добавьте UI-уведомление о сдвиге времени встреч.
Ред. Пять шагов, триггер и UPDATE всех будущих записей, то есть честная плата за то, что время это не число, а обещание перед пользователем.
Можно ли доверять
Статья от Crunchy Data (компании со специалистами по Postgres), содержит валидный SQL-код и примеры. Проблема реальна и документирована в пост-сообществе (ссылка на обсуждение postgresql-general от ноября 2025). Требования RFC 9557 (новый стандарт временных меток) специально исключают future-time сценарии как неразрешимые стандартом.
Ред. Crunchy Data знают Postgres, и даже свежий стандарт RFC 9557 честно расписался в том, что будущие даты он не вытянет.
Риски и подводные камни
Миграция старых данных сложна: нужно точно определить, когда tzdata обновлена, найти затронутые строки, уведомить пользователей, провести тест на staging. Если пользователь уже адаптировался к сдвинутому времени, переобработка может их запутать. Generated columns в Postgres НЕ поддерживают timestamptz (не объявлен как immutable), поэтому нужен триггер, а не встроенная генерация.
Ред. Самое коварное тут не миграция, а пользователь, который уже привык к сдвинутому времени, и теперь вы сдвинете его обратно.
«If you stored timestamps in a UTC-based column for British Columbia-based appointment in 2026 and beyond, your November through March appointments may be off by an hour!»
— Crunchy Data, о последствиях tzdata update