Чек-лист тестирования дат, времени и таймзон
Даты и время — одна из тех областей, где всё выглядит просто, а ломается коварно: баг вылезает не сразу, а через полгода — в ночь перехода на летнее время, 29 февраля или у пользователя из другой таймзоны. Ниже практический чек-лист, что проверять.
Хранение и модель
- Всё на бэкенде — в UTC. Таймзона применяется только при отображении. Хранение локального времени без таймзоны — почти гарантированный баг.
- «Наивные» datetime (без tz) — красный флаг: при сравнении, сортировке и записи в БД они молча трактуются по-разному.
- Отделяй момент времени от календарной даты. «Дата рождения» и «дедлайн 23:59» — это разные сущности: одна без времени/tz, другая — с ними.
- Проверь, что API отдаёт время в ISO 8601 с оффсетом (
2026-08-18T14:30:00Zили+02:00), а не в неоднозначном локальном виде.
Таймзоны
- Пользователь в одной TZ, сервер в другой, данные создавались в третьей — проверь всю цепочку.
- Пользователь сменил таймзону (перелёт, VPN, ручная смена в настройках) — прошлые события не должны «сдвинуться».
- Оффсеты бывают не кратны часу: Индия (+05:30), Непал (+05:45), часть Австралии.
- Используется актуальная база таймзон (IANA/tzdata)? Правила стран меняются; хардкод оффсета — баг.
Переход на летнее время (DST)
- Несуществующее время: при переводе вперёд стрелок час пропадает (например, 02:00→03:00). Что делает система с событием на 02:30?
- Дублирующееся время: при переводе назад 02:30 наступает дважды. Какой из двух моментов имеется в виду?
- Событие в «дыре» перехода — напоминание/крон/бронь ровно на несусществующий час.
- Страны переходят на DST в разные даты (и не все переходят вообще) — не завязывайся на «как в США/ЕС».
Форматы отображения и ввода
04/05/2026— это 4 мая или 5 апреля? Проверь DD/MM vs MM/DD по локали, на вывод и на ввод.- 12ч vs 24ч,
AM/PM, полночь00:00vs12:00 AM, полдень. - Локальные разделители и порядок; названия месяцев/дней на языке пользователя.
- Первый день недели (пн или вс — зависит от локали) в календарях-пикерах.
Границы (где всё падает)
- Полночь и переход через полночь; события ровно в
00:00и23:59:59. - Конец месяца/года; «31-е число» в месяцах, где его нет.
- 29 февраля (високосный год) — и «+1 год» от 29 февраля.
- «+1 месяц» от 31 января — 28/29 фев или 3 марта? Зафиксируй ожидаемое поведение.
- Эпоха и переполнение: Unix-время 0 (1970), проблема 2038 (32-бит
time_t), очень большие/отрицательные даты.
Расчёты и разница
- Разница между датами через переход DST — в сутках может быть не 24 часа (23 или 25).
- Возраст, «сколько дней осталось», рабочие дни (исключая выходные/праздники по стране).
- Складывание длительностей: «через 90 дней» vs «через 3 месяца» — это разные результаты.
- Сравнение времени из разных таймзон — приводи к одному моменту (UTC), а не сравнивай «как есть».
Относительное время
- «5 минут назад», «завтра», «через 2 часа» — проверь на границах (23:59 → «завтра»).
- Часы клиента врут/скошены — не доверяй времени устройства для критичной логики (токены, дедлайны); источник истины — сервер.
- Живое обновление относительных меток (через минуту «only now» должно стать «1 min ago»).
Как воспроизводить
- Меняй таймзону устройства/ОС и язык — самый быстрый способ поймать баги отображения.
- Freeze/mock часов в автотестах (фиксируй «сейчас»), иначе тест мигает у полуночи/на границе года.
- Держи набор опасных дат как тест-данные: 29 фев, ночь перехода DST (вперёд и назад), 31 декабря 23:59, +05:45-таймзона, 2038 год.
- Прогоняй хотя бы в двух-трёх таймзонах (UTC, что-то с DST, что-то с получасовым оффсетом).
Коротко
- Храни в UTC, таймзону применяй только на отображении; «наивные» datetime — баг.
- DST рождает несуществующее и дублирующееся время — проверь события в этих окнах.
- Форматы дат неоднозначны (04/05) — тестируй вывод и ввод по локали.
- Границы: полночь, конец месяца, 29 февраля, «+1 месяц» от 31-го, 2038.
- Не доверяй часам клиента; источник времени — сервер.
- Воспроизводи сменой TZ устройства + freeze clock + набор опасных дат.