🕐 Почему вечно «едут» даты
Со временем всё просто — до первого бага
У юзера отчёт за «вчера» показывает не то, напоминалка падает на час раньше, а после перевода часов вообще всё разъехалось
И самое обидное — локально не повторить, у тебя-то сходится
Разберём, обо что тут все спотыкаются и как перестать воевать
🌍 Правило номер один: всё в UTC
Главная засада — хранить в базе местное время
Пока сервис в одном городе — вроде норм
А как появятся юзеры из разных зон (или сервак переедет) — и ты уже сам не понимаешь, что за 14:00 лежит в базе
По Москве? По серверу? По юзеру? Фиг знает
Как надо: внутри системы всё живёт в UTC — и база, и логика
А местное время — это просто «как показать юзеру», его считаешь в самый последний момент
Прилетело время от клиента — сразу перегнал в UTC и забыл
Отдаёшь наружу — перегнал в зону юзера
🎭 Время без зоны — это мина
В коде время бывает двух видов: с зоной и без
Без зоны — это голое 2026-08-19 14:00, и непонятно, это 14:00 вообще где
Такие штуки нельзя спокойно сравнивать и складывать — рано или поздно бахнет
dt = datetime(2026, 8, 19, 14, 0, tzinfo=timezone.utc)
🌗 Перевод часов — отдельная боль
Даже если зона одна, есть летнее/зимнее время, и тут два прикола, про которые вспоминают только когда уже горит: — один и тот же час может случиться дважды (когда стрелки крутят назад); — а иногда его не бывает вообще (когда крутят вперёд — час просто исчезает)
Поэтому и нельзя держать местное время и думать, что отмотаешь назад
📅 «Вчера» — это когда вообще?
Классика аналитики: юзер хочет отчёт за «вчера», а сутки у всех кончаются в разное время
У чувака в Москве день закрылся в 21:00 UTC, у другого в Нью-Йорке — совсем в другой момент
Режешь сутки по серверному времени — у половины народа «вчера» будет кривым
Границы дня надо считать в зоне юзера, и только потом гнать в UTC для запроса
🔢 Ещё пара вещей, чтоб не наступить
В Postgres храни момент в timestamptz, а не в timestamp
Первый — момент времени, второй — цифры без привязки, и это ловушка
Не парси даты строками руками
Есть ISO 8601 (2026-08-19T14:00:00Z) — понятный формат с зоной, гоняй время между сервисами только так. — Зоны бери из базы IANA (Europe/Moscow), а не хардкодь смещение +3
Страны меняют переводы часов, база обновляется — хардкод нет
⏱️ А ещё есть Unix timestamp
Отдельная штука, которую любят и часто понимают наполовину
Unix timestamp — это число секунд, прошедших с 1 января 1970
Штука отличная: это UTC по своей природе, зоны в нём нет, сравнивать и хранить — одно удовольствие, никаких «а это по чьему времени»
Но есть нюанс: он говорит только про момент и ничего не помнит про то, какая это была дата у юзера
Так что timestamp — это не замена зонам, а просто удобный способ хранить сам момент.
Держи момент в UTC и половина мистических багов с датами отваливается сама.
Расскажите, про баги, которые возникали у вас из-за проблем со временем? 🤔
#backend #database #dev #programming #datetime #postgres
Post #1527
72