Python 시간대 처리: pytz와 zoneinfo

Naive vs Aware Datetime

Python의 datetime 객체는 두 가지 종류가 있습니다. Naive datetime은 시간대 정보가 없어 컨텍스트 없는 시계 읽기에 불과합니다. Aware datetime은 시간대 정보를 포함해 명확한 시점을 나타냅니다. 프로덕션 코드에서는 항상 aware datetime을 사용하세요.

from datetime import datetime, timezone

# Naive — 위험, 프로덕션에서 지양
naive = datetime(2024, 3, 1, 14, 0, 0)
print(naive.tzinfo)  # None

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

현대적 방법: zoneinfo (Python 3.9+)

Python 3.9부터 표준 라이브러리에 IANA 시간대 데이터베이스를 직접 읽는 zoneinfo가 포함되었습니다. 새 코드에는 이 방법을 권장합니다:

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

# 서울 시간으로 aware datetime 생성
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

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

# 특정 시간대의 현재 시각
now_in_tokyo = datetime.now(tz=ZoneInfo("Asia/Tokyo"))

# Windows에서는 별도 패키지 필요:
# pip install tzdata

레거시: pytz

zoneinfo 이전에는 pytz가 표준이었습니다. pytz는 tzinfo를 직접 전달하면 DST 처리가 잘못되므로 반드시 localize()를 사용해야 합니다:

import pytz
from datetime import datetime

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

# 잘못된 방법 — tzinfo 직접 전달 금지
dt_wrong = datetime(2024, 3, 1, 14, 0, tzinfo=tz)

# 올바른 방법 — localize() 사용
dt_correct = tz.localize(datetime(2024, 3, 1, 14, 0))
print(dt_correct)   # 2024-03-01 14:00:00-05:00

자주 하는 실수

  • DST 전환: America/New_York은 겨울에 UTC-5, 여름에 UTC-4입니다. 고정 오프셋 대신 IANA 시간대 이름을 사용하세요.
  • Naive와 Aware 혼용: Python은 naive와 aware datetime을 비교하거나 빼려 할 때 TypeError를 발생시킵니다 — 숨겨진 버그를 방지하는 유용한 오류입니다.
  • 직렬화: JSON이나 데이터베이스에 datetime을 저장할 때 UTC 오프셋이 포함된 .isoformat()을 항상 사용하세요.