Python DateTime & Timezone
Python DateTime & Timezone
Rule of thumb: Store and compute in UTC. Convert to local only for display.
- Naive vs aware:
datetime.now()is naive (no tz). Preferdatetime.now(timezone.utc)ordatetime.now(ZoneInfo("Europe/Lisbon")). - Python 3.9+:
from zoneinfo import ZoneInfo(stdlib). Older: usepytz. - pytz: use
tz.localize(dt)for local times; don’t pass tz intodatetime(..., tzinfo=pytz.timezone(...))for non-UTC (DST issues). - Store in DB: always in UTC. Validate
dt.tzinfo is not Nonebefore save; convert withdt.astimezone(timezone.utc). - DST: ambiguous or non-existent times (e.g. 2:30 when clocks jump). pytz:
AmbiguousTimeError/NonExistentTimeError. Handle explicitly (e.g.is_dst=Falsefor ambiguous). - Testing: patch
django.utils.timezone.nowor equivalent to fix “now” and assert on conversions.
Debug: log or print dt, dt.tzinfo, and dt.astimezone(timezone.utc) so you see what’s actually there.