API'm Her 1 Ocak'ta Bozuluyordu

API'm tam olarak 1 Ocak günü saat 00:00 UTC'de bozuldu.

Kullanıcıların gece yarısında bozulmadı. UTC gece yarısında bozuldu. Tokyo'daki kullanıcılar, kendi yerel saatleriyle sabah 09:00'dan itibaren hatalı veriler gördüler.

Testler geçti. Staging ortamı sorunsuz çalıştı. Hata sadece production ortamında mevcuttu çünkü production sunucusu, staging ortamından farklı bir saat dilimi kullanıyordu.

Sorun şu mantıktaydı:

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" gibi bir tarihi saat bilgisi olmadan geçtiğinizde, sistem yerel saat dilimini kullanır.

Staging sunucumuz UTC kullanıyordu. Production sunucumuz US-East kullanıyordu. Bu durum, her bir tarih sorgusunda beş saatlik bir kaymaya neden oldu.

Her sorguda beş saatlik veri kaybettik. Sayılar o kadar yakın görünüyordu ki kimse tam bir yıl boyunca fark etmedi.

Çözüm basitti. String'in sonuna saat ekleyerek UTC'yi zorunlu kıldık:

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 }
    }
  });
}

Kod değişikliği saniyeler sürdü. Sistemin düzeltilmesi ise bir hafta aldı. Şu dört adımı attık:

• Ortamın UTC'de kalmasını sağlamak için CI'ya bir saat dilimi doğrulaması (assertion) ekledik. • Her konteynerin özdeş kalması için tüm Dockerfile'larda TZ=UTC olarak ayarladık. • Deploy betiğine bir saat dilimi kontrolü ekledik. • Saat dilimi bilgisi eksik olan tüm Date constructor'larını işaretlemek için bir linter kuralı yazdık.

Saat dilimi hataları tehlikelidir. Sisteminizi çökertmezler. Doğru görünen yanlış veriler üretirler. Kullanıcılarınız bir hata sayfası görmezler. Yanlış sayıları görürler ve onlara güvenirler.

Şu üç kurala uyun:

  • Sistem saat dilimine asla güvenmeyin. Her zaman TZ=UTC olarak ayarlayın.
  • Saat dilimi bilgisi olmadan tarihleri asla ayrıştırmayın (parse etmeyin).
  • CI saat diliminizin production ile eşleştiğini asla varsaymayın.

Kaynak: https://dev.to/kollittle/my-api-broke-every-january-1st-the-timezone-bug-i-should-have-caught-in-code-review-51hb