시간대 문제 디버깅: 흔한 버그와 해결책

가장 흔한 시간대 버그

수년간의 개발자 고통 끝에 특정 시간대 버그들이 반복적으로 등장합니다. 가장 흔한 버그들과 수정 방법을 소개합니다.

버그 1: Naive Datetime 함정 (Python)

# 버그: naive와 aware datetime 비교
from datetime import datetime, timezone
deadline = datetime(2024, 3, 1, 0, 0)          # naive — 시간대 없음!
now = datetime.now(timezone.utc)                 # aware UTC
print(now > deadline)    # TypeError 발생!

# 수정: 항상 timezone-aware datetime 사용
deadline = datetime(2024, 3, 1, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
print(now > deadline)    # 정상 작동

버그 2: DST 전환 — 없어지거나 두 번 나타나는 시간

# 버그: 시계가 앞당겨질 때 "오전 2시 30분"으로 스케줄링
# 미국에서 3월 두 번째 일요일: 오전 2시 → 오전 3시로 점프
# 오전 2시 30분은 존재하지 않습니다!

# 수정: UTC로 계산하고 표시용으로만 변환
# "현지 오전 2시 30분" 대신 UTC 오전 7시 30분으로 예약

버그 3: JavaScript Date 파싱 불일치

// 버그: 날짜만 있는 문자열은 UTC로 파싱되지만 현지 시간으로 표시
const d = new Date("2024-03-01");
// UTC 자정으로 파싱됨
// UTC-9에서는 2024-02-29로 표시됨!

// 수정: 항상 시간과 시간대 포함
const d = new Date("2024-03-01T00:00:00Z");

디버깅 기법

  • 어디서나 UTC 출력: 디버깅 시 항상 datetime.now(timezone.utc).isoformat() 로그
  • 다른 시간대에서 테스트: TZ=America/New_York 환경 변수로 머신 변경 없이 다른 시간대 테스트
  • DST 전환 시점에서 테스트: Python의 freezegun으로 특정 시간 시뮬레이션
  • 데이터베이스 시간대 확인: SHOW timezone; (PostgreSQL)
# Python: 다른 시간대에서 코드 테스트
TZ=America/New_York python my_script.py

# pytest + freezegun
from freezegun import freeze_time

@freeze_time("2024-03-10 06:59:00")
def test_dst_transition():
    result = schedule_task("America/New_York", hour=2, minute=30)
    assert result.hour != 2  # 2:30 AM이 존재하지 않으므로 적절히 처리해야 함

황금 체크리스트

  • 모든 datetime이 timezone-aware (프로덕션에서 naive datetime 없음)
  • 데이터베이스가 UTC 저장
  • 서버 시간대가 UTC로 설정됨
  • API 응답의 모든 타임스탬프 필드에 시간대 오프셋 포함
  • 크론 잡이 UTC를 사용하거나 명시적으로 CRON_TZ 설정
  • IANA 시간대 이름 사용 (원시 UTC 오프셋 +09:00 대신)
  • DST 전환이 자동화 테스트에서 검증됨