Gestion des Fuseaux Horaires en Python : pytz et zoneinfo

Naive vs Aware Datetimes

Python's datetime objects come in two flavors. A naive datetime has no timezone information — it's just a clock reading with no context. An aware datetime carries timezone information and represents an unambiguous point in time. Always prefer aware datetimes in production code.

from datetime import datetime, timezone

# Naive — dangerous, avoid in production
naive = datetime(2024, 3, 1, 14, 0, 0)
print(naive.tzinfo)  # None

# Aware (UTC) — safe
aware = datetime(2024, 3, 1, 14, 0, 0, tzinfo=timezone.utc)
print(aware.tzinfo)  # UTC

The Modern Way: zoneinfo (Python 3.9+)

Since Python 3.9, the standard library includes zoneinfo, which reads the IANA timezone database directly. This is the recommended approach for new code:

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

# Create a timezone-aware datetime in Seoul time
seoul_tz = ZoneInfo("Asia/Seoul")
dt = datetime(2024, 3, 1, 14, 0, tzinfo=seoul_tz)
print(dt)             # 2024-03-01 14:00:00+09:00

# Convert to UTC
utc_dt = dt.astimezone(timezone.utc)
print(utc_dt)         # 2024-03-01 05:00:00+00:00

# Get current time in a specific timezone
now_in_tokyo = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
print(now_in_tokyo)

# On Python 3.8 or earlier, install tzdata package separately:
# pip install tzdata  (provides IANA database on Windows)

Legacy: pytz

Before zoneinfo, pytz was the standard. It has a quirk: you must use localize() instead of passing tzinfo directly, or DST handling will be wrong:

import pytz
from datetime import datetime

tz = pytz.timezone("America/New_York")

# WRONG — do not use this pattern with pytz
dt_wrong = datetime(2024, 3, 1, 14, 0, tzinfo=tz)

# CORRECT — use localize()
dt_correct = tz.localize(datetime(2024, 3, 1, 14, 0))
print(dt_correct)   # 2024-03-01 14:00:00-05:00

# Converting between timezones
utc_dt = dt_correct.astimezone(pytz.utc)
tokyo_dt = utc_dt.astimezone(pytz.timezone("Asia/Tokyo"))

Working with Django

# settings.py
USE_TZ = True
TIME_ZONE = 'UTC'

# In views/models — use django.utils.timezone
from django.utils import timezone

now = timezone.now()          # timezone-aware UTC datetime
localtime = timezone.localtime(now)  # convert to settings.TIME_ZONE

Common Pitfalls

  • DST transitions: America/New_York is UTC-5 in winter and UTC-4 in summer. Use the IANA timezone name, not a fixed offset.
  • Mixing naive and aware: Python raises TypeError when you try to compare or subtract a naive and aware datetime — a helpful error that prevents silent bugs.
  • Serialization: When converting datetime to a string for JSON or databases, always use .isoformat() which includes the UTC offset.