Zaman damgaları, saat dilimleri ve iki kez yaşanan saat

Unix zamanının gerçekte neyi saydığı, ISO 8601 ofsetlerinin IANA saat dilimlerinden nasıl ayrıldığı, yaz saati uygulamasının alarmlara ve sürelere ne yaptığı ve UTC saklamanın nerede yanlış cevap olduğu.

Bir zaman damgası iki sorudan birini cevaplar ve tarih hatalarının çoğu bu ikisinin karıştırılmasından doğar. Ya her gözlemcinin üzerinde anlaştığı bir zaman çizgisi noktası olan bir an adlandırır, ya da kimin duvarından söz edildiğini bilmeden hiçbir anlam taşımayan bir duvar saati okuması. Bir ödeme bir anda gerçekleşti; bir diş hekimi randevusu ise bir duvar saati okumasıdır. Birini diğeri olarak saklayın, iş sonradan, tam bir saat kayarak, bir pazar sabahı bozulsun.

Unix zamanı sayar, saati söylemez

Unix zamanı, 1970-01-01 00:00:00 UTC tarihinden bu yana geçen saniye sayısıdır. Buradaki UTC saymanın nerede başladığını söyler; değerin kendisi hiçbir saat dilimi taşımaz. Aynı an Amsterdam'da, Auckland'da ve Lima'da aynı sayıdır.

Sorun birimdedir, o yüzden haneleri sayın.

HaneÖrnekBirim
101756080000saniye
131756080000000milisaniye

Bugünkü her tarih saniye cinsinden 10, milisaniye cinsinden 13 hanelidir ve 2286'ya kadar öyle kalacaktır. Yanlış okumaların ikisi de gürültülüdür: saniye sanılan milisaniye 57626 yılına düşer, milisaniye sanılan saniye ise Ocak 1970'e. Yorumlanan tarihi gösteren bir zaman damgası dönüştürücüsü bunu apaçık kılar.

Diğer sınır kaptır. İşaretli 32 bitlik bir saniye sayacı 2147483647 değerinde biter; bu da 19 Ocak 2038, 03:14:07 UTC demektir, sonra negatife sarar ve Aralık 1901 olarak okunur. 30 yıllık bir son kullanma tarihi saklayan her şey bunun ötesini şimdiden hesaplıyor. İşaretsiz 32 bit 2106'ya ulaşır ama 1970 öncesindeki bütün tarihleri kaybeder; 64 bitin ise pratikte bir tavanı yoktur.

ISO 8601 ve RFC 3339

Ezberlemeye değer biçim 2026-08-25T14:30:00Z şeklidir: tarih, bir T, saat, sonra bir dilim belirteci. RFC 3339, ISO 8601'in internet protokolleri için daha katı bir profilidir ve o belirteci zorunlu kılar. ISO 8601'in kendisi ayrıca hafta tarihlerine, 20260825T143000Z gibi ayırıcısız bir biçime ve ofseti olmayan zaman damgalarına da izin verir; dolayısıyla "ISO 8601" sözü veren bir API genellikle RFC 3339 altkümesini kastediyordur.

Z, ofsetin sıfır olduğu anlamına gelir. +02:00 ise yerel saatin UTC'nin iki saat ilerisinde olduğu anlamına gelir, dolayısıyla UTC çıkarma yapılarak bulunur; bunu ters çevirmek sık görülen bir iki saatlik hatadır.

DizeNeyi adlandırır
2026-08-25T14:30:00ZBir anı, hiçbir belirsizlik olmadan
2026-08-25T16:30:00+02:00Aynı anı, iki saat ileri bir saatte
2026-08-25T14:30:00Bir duvar saati okumasını, an değil
2026-08-2523, 24 ya da 25 saat uzunluğunda bir tarihi

Ne Z ne de ofset içeren bir dize belirsizdir ve ayrıştırıcılar anlaşamaz: kimi UTC varsayar, kimi sistemin dilimini. Doğum günü gibi yalnızca tarihten oluşan bir değerin Greenwich'in batısında çoğu zaman bir gün erken görünmesinin nedeni budur.

Ofset, saat dilimi değildir

+02:00, bir yerdeki bir an hakkında bir olgudur. Europe/Amsterdam ise bir kurallar kümesidir: kışın +01:00, yazın +02:00 ve önceki on yıllarda başka bir biçim. Ofseti saklamak, ölçüldüğü ana ait cevabı korur ve başka herhangi bir cevabı hesaplama olanağını atar.

Ofsetler benzersiz de değildir. Bir yaz öğleden sonrasında +02:00 hem Amsterdam'ı hem Lagos'u hem de Johannesburg'u kapsar, dolayısıyla yalnızca ofsetten kurallara geri dönmenin yolu yoktur ve o saatin önümüzdeki aralık ayında ne göstereceğini bilmenin de yolu yoktur. Kısaltmalar daha da kötüdür, çünkü CST üç ayrı dilimi adlandırır. IANA tanımlayıcısını Area/Location biçiminde saklayın.

Var olmayan saat ve iki kez yaşanan saat

