PEP 431 – 시간대 지원 개선
- Author:
- Lennart Regebro <regebro at gmail.com>
- BDFL-Delegate:
- Barry Warsaw <barry at python.org>
- Status:
- Superseded
- Type:
- Standards Track
- Created:
- 11-Dec-2012
- Post-History:
- 11-Dec-2012, 28-Dec-2012, 28-Jan-2013
- Superseded-By:
- 615
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 Python 표준 라이브러리에서 구체적인 시간대 지원을 구현하고, DST 변경 중에 발생하는 모호한 시간 명세를 처리할 수 있도록 시간대 API를 개선할 것을 제안합니다.
철회
오랜 논의 끝에, 제가 datetime 구현의 문제라고 생각했던 부분들이 의도된 것임이 밝혀졌습니다. 여기에는 날짜 시간 산술 연산을 할 때 DST 전환을 완전히 무시하는 것이 포함됩니다. 따라서 이 PEP의 is_dst 플래그 부분은 아무런 쓸모 있는 함수 역할도 하지 못하므로 무의미해집니다. datetime은 설계상 모호한 datetime을 구분하지 않으며 앞으로도 그렇게 하지 않을 것입니다.
따라서 저는 이 PEP를 철회합니다.
업데이트: PEP 615 “표준 라이브러리의 IANA 시간대 데이터베이스 지원(Support for the IANA Time Zone Database in the Standard Library)”이 Python 3.9에 zoneinfo 모듈을 추가하면서 이 PEP를 대체했습니다.
제안
구체적인 시간대 지원
Python의 시간대 지원은 고정 오프셋을 지원하는 tzinfo 베이스 클래스 외에는 표준 라이브러리에 구체적인 구현이 없습니다. 시간대를 제대로 지원하려면 일광 절약 시간 변경을 포함하여 현재와 과거의 모든 시간대에 대한 데이터베이스를 포함해야 합니다. 그러나 이러한 정보는 자주 바뀌므로, Python 릴리스에 최신 정보를 포함하더라도 불과 몇 달 뒤면 그 정보는 낡은 것이 됩니다.
그래서 시간대 지원은 지금까지 두 개의 서드파티 모듈인 pytz와 dateutil을 통해서만 제공되었으며, 두 모듈 모두 “zoneinfo” 데이터베이스를 포함하고 감싸고 있습니다. “tz” 또는 “Olsen 데이터베이스”라고도 불리는 이 데이터베이스는 사실상 표준인 시간대 데이터베이스이며, OS X를 포함한 대부분의 Unix 및 Unix 계열 운영 체제에 포함되어 있습니다.
이 덕분에 zoneinfo 데이터를 지원하는 코드를 표준 라이브러리에 포함하되, 기본적으로는 운영 체제가 가진 데이터 사본을 사용할 수 있습니다. 이 사본은 보통 운영 체제나 배포판의 업데이트 메커니즘을 통해 최신 상태로 유지됩니다.
Windows처럼 zoneinfo 데이터베이스를 포함하지 않는 운영 체제를 사용하는 경우를 위해 Python 소스 배포판에 zoneinfo 데이터베이스 사본을 포함하고, 최신 zoneinfo 데이터베이스를 담은 배포 패키지도 Python 패키지 색인에 올려 easy_install이나 pip 같은 Python 패키징 도구로 쉽게 설치할 수 있도록 합니다. 더 이상 업데이트를 받지 못해 데이터베이스가 낡은 Unix 시스템에서도 같은 방법을 쓸 수 있습니다.
이러한 메커니즘을 통해 Python은 어떤 플랫폼에서든 표준 라이브러리에서 완전한 시간대 지원을 갖추게 되며, Windows처럼 zoneinfo 데이터베이스가 포함되지 않은 플랫폼이나 OS 업데이트가 더 이상 제공되지 않는 플랫폼에서는 간단한 패키지 설치만으로 최신 시간대 데이터베이스를 얻을 수 있습니다.
시간대 지원은 datetime 모듈을 패키지로 바꾸고, Stuart Bishop의 pytz 모듈을 바탕으로 datetime에 시간대 지원을 추가하는 방식으로 구현합니다.
지역 시간대 얻기
Unix에는 현재 사용 중인 시간대의 이름을 알아내는 표준 방법이 없습니다. 얻을 수 있는 정보는 EST나 PDT 같은 시간대 약어뿐인데, 이 약어 중 상당수는 모호하므로 자신이 어느 시간대에 있는지 알아내는 데 이를 신뢰할 수 없습니다.
하지만 컴파일된 시간대 정보는 /etc/localtime에 있으므로 이를 찾는 표준 방법은 있습니다. 따라서 시간대의 이름을 모르더라도 올바른 시간대 정보를 가진 지역 시간대 객체를 만들 수 있습니다. 지역 시간대를 반환하는 함수를 datetime에 제공해야 합니다.
이 기능은 Lennart Regebro의 tzlocal 모듈을 새 datetime 모듈에 통합하는 방식으로 지원합니다.
Windows에서는 로컬 Windows 시간대 이름을 조회한 다음, 유니코드 컨소시엄이 제공하는 Windows 시간대 이름과 zoneinfo 시간대 이름 간의 매핑을 사용하여 이를 zoneinfo 시간대로 변환합니다.
이 매핑은 각 메이저 릴리스나 버그 수정 릴리스 전에 갱신해야 하며, 이를 위한 스크립트는 Tools/ 디렉터리에 제공됩니다.
모호한 시각
일광 절약 시간(DST)에서 전환될 때는 시계를 한 시간 되돌립니다. 즉, 그 한 시간 동안의 시각이 DST가 적용된 상태로 한 번, DST가 적용되지 않은 상태로 다시 한 번, 이렇게 두 번 나타납니다. 마찬가지로 일광 절약 시간으로 전환될 때는 한 시간이 사라집니다.
현재의 시간대 API는 DST에서 전환되는 동안 나타나는 모호한 두 시각을 구별하지 못합니다. 예를 들어 스톡홀름에서 2012-11-28 02:00:00이라는 시각은 UTC 2012-11-28 00:00:00과 2012-11-28 01:00:00에 각각 한 번씩, 모두 두 번 나타납니다.
현재의 시간대 API는 이 모호함을 해소할 수 없으므로 어느 시각을 반환해야 하는지 명확하지 않습니다:
# This could be either 00:00 or 01:00 UTC:
>>> dt = datetime(2012, 10, 28, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'))
# But we can not specify which:
>>> dt.astimezone(zoneinfo('UTC'))
datetime.datetime(2012, 10, 28, 1, 0, tzinfo=<UTC>)
pytz는 tzinfo 객체의 여러 메서드에 is_dst 매개변수를 추가하여 필요할 때 시각의 모호함을 해소할 수 있게 함으로써 이 문제를 해결했습니다.
이 PEP는 datetime API의 관련 메서드에 이러한 is_dst 매개변수를 추가하여 이 기능을 datetime에 직접 추가할 것을 제안합니다. 이 작업은 기존 외부 라이브러리를 재구성하는 데 그치지 않고 새 코드를 작성해야 하며, datetime 라이브러리의 C 버전에 이 기능을 추가하도록 갱신해야 하므로 이 PEP에서 가장 어려운 부분일 것입니다.
구현 API
zoneinfo 데이터베이스
zoneinfo 데이터베이스의 최신 버전은 Python 소스 관리 시스템의 Lib/tzdata 디렉터리에 있어야 합니다. 데이터베이스의 이 사본은 Python의 모든 기능 릴리스와 버그 수정 릴리스 전에 갱신해야 하지만, 보안 수정 전용 모드에 있는 Python 버전의 릴리스에서는 갱신하지 않습니다.
데이터베이스를 갱신하는 스크립트는 Tools/에 제공될 것이며, 릴리스 지침에도 이 갱신 작업이 포함되도록 수정될 것입니다.
소스에서 설치할 때 이 데이터베이스의 설치를 활성화하거나 비활성화할 수 있도록 --enable-internal-timezone-database와 --disable-internal-timezone-database라는 새 configure 옵션이 구현될 것입니다. 소스 설치 시에는 기본적으로 데이터베이스를 설치합니다.
시스템이 제공하는 zoneinfo 데이터베이스가 있는 시스템용 바이너리 설치 프로그램은 포함된 데이터베이스를 설치하지 않아도 됩니다. 이러한 플랫폼에서는 포함된 데이터베이스가 전혀 사용되지 않기 때문입니다. 그 밖의 플랫폼(예: Windows)용 바이너리 설치 프로그램은 포함된 데이터베이스를 반드시 설치해야 합니다.
datetime 모듈의 변경 사항
새 시간대 지원의 공개 API에는 새 클래스 하나, 새 함수 하나, 새 예외 하나, 새 컬렉션 네 개가 포함됩니다. 이와 더불어 datetime 객체의 여러 메서드에 새 is_dst 매개변수가 추가됩니다.
새 클래스 dsttimezone
이 클래스는 DST 지원을 구현하는 tzinfo 베이스 클래스의 구체적인 구현을 제공합니다.
새 함수 zoneinfo(name=None, db_path=None)
이 함수는 “US/Eastern”, “Europe/Warsaw”, “Etc/GMT”처럼 유효한 zoneinfo 시간대를 지정하는 문자열을 이름으로 받습니다. 이름을 지정하지 않으면 지역 시간대를 조회합니다. 유효하지 않은 시간대 이름이 주어지거나 지역 시간대를 가져올 수 없으면 이 함수는 UnknownTimeZoneError를 발생시킵니다.
이 함수는 사용할 zoneinfo 데이터베이스의 위치를 가리키는 경로도 선택적으로 받습니다. 경로를 지정하지 않으면 이 함수는 다음 순서로 데이터베이스를 찾습니다:
tzdata-update모듈이 설치되어 있는지 확인하고, 설치되어 있으면 그 데이터베이스를 사용합니다./usr/share/zoneinfo에 데이터베이스가 있으면 그 데이터베이스를 사용합니다.Lib/tzdata에 있는 Python 제공 데이터베이스를 사용합니다.
데이터베이스를 찾지 못하면 UnknownTimeZoneError 또는 그 서브클래스가 발생합니다. 이때 zoneinfo 데이터베이스를 찾을 수 없지만 tzdata-update 패키지로 설치할 수 있다는 메시지가 함께 표시됩니다.
새 매개변수 is_dst
DST 전환 시의 시간 모호성을 처리하기 위해 여러 메서드에 새 is_dst 매개변수가 추가됩니다.
tzinfo.utcoffset(dt, is_dst=False)tzinfo.dst(dt, is_dst=False)tzinfo.tzname(dt, is_dst=False)datetime.astimezone(tz, is_dst=False)
is_dst 매개변수는 False(기본값), True 또는 None일 수 있습니다.
False는 주어진 datetime을 일광 절약 시간이 아닌 때로 해석하도록 지정합니다. 즉, 지정한 시각이 DST가 끝난 이후라는 뜻입니다. 기존 동작을 유지하기 위해 이것이 기본값입니다.
True는 주어진 datetime을 일광 절약 시간 중인 때로 해석하도록 지정합니다. 즉, 지정한 시각이 DST가 끝나기 이전이라는 뜻입니다.
None은 지정한 시각이 DST 전환 중에 해당하면 AmbiguousTimeError 예외를 발생시킵니다. 또한 DST로 전환될 때의 “사라지는 시간” 중의 시각을 지정하면 NonExistentTimeError를 발생시킵니다.
새 예외
UnknownTimeZoneError이 예외는 KeyError의 서브클래스이며, 찾을 수 없는 시간대 명세를 지정했을 때 발생합니다.:
>>> datetime.zoneinfo('Europe/New_York') Traceback (most recent call last): ... UnknownTimeZoneError: There is no time zone called 'Europe/New_York'
InvalidTimeError이 예외는
AmbiguousTimeError와NonExistentTimeError의 베이스 역할을 하며, 이 두 예외를 따로 잡을 수 있게 해 줍니다. 이 예외는 ValueError의 서브클래스가 되므로, 2011년 2월 29일과 같은 입력과 함께 이러한 오류를 포착할 수 있습니다.AmbiguousTimeError이 예외는
is_dst를 None으로 설정한 상태에서 모호한 datetime 명세를 지정했을 때 발생합니다.:>>> datetime(2012, 11, 28, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'), is_dst=None) >>> Traceback (most recent call last): ... AmbiguousTimeError: 2012-10-28 02:00:00 is ambiguous in time zone Europe/Stockholm
NonExistentTimeError이 예외는
is_dst를 None으로 설정한 상태에서 일광 절약 시간 때문에 존재하지 않는 시간에 대한 datetime 명세를 지정했을 때 발생합니다.:>>> datetime(2012, 3, 25, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'), is_dst=None) >>> Traceback (most recent call last): ... NonExistentTimeError: 2012-03-25 02:00:00 does not exist in time zone Europe/Stockholm
새 컬렉션
all_timezones는 사용할 수 있는 시간대 이름을 알파벳순으로 나열한 전체 목록입니다.common_timezones는 유용한 현행 시간대를 알파벳순으로 나열한 목록입니다.
tzdata-update 패키지
zoneinfo 데이터베이스는 easy_install/pip/buildout으로 쉽게 설치할 수 있도록 패키지로 제공됩니다. 이 패키지는 어떠한 Python 코드도 설치하지 않으며, 설치에 필요한 코드를 제외하고는 어떠한 Python 코드도 포함하지 않습니다.
이것은 내부 데이터베이스와 동일한 도구로 최신 상태가 유지되지만, zoneinfo 데이터베이스가 갱신될 때마다 릴리스되며, 동일한 버전 스키마를 사용합니다.
pytz API와의 차이점
pytz에는tzinfo에 is_dst가 없다는 점을 우회하기 위한localize()와normalize()함수가 있습니다.is_dst가datetime.tzinfo에 직접 구현되면 이 함수들은 더 이상 필요하지 않습니다.timezone()함수는 Python 3.2에서 도입된timezone클래스와 충돌하지 않도록zoneinfo()라는 이름을 사용합니다.zoneinfo()를 인자 없이 호출하면 로컬 시간대를 반환합니다.pytz.StaticTzInfo클래스는 정적 시간대에is_dst지원을 제공하기 위해 존재합니다.is_dst지원이datetime.tzinfo에 포함되면 이 클래스는 더 이상 필요하지 않습니다.InvalidTimeError는ValueError의 서브클래스입니다.
참고 자료
Copyright
This document has been placed in the public domain.