𝗠𝘆 𝗔𝗣𝗜 𝗕𝗿𝗼𝗸𝗲 𝗘𝘃𝗲𝗿𝘆 𝗝𝗮𝗻𝘂𝗮𝗿𝘆 𝟭𝘀𝘁

Мой API сломался ровно в 00:00 UTC 1 января.

Он сломался не в полночь по времени пользователей. Он сломался в полночь по UTC. Пользователи в Токио увидели некорректные данные, начиная с 9 утра по их времени.

Тесты прошли. Стейджинг работал. Ошибка проявлялась только в продакшене, потому что на продакшн-сервере был установлен другой часовой пояс, отличный от стейджинга.

Проблема заключалась в этой логике:

function getDailyReport(date) {
  const start = new Date(date).toISOString().split('T')[0];
  const end = new Date(start + 'T23:59:59Z');

  return db.reports.findMany({
    where: {
      createdAt: { gte: new Date(start), lt: end }
    }
  });
}

Когда вы передаете дату вроде "2026-01-01" без указания времени, система использует локальный часовой пояс.

Наш стейджинг-сервер использовал UTC. Наш продакшн-сервер использовал US-East. Это создавало пятичасовое смещение в каждом запросе даты.

Мы теряли пять часов данных в каждом запросе. Цифры были достаточно близки к истине, поэтому никто не замечал этого целый год.

Исправление было простым. Принудительно установите UTC, добавив время к строке:

function getDailyReport(date: string) {
  const start = new Date(`${date}T00:00:00Z`);
  const end = new Date(`${date}T23:59:59.999Z`);

  return db.reports.findMany({
    where: {
      createdAt: { gte: start, lt: end }
    }
  });
}

Изменение кода заняло секунды. Исправление системы заняло неделю. Мы сделали следующее:

• Добавили проверку часового пояса в CI, чтобы гарантировать, что среда остается в UTC. • Установили TZ=UTC во всех Dockerfile, чтобы все контейнеры были идентичны. • Добавили проверку часового пояса в скрипт деплоя. • Написали правило для линтера, которое помечает любой конструктор Date без информации о часовом поясе.

Баги с часовыми поясами опасны. Они не обрушивают систему. Они выдают неверные данные, которые выглядят корректно. Ваши пользователи не увидят страницу ошибки. Они увидят неверные цифры и будут им доверять.

Следуйте этим трем правилам:

  • Никогда не доверяйте системному часовому поясу. Всегда устанавливайте TZ=UTC.
  • Никогда не парсите даты без указания часового пояса.
  • Никогда не предполагайте, что часовой пояс в CI совпадает с продакшном.

Источник: https://dev.to/kollittle/my-api-broke-every-january-1st-the-timezone-bug-i-should-have-caught-in-code-review-51hb