AB genelinde saatler mart ayının son pazarı ileri, ekim ayının son pazarı geri alınır. Amsterdam'da ilkbaharda 02:00 saati 03:00 olur, dolayısıyla 02:00:00 ile 02:59:59 arasındaki her yerel saat o gün hiç yaşanmaz. Sonbaharda 03:00 saati 02:00 olur, dolayısıyla 02:30 iki kez yaşanır: bir kez +02:00 ile, bir saat sonra bir kez daha +01:00 ile.

  • Yinelenen alarmlar. Yerel saatle 02:30'a kurulmuş bir işin ilkbahardaki o pazar günü geçerli bir zamanı yoktur. Zamanlayıcılar birbirinden ayrılır: atlarlar, 03:00'a kaydırırlar ya da 01:30'a kaydırırlar. Sonbahardaki pazar günü aynı iş bir ya da iki kez tetiklenebilir, dolayısıyla bir cron ayrıştırıcısıyla sonraki birkaç tetiklenme zamanını denetleyin.
  • Günlük dosyaları. Ofsetsiz yerel zaman damgalarından oluşan bir saatlik kayıt sıralanamaz ve bir saat arayla gerçekleşen iki olay birebir aynı metni taşır. UTC ile günlükleyin ya da ofseti her satıra koyun.
  • Süreler. Amsterdam yerel saatiyle 24 Ekim 2026 günü 20:00'den ertesi gün 20:00'ye kadar geçen süre 25 saattir. "Bir gün ekle" ile "24 saat ekle" farklı işlemlerdir ve takvim günü cinsinden bir tarih farkı, saatlerle çalışan bir süre dönüştürücüsünden başka bir soruyu cevaplar.

Kurallar değişir, dolayısıyla saklama biçimi bunlara dayanmalıdır

Bu kuralları IANA saat dilimi veritabanı, yani tzdata tutar ve yılda birkaç kez yayımlanır, çünkü kurallar mevzuattır: hükümetler yaz saati uygulamasını kaldırır, benimser ya da geçiş tarihlerini kaydırır, bazen haftalarla ölçülen bir bildirimle. Sabitlenmiş bir konteyner imajı, bir tarayıcı ve bir dil çalışma zamanının her biri kendi kopyasını taşır ve tek bir makinede birbiriyle çelişebilirler. Gelecekteki yerel bir saati bir ana çevirmek bir tahmindir ve ancak o an geldiğinde kesinleşir.

Değerin türüNe saklanmalıNedeni
Olmuş bitmiş bir şeyUTC cinsinden anGeçmiş yeniden yasalaştırılamaz
Duvar saatine bağlı gelecek randevuYerel tarih ve saat artı IANA dilim kimliğiNiyet, saatin okunuşudur
Dilimler arasında sabit gelecek anUTCNiyet, anın kendisidir
Saati olmayan tarihDüz tarih; dilim yok, gece yarısı yokBir dilim iliştirmek onu kaydırır

Gelecek yılki bir toplantı için "sen UTC sakla geç" yaklaşımının yanlış olmasının nedeni budur. Europe/Amsterdam diliminde 30 Mart 2027 saat 09:00'u bugün UTC'ye çevirin, cevap 07:00Z çıkar. Geçiş tarihi o zamana kadar kayarsa toplantı yerel saatle hâlâ 09:00'dadır, ama 07:00Z artık 08:00 olarak görünür: saklanan değer bir tahmini dondurmuş ve niyeti atmıştır. Doğruluğun kaynağı olarak yerel saat artı dilimi tutun; yanındaki her UTC sütunu bir önbellektir.

Tarihleri insanlara göstermek

03/04 ifadesinin belirsizliği dizeden giderilemez. Dünyanın çoğunda 3 Nisan, Amerika Birleşik Devletleri'nde 4 Mart demektir; 03/04/05 ise üçüncü bir bilinmeyen ekler. İnsana giden çıktıda ayı sözcükle yazın (4 Apr 2026) ve makine alışverişinde ISO kullanın. Bir Discord zaman damgası etiketi, sohbette bunu, okuyan kişinin dilimi ve yerel ayarıyla çizerek aşar: belirsizliği olmayan bir değer saklayın, biçimlendirmeyi kenarda yapın.

Hafta numaralarının kendi kuralı vardır. ISO haftaları pazartesi başlar ve 1. hafta, ocak ayının ilk perşembesini, eşdeğer bir ifadeyle 4 Ocak'ı içeren haftadır. Dolayısıyla 1 Ocak bir önceki ISO yılının 52. ya da 53. haftasına, 29 Aralık ise bir sonrakinin 1. haftasına düşebilir. Kuzey Amerika'da yaygın bir gelenek ise numaralandırmayı 1 Ocak'ı içeren ve pazar başlayan haftadan yapar, dolayısıyla aynı tarih iki numara alır; bu yüzden bir hafta günü hesaplayıcısının ISO haftasını bir hesap tablosuyla karşılaştırmakta yarar vardır.

Süreler, aylar ve artık yıllar

"Bir ay sonra" sabit bir gün sayısı değildir; 28, 29, 30 ya da 31 gündür. 31 Ocak'a bir ay eklemenin doğru bir cevabı yoktur ve kütüphaneler genellikle şubat sonuna kırpar; bu da işlemi geri alınamaz kılar: bir ay ekleyin, sonra çıkarın, 31 Ocak artık 28 Ocak olur. Yuvarlama da aynı tuzağın küçük bir örneğidir: bir saat değerini en yakın çeyrek saate budamak ile ona yuvarlamak, bir tam aralığa kadar farklı sonuç verir.

Artık yıl kuralının tamamı: bir yıl 4'e bölünüyorsa artık yıldır, ancak 100'e bölünen yıllar artık yıl değildir, meğerki 400'e de bölünüyor olsunlar. Yani 1900 artık yıl değildi, 2000 artık yıldı ve 2100 olmayacak; bu da ortalama yılı 365,2425 gün yapar. Yalnızca 4'e bölünebilirliğe bakan kod, hafızalardaki her yıl için doğrudur; 2100'e kadar ayakta kalmasının nedeni de budur. 29 Şubat yıl dönümü de buna bağlı bir baş belasıdır: sonraki yıl size 28 Şubat ile 1 Mart'ı sunar ve hiçbir kural ikisi arasında seçim yapmaz, dolayısıyla birini bilerek seçin.