Kafayı yiyecektim arkadaşlar. Haftalardır farklı sunuculardan gelen logları tek bir zaman damgasına (UTC) çevirip birleştiren bir script yazıyordum. Her şey mükemmel çalışıyordu, ta ki dün geçmiş ayların raporunu çalıştırana kadar. Mart ayının son pazarında, tam 1 saatlik veri buharlaşıp gitmişti. Sanki o saat hiç yaşanmamıştı.
Saatlerin Karanlık Yüzü: DST (Yaz Saati Uygulaması)
Meğerse sorun, benim masumane kullandığım pytz kütüphanesi ve naive datetime objeleriymiş. Script'im, log kaydının geldiği zaman dilimini (örn: 'Europe/Istanbul') biliyordu ve şöyle bir dönüşüm yapıyordu:
İşte o ölümcül hata buradaydı! Yaz saati geçişinde (02:00'te saatler 03:00'e alındığında), '02:30:00' diye bir zaman o gün yoktu. Kütüphane de sessizce bu geçersiz zamanı, geçiş sonrası bir saate (muhtemelen 03:30) kaydırdı veya hata vermedi. Sonuç? O bir saatteki tüm loglar ya yanlış yere kaydı ya da tamamen atlandı.
Çözüm: "Aware" DateTime ve İsExists Kontrolü
StackOverflow'da bile doğrudan çözüm bulamadım, ta ki zaman dilimlerinin gerçek bir canavar olduğunu fark edene kadar. Çözüm, zamanı dilim bilgisi olmadan oluşturmamak ve geçersiz saatleri tespit etmekten geçiyordu.
Alınan Acı Dersler
1. Naive datetime'lar sadece basit hesaplamalar içindir. Zaman dilimi işin içine girerse, derhal aware datetime kullan.
2. pytz kütüphanesi güçlüdür ama kuralları vardır. .localize() ve .normalize() metodlarını doğru öğren.
3. Loglama sisteminize mümkünse UTC zaman damgası yazdırın. Bu, gelecekteki sizden bir hediyedir.
4. Tarih-saat işlemleri, yazılımcının en büyük illüzyonudur. Asla güvenmeyin, her zaman şüpheyle yaklaşın.
Şaka gibi ama bir saatlik veri için günlerimi harcadım. Siz de benzer bir zaman dilimi tuzağına düştünüz mü? Ya da pytz yerine dateutil veya Python 3.9+'daki yerel zoneinfo ile daha temiz bir çözümünüz var mı? Fikirlerinizi bekliyorum!
Meğerse sorun, benim masumane kullandığım pytz kütüphanesi ve naive datetime objeleriymiş. Script'im, log kaydının geldiği zaman dilimini (örn: 'Europe/Istanbul') biliyordu ve şöyle bir dönüşüm yapıyordu:
Python:
local_time = parser.parse(log_line) # '2024-03-31 02:30:00' (Ancak bu saat, bu tarihte YOK!)
utc_time = timezone.localize(local_time).astimezone(pytz.UTC)
İşte o ölümcül hata buradaydı! Yaz saati geçişinde (02:00'te saatler 03:00'e alındığında), '02:30:00' diye bir zaman o gün yoktu. Kütüphane de sessizce bu geçersiz zamanı, geçiş sonrası bir saate (muhtemelen 03:30) kaydırdı veya hata vermedi. Sonuç? O bir saatteki tüm loglar ya yanlış yere kaydı ya da tamamen atlandı.
StackOverflow'da bile doğrudan çözüm bulamadım, ta ki zaman dilimlerinin gerçek bir canavar olduğunu fark edene kadar. Çözüm, zamanı dilim bilgisi olmadan oluşturmamak ve geçersiz saatleri tespit etmekten geçiyordu.
Python:
from datetime import datetime
import pytz
tz = pytz.timezone('Europe/Istanbul')
# Önce 'naive' bir datetime oluştur
naive_dt = datetime(2024, 3, 31, 2, 30, 0)
# LOCALIZE ederken 'is_dst' parametresiyle kontrol et
try:
aware_dt = tz.localize(naive_dt, is_dst=None) # is_dst=None, geçersiz saatte hata fırlatır
except pytz.exceptions.AmbiguousTimeError:
# Belirsiz saat (sonbahar) için bir seçim yap
aware_dt = tz.localize(naive_dt, is_dst=False)
except pytz.exceptions.NonExistentTimeError:
# OLMAYAN bir saat (ilkbahar) için, geçiş sonrası ilk geçerli saate atla
print(f"Uyarı: {naive_dt} saati bu zaman diliminde yok. Atlanıyor veya düzeltiliyor...")
# Örnek: Bir sonraki geçerli saate ilerlet
aware_dt = tz.localize(datetime(2024, 3, 31, 3, 30, 0))
1. Naive datetime'lar sadece basit hesaplamalar içindir. Zaman dilimi işin içine girerse, derhal aware datetime kullan.
2. pytz kütüphanesi güçlüdür ama kuralları vardır. .localize() ve .normalize() metodlarını doğru öğren.
3. Loglama sisteminize mümkünse UTC zaman damgası yazdırın. Bu, gelecekteki sizden bir hediyedir.
4. Tarih-saat işlemleri, yazılımcının en büyük illüzyonudur. Asla güvenmeyin, her zaman şüpheyle yaklaşın.
Şaka gibi ama bir saatlik veri için günlerimi harcadım. Siz de benzer bir zaman dilimi tuzağına düştünüz mü? Ya da pytz yerine dateutil veya Python 3.9+'daki yerel zoneinfo ile daha temiz bir çözümünüz var mı? Fikirlerinizi bekliyorum!