zoneinfo — IANA 시간대 지원
zoneinfo — IANA 시간대 지원
zoneinfo 모듈은 PEP 615에 처음 명시된 IANA 시간대 데이터베이스를 지원하는 구체적인 시간대 구현을 제공해요. 기본적으로 시스템의 시간대 데이터를 사용하며, 시스템 데이터가 없으면 PyPI의 1st-party tzdata 패키지로 폴백합니다.
출처: Python 표준 라이브러리
버전 3.9에서 추가. / 사용 가능 환경: WASI 아님.
본문
zoneinfo 모듈은 원래 PEP 615에 명시된 IANA 시간대 데이터베이스를 지원하는 구체적인 시간대 구현을 제공해요. 기본적으로 사용 가능하면 시스템의 시간대 데이터를 쓰고, 시스템 시간대 데이터가 없으면 PyPI의 1st-party tzdata 패키지로 폴백합니다.
ZoneInfo 클래스는 datetime.tzinfo 추상 기본 클래스의 구체적 구현이며, 생성자·datetime.replace·datetime.astimezone을 통해 tzinfo에 붙이도록 설계되었어요.
>>> from zoneinfo import ZoneInfo
>>> import datetime as dt
>>> when = dt.datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(when)
2020-10-31 12:00:00-07:00
>>> when.tzname()
'PDT'
이런 방식으로 만든 datetime은 datetime 산술과 호환되며, 별도의 개입 없이 일광 절약 시간 전환을 처리합니다.
>>> when_add = when + dt.timedelta(days=1)
>>> print(when_add)
2020-11-01 12:00:00-08:00
>>> when_add.tzname()
'PST'
이 시간대들은 PEP 495에 도입된 fold 속성도 지원해요. 모호한 시간을 만드는 오프셋 전환(예: 일광 절약→표준 시간 전환) 동안 fold=0이면 전환 이전의 오프셋, fold=1이면 전환 이후의 오프셋이 사용됩니다.
>>> when = dt.datetime(2020, 11, 1, 1, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(when)
2020-11-01 01:00:00-07:00
>>> print(when.replace(fold=1))
2020-11-01 01:00:00-08:00
다른 시간대에서 변환할 때는 fold가 올바른 값으로 설정됩니다.
>>> LOS_ANGELES = ZoneInfo("America/Los_Angeles")
>>> when_utc = dt.datetime(2020, 11, 1, 8, tzinfo=dt.timezone.utc)
>>> # PDT -> PST 전환 이전
>>> print(when_utc.astimezone(LOS_ANGELES))
2020-11-01 01:00:00-07:00
>>> # PDT -> PST 전환 이후
>>> print((when_utc + dt.timedelta(hours=1)).astimezone(LOS_ANGELES))
2020-11-01 01:00:00-08:00
데이터 소스 (Data sources)
zoneinfo 모듈은 시간대 데이터를 직접 제공하지 않고, 시스템 시간대 데이터베이스나 (가능하면) 1st-party PyPI 패키지 tzdata에서 가져와요. 특히 Windows 같은 일부 시스템은 IANA 데이터베이스가 없어서, 시간대 데이터가 필요한 크로스 플랫폼 호환 프로젝트라면 tzdata에 의존성을 선언하는 것이 권장됩니다. 시스템 데이터도 tzdata도 없으면 모든 ZoneInfo 호출이 ZoneInfoNotFoundError를 일으켜요.
데이터 소스 구성
ZoneInfo(key)를 호출하면 생성자가 먼저 TZPATH에 지정된 디렉터리에서 key와 일치하는 파일을 검색하고, 실패하면 tzdata 패키지에서 일치 항목을 찾습니다. 이 동작은 세 가지 방식으로 구성할 수 있어요.
- 지정하지 않았을 때의 기본
TZPATH는 컴파일 타임에 구성할 수 있습니다. TZPATH는 환경 변수로 구성할 수 있습니다.- 런타임에는
reset_tzpath()함수로 검색 경로를 조작할 수 있습니다.
컴파일 타임 구성
기본 TZPATH에는 시간대 데이터베이스의 여러 일반적인 배포 위치가 포함됩니다 (시간대 데이터의 "잘 알려진" 위치가 없는 Windows 제외). POSIX 시스템에서 시스템 시간대 데이터가 어디 있는지 아는 다운스트림 배포자나 소스에서 Python을 빌드하는 사람은 컴파일 타임 옵션 TZPATH(또는 보통 configure 플래그 --with-tzpath)를 지정해 기본 시간대 경로를 바꿀 수 있어요. os.pathsep으로 구분된 문자열이어야 합니다.
모든 플랫폼에서 구성된 값은 sysconfig.get_config_var()의 TZPATH 키로 확인할 수 있습니다.
환경 구성
TZPATH를 초기화할 때(import 시점이나 인자 없이 reset_tzpath()를 호출할 때) zoneinfo 모듈은 PYTHONTZPATH 환경 변수가 있으면 그걸로 검색 경로를 설정해요.
PYTHONTZPATH — 사용할 시간대 검색 경로를 담은 os.pathsep 구분 문자열. 절대 경로만으로 구성되어야 하며 상대 경로는 안 됩니다. PYTHONTZPATH에 지정된 상대 구성 요소는 사용되지 않지만, 그 외 상대 경로가 지정됐을 때의 동작은 구현에 따라 정의됩니다. CPython은 InvalidTZPathWarning을 일으키지만, 다른 구현은 잘못된 구성 요소를 조용히 무시하거나 예외를 일으킬 수 있어요.
시스템을 시스템 데이터를 무시하고 tzdata 패키지를 쓰게 하려면 PYTHONTZPATH=""로 설정하세요.
런타임 구성
TZ 검색 경로는 reset_tzpath() 함수로 런타임에도 구성할 수 있어요. 보통 권장되는 작업은 아니지만, 특정 시간대 경로를 요구하거나(또는 시스템 시간대 접근을 끊어야 하는) 테스트 함수에서 쓰기에는 합리적입니다.
ZoneInfo 클래스
class zoneinfo.ZoneInfo(key)
문자열 key로 지정된 IANA 시간대를 나타내는 구체적 datetime.tzinfo 하위 클래스입니다. 기본 생성자 호출은 항상 동일하게 비교되는 객체를 반환해요. 다시 말해, ZoneInfo.clear_cache()를 통한 캐시 무효화가 없다면 모든 key 값에 대해 다음 단언이 항상 참입니다.
a = ZoneInfo(key)
b = ZoneInfo(key)
assert a is b
key는 상위 레벨 참조가 없는, 상대적이고 정규화된 POSIX 경로 형태여야 합니다. 생성자는 기준에 맞지 않는 key를 넘기면 ValueError를 일으켜요.
key와 일치하는 파일을 찾지 못하면 ZoneInfoNotFoundError를 일으킵니다.
ZoneInfo 클래스에는 두 개의 대체 생성자가 있어요.
classmethod ZoneInfo.from_file(file_obj, /, key=None)
바이트를 반환하는 파일류 객체(예: 바이너리 모드로 연 파일 또는 io.BytesIO 객체)에서 ZoneInfo 객체를 만듭니다. 기본 생성자와 달리 항상 새 객체를 만들어요. key 매개변수는 __str__()와 __repr__()의 목적으로 구역의 이름을 설정합니다. 이 생성자로 만든 객체는 피클할 수 없습니다 (피클 참고). file_obj에서 읽은 데이터가 유효한 TZif 파일이 아니면 ValueError가 발생해요.
classmethod ZoneInfo.no_cache(key)
생성자의 캐시를 우회하는 대체 생성자입니다. 기본 생성자와 동일하지만 호출마다 새 객체를 반환해요. 테스트나 시연 목적으로 가장 유용하지만, 다른 캐시 무효화 전략을 가진 시스템을 만드는 데도 쓸 수 있습니다. 이 생성자로 만든 객체는 역피클 시에도 역직렬화 프로세스의 캐시를 우회해요.
주의 — 이 생성자를 쓰면 datetime의 의미가 놀랍게 바뀔 수 있어요. 꼭 필요하다고 아는 경우에만 사용하세요.
classmethod ZoneInfo.clear_cache(*, only_keys=None)
ZoneInfo 클래스의 캐시를 무효화하는 메서드입니다. 인자를 넘기지 않으면 모든 캐시가 무효화되고 다음 기본 생성자 호출이 각 key에 새 인스턴스를 반환해요. only_keys 매개변수에 key 이름의 반복 가능한 객체를 넘기면 지정된 key만 캐시에서 제거됩니다. only_keys에 넘겼지만 캐시에 없는 key는 무시돼요.
경고 — 이 함수를 호출하면
ZoneInfo를 쓰는 datetime의 의미가 놀랍게 바뀔 수 있습니다. 모듈 상태를 수정하므로 광범위한 영향을 줄 수 있어요. 꼭 필요하다고 아는 경우에만 사용하세요.
ZoneInfo.key
생성자에 넘긴 key 값을 반환하는 읽기 전용 속성입니다. IANA 시간대 데이터베이스의 조회 키여야 해요 (예: America/New_York, Europe/Paris, Asia/Tokyo). key 매개변수 없이 파일로 만든 구역은 None으로 설정됩니다.
참고 — 이 값을 최종 사용자에게 노출하는 것은 다소 흔한 관행이지만, 이 값들은 관련 구역을 나타내는 기본 키이도록 설계된 것이지 반드시 사용자에게 보여줄 요소는 아니에요. CLDR(Unicode Common Locale Data Repository) 같은 프로젝트를 사용하면 이 키들로 더 사용자 친화적인 문자열을 얻을 수 있습니다.
문자열 표현 (String representations)
ZoneInfo 객체에 str을 호출하면 기본적으로 ZoneInfo.key 속성을 사용합니다.
>>> zone = ZoneInfo("Pacific/Kwajalein")
>>> str(zone)
'Pacific/Kwajalein'
>>> when = dt.datetime(2020, 4, 1, 3, 15, tzinfo=zone)
>>> f"{when.isoformat()} [{when.tzinfo}]"
'2020-04-01T03:15:00+12:00 [Pacific/Kwajalein]'
key 매개변수 없이 파일로 만든 객체는 str이 repr()로 폴백해요. ZoneInfo의 repr은 구현에 따라 정의되어 버전 간에 안정적이지 않을 수 있지만, 유효한 ZoneInfo 키가 아니라는 것은 보장됩니다.
피클 직렬화 (Pickle serialization)
모든 전환 데이터를 직렬화하는 대신, ZoneInfo 객체는 key로 직렬화됩니다. 파일로 만든 ZoneInfo 객체(key 값이 지정됐어도)는 피클할 수 없어요.
ZoneInfo의 동작은 어떻게 만들었느냐에 따라 달라집니다.
ZoneInfo(key): 기본 생성자로 만들면ZoneInfo객체가 key로 직렬화되고, 역직렬화 시 역직렬화 프로세스가 기본 생성자를 사용합니다. 따라서 같은 시간대에 대한 다른 참조와 같은 객체일 것으로 기대돼요. 예를 들어europe_berlin_pkl이ZoneInfo("Europe/Berlin")으로 만든 pickle을 담은 문자열이라면 다음 동작을 기대할 수 있습니다.>>> a = ZoneInfo("Europe/Berlin") >>> b = pickle.loads(europe_berlin_pkl) >>> a is b TrueZoneInfo.no_cache(key): 캐시 우회 생성자로 만들면 이 객체도 key로 직렬화되지만, 역직렬화 시 역직렬화 프로세스가 캐시 우회 생성자를 사용해요.europe_berlin_pkl_nc가ZoneInfo.no_cache("Europe/Berlin")으로 만든 pickle을 담은 문자열이라면 다음 동작을 기대할 수 있습니다.>>> a = ZoneInfo("Europe/Berlin") >>> b = pickle.loads(europe_berlin_pkl_nc) >>> a is b FalseZoneInfo.from_file(file_obj, /, key=None): 파일로 만들면ZoneInfo객체는 피클 시 예외를 일으킵니다. 최종 사용자가 파일로 만든ZoneInfo를 피클하고 싶다면 래퍼 타입이나 커스텀 직렬화 함수를 쓰는 것이 권장됩니다. key로 직렬화하거나 파일 객체 내용을 저장해 그걸 직렬화하는 방식이에요.
이 직렬화 방식은 필요한 key의 시간대 데이터가 직렬화 쪽과 역직렬화 쪽 모두에 있어야 한다는 점을 요구합니다. 클래스·함수에 대한 참조가 직렬화·역직렬화 환경 양쪽에 존재해야 한다고 기대되는 방식과 비슷해요. 또한 시간대 데이터의 다른 버전 환경에서 역피클했을 때 결과의 일관성에 대한 보장이 없다는 뜻이기도 합니다.
함수 (Functions)
zoneinfo.available_timezones()
시간대 경로 어디든 IANA 시간대에 대한 유효한 모든 키를 담은 집합을 가져옵니다. 이 함수를 호출할 때마다 다시 계산돼요.
이 함수는 표준 구역 이름만 포함하며 posix/·right/ 디렉터리 아래의 "특별한" 구역이나 posixrules 구역은 포함하지 않습니다.
주의 — 시간대 경로의 파일이 유효한 시간대인지 확인하는 최선의 방법이 시작 부분의 "매직 문자열"을 읽는 것이므로, 이 함수는 많은 수의 파일을 열 수 있어요.
참고 — 이 값들은 최종 사용자에게 노출하도록 설계된 것이 아닙니다. 사용자 대상 요소는 CLDR(Unicode Common Locale Data Repository) 같은 것을 사용해 더 사용자 친화적인 문자열을 얻으세요.
ZoneInfo.key의 주의 사항도 참고하세요.
zoneinfo.reset_tzpath(to=None)
모듈의 시간대 검색 경로(TZPATH)를 설정하거나 리셋합니다. 인자 없이 호출하면 TZPATH가 기본값으로 설정돼요.
reset_tzpath를 호출해도 ZoneInfo 캐시는 무효화되지 않으므로, 기본 ZoneInfo 생성자 호출은 캐시 미스의 경우에만 새 TZPATH를 사용합니다.
to 매개변수는 문자열이 아닌 문자열 또는 os.PathLike의 시퀀스여야 하며, 모두 절대 경로여야 해요. 절대 경로가 아닌 것을 넘기면 ValueError가 발생합니다.
전역 (Globals)
zoneinfo.TZPATH
시간대 검색 경로를 나타내는 읽기 전용 시퀀스입니다. key에서 ZoneInfo를 만들 때 key가 TZPATH의 각 항목과 결합되고 첫 번째로 찾은 파일이 사용됩니다.
TZPATH는 어떻게 구성됐든 절대 경로만 담을 수 있고 상대 경로는 절대 없습니다.
zoneinfo.TZPATH가 가리키는 객체는 reset_tzpath() 호출에 따라 바뀔 수 있으므로, zoneinfo에서 TZPATH를 import하거나 오래 지속되는 변수를 zoneinfo.TZPATH에 할당하는 것보다 zoneinfo.TZPATH를 사용하는 것을 권장해요.
시간대 검색 경로 구성에 대한 자세한 내용은 데이터 소스 구성을 참고하세요.
예외와 경고 (Exceptions and warnings)
exception zoneinfo.ZoneInfoNotFoundError
지정한 key를 시스템에서 찾을 수 없어 ZoneInfo 객체 생성이 실패할 때 발생합니다. KeyError의 하위 클래스예요.
exception zoneinfo.InvalidTZPathWarning
PYTHONTZPATH가 경로(예: 상대 경로)처럼 필터링되어 제거될 잘못된 구성 요소를 포함할 때 발생합니다.