zoneinfo
--- IANA 時(shí)區支持?
3.9 新版功能.
zoneinfo
模塊根據 PEP 615 的最初說(shuō)明提供了具體的時(shí)區實(shí)現來(lái)支持 IANA 時(shí)區數據庫。 按照默認設置,zoneinfo
會(huì )在可能的情況下使用系統的時(shí)區數據;如果系統時(shí)區數據不可用,該庫將回退為使用 PyPI 上提供的 tzdata 第一方包。
參見(jiàn)
使用 ZoneInfo
?
ZoneInfo
是 datetime.tzinfo
抽象基類(lèi)的具體實(shí)現,其目標是通過(guò)構造器、 datetime.replace
方法或 datetime.astimezone
來(lái)與 tzinfo
建立關(guān)聯(lián):
>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime, timedelta
>>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-10-31 12:00:00-07:00
>>> dt.tzname()
'PDT'
以此方式構造的日期時(shí)間對象可兼容日期時(shí)間運算并可在無(wú)需進(jìn)一步干預的情況下處理夏令時(shí)轉換:
>>> dt_add = dt + timedelta(days=1)
>>> print(dt_add)
2020-11-01 12:00:00-08:00
>>> dt_add.tzname()
'PST'
這些時(shí)區還支持在 PEP 495 中引入的 fold
。 在可能導致時(shí)間歧義的時(shí)差轉換中(例如夏令時(shí)到標準時(shí)的轉換),當 fold=0
時(shí)會(huì )使用轉換 之前 的時(shí)差,而當 fold=1
時(shí)則使用轉換 之后 的時(shí)差,例如:
>>> dt = datetime(2020, 11, 1, 1, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-11-01 01:00:00-07:00
>>> print(dt.replace(fold=1))
2020-11-01 01:00:00-08:00
當執行來(lái)自另一時(shí)區的轉換時(shí),fold 將被設置為正確的值:
>>> from datetime import timezone
>>> LOS_ANGELES = ZoneInfo("America/Los_Angeles")
>>> dt_utc = datetime(2020, 11, 1, 8, tzinfo=timezone.utc)
>>> # Before the PDT -> PST transition
>>> print(dt_utc.astimezone(LOS_ANGELES))
2020-11-01 01:00:00-07:00
>>> # After the PDT -> PST transition
>>> print((dt_utc + timedelta(hours=1)).astimezone(LOS_ANGELES))
2020-11-01 01:00:00-08:00
數據源?
zoneinfo
模塊不直接提供時(shí)區數據,而是在可能的情況下從系統時(shí)區數據庫或 PyPI 上的第一方包 tzdata 獲取時(shí)區信息。 某些系統,重要的一點(diǎn)是 Windows 系統也包括在內,并沒(méi)有可用的 IANA 數據庫,因此對于要保證獲取時(shí)區信息的跨平臺兼容性的項目,推薦對 tzdata 聲明依賴(lài)。 如果系統數據和 tzdata 均不可用,則所有對 ZoneInfo
的調用都將引發(fā) ZoneInfoNotFoundError
。
配置數據源?
當 ZoneInfo(key)
被調用時(shí),此構造器首先會(huì )在 TZPATH
所指定的目錄下搜索匹配 key
的文件,失敗時(shí)則會(huì )在 tzdata 包中查找匹配。 此行為可通過(guò)三種方式來(lái)配置:
TZPATH
可使用 環(huán)境變量 進(jìn)行配置。在 運行時(shí),搜索路徑可使用
reset_tzpath()
函數來(lái)修改。
編譯時(shí)配置?
默認的 TZPATH
包括一些時(shí)區數據庫的通用部署位置(Windows 除外,該系統沒(méi)有時(shí)區數據的“通用”位置)。 在 POSIX 系統中,下游分發(fā)者和從源碼編譯 Python 的開(kāi)發(fā)者知道系統時(shí)區數據部署位置,它們可以通過(guò)指定編譯時(shí)選項 TZPATH
(或者更常見(jiàn)的是通過(guò) 配置旗標 --with-tzpath
) 來(lái)改變默認的時(shí)區路徑,該選項應當是一個(gè)由 os.pathsep
分隔的字符串。
在所有平臺上,配置值會(huì )在 sysconfig.get_config_var()
中以 TZPATH
鍵的形式提供。
環(huán)境配置?
當初始化 TZPATH
時(shí)(在導入時(shí)或不帶參數調用 reset_tzpath()
時(shí)),zoneinfo
模塊將使用環(huán)境變量 PYTHONTZPATH
,如果變量存在則會(huì )設置搜索路徑。
- PYTHONTZPATH?
這是一個(gè)以
os.pathsep
分隔的字符串,其中包含要使用的時(shí)區搜索路徑。 它必須僅由絕對路徑而非相對路徑組成。 在PYTHONTZPATH
中指定的相對路徑部分將不會(huì )被使用,但在其他情況下當指定相對路徑時(shí)的行為該實(shí)現是有定義的;CPython 將引發(fā)InvalidTZPathWarning
,而其他實(shí)現可自由地忽略錯誤部分或是引發(fā)異常。
要設置讓系統忽略系統數據并改用 tzdata 包,請設置 PYTHONTZPATH=""
。
運行時(shí)配置?
TZ 搜索路徑也可在運行時(shí)使用 reset_tzpath()
函數來(lái)配置。 通常并不建議如此操作,不過(guò)在需要使用指定時(shí)區路徑(或者需要禁止訪(fǎng)問(wèn)系統時(shí)區)的測試函數中使用它則是合理的。
ZoneInfo
類(lèi)?
- class zoneinfo.ZoneInfo(key)?
一個(gè)具體的
datetime.tzinfo
子類(lèi),它代表一個(gè)由字符串key
所指定的 IANA 時(shí)區。 對主構造器的調用將總是返回可進(jìn)行標識比較的對象;但是另一種方式,對所有的key
值通過(guò)ZoneInfo.clear_cache()
禁止緩存失效,對以下斷言將總是為真值:a = ZoneInfo(key) b = ZoneInfo(key) assert a is b
key
必須采用相對的標準化 POSIX 路徑的形式,其中沒(méi)有對上一層級的引用。 如果傳入了不合要求的鍵則構造器將引發(fā)ValueError
。如果沒(méi)有找到匹配
key
的文件,構造器將引發(fā)ZoneInfoNotFoundError
。
ZoneInfo
類(lèi)具有兩個(gè)替代構造器:
- classmethod ZoneInfo.from_file(fobj, /, key=None)?
基于一個(gè)返回字節串的文件類(lèi)對象(例如一個(gè)以二進(jìn)制模式打開(kāi)的文件或是一個(gè)
io.BytesIO
對象)構造ZoneInfo
對象。 不同于主構造器,此構造器總是會(huì )構造一個(gè)新對象。key
形參設置時(shí)區名稱(chēng)以供__str__()
和__repr__()
使用。由此構造器創(chuàng )建的對象不可被封存 (參見(jiàn) pickling)。
- classmethod ZoneInfo.no_cache(key)?
一個(gè)繞過(guò)構造器緩存的替代構造器。 它與主構造器很相似,但每次調用都會(huì )返回一個(gè)新對象。 此構造器在進(jìn)行測試或演示時(shí)最為適用,但它也可以被用來(lái)創(chuàng )建具有不同緩存失效策略的系統。
由此構造器創(chuàng )建的對象在被解封時(shí)也會(huì )繞過(guò)反序列化進(jìn)程的緩存。
小心
使用此構造器可以會(huì )以令人驚訝的方式改變日期時(shí)間對象的語(yǔ)義,只有在你確定你的需求時(shí)才使用它。
也可以使用以下的類(lèi)方法:
- classmethod ZoneInfo.clear_cache(*, only_keys=None)?
一個(gè)可在
ZoneInfo
類(lèi)上禁用緩存的方法。 如果不傳入參數,則會(huì )禁用所有緩存并且下次對每個(gè)鍵調用主構造器將返回一個(gè)新實(shí)例。如果將一個(gè)鍵名稱(chēng)的可迭代對象傳給
only_keys
形參,則將只有指定的鍵會(huì )被從緩存中移除。 傳給only_keys
但在緩存中找不到的鍵會(huì )被忽略。警告
發(fā)起調用此函數可能會(huì )以令人驚訝的方式改變使用
ZoneInfo
的日期時(shí)間對象的語(yǔ)義;這會(huì )修改進(jìn)程范圍內的全局狀態(tài)并因此可能產(chǎn)生大范圍的影響。 只有在你確定你的需求時(shí)才使用它。
該類(lèi)具有一個(gè)屬性:
- ZoneInfo.key?
這是一個(gè)只讀的 attribute,它返回傳給構造器的
key
的值,該值應為一個(gè) IANA 時(shí)區數據庫的查找鍵 (例如America/New_York
,Europe/Paris
或Asia/Tokyo
)。對于不指定
key
形參而是基于文件構造時(shí)區,該屬性將設為None
。備注
盡管將這些信息暴露給最終用戶(hù)是一種比較普通的做法,但是這些值被設計作為代表相關(guān)時(shí)區的主鍵而不一定是面向用戶(hù)的元素。 CLDR (Unicode 通用區域數據存儲庫) 之類(lèi)的項目可被用來(lái)根據這些鍵獲取更為用戶(hù)友好的字符串。
字符串表示?
當在 ZoneInfo
對象上調用 str
時(shí)返回的字符串表示默認會(huì )使用 ZoneInfo.key
屬性(參見(jiàn)該屬性文檔中的用法注釋?zhuān)?
>>> zone = ZoneInfo("Pacific/Kwajalein")
>>> str(zone)
'Pacific/Kwajalein'
>>> dt = datetime(2020, 4, 1, 3, 15, tzinfo=zone)
>>> f"{dt.isoformat()} [{dt.tzinfo}]"
'2020-04-01T03:15:00+12:00 [Pacific/Kwajalein]'
對于基于文件而非指定 key
形參所構建的對象,str
會(huì )回退為調用 repr()
。 ZoneInfo
的 repr
是由具體實(shí)現定義的并且不一定會(huì )在不同版本間保持穩定,但它保證不會(huì )是一個(gè)有效的 ZoneInfo
鍵。
封存序列化?
ZoneInfo
對象的序列化是基于鍵的,而不是序列化所有過(guò)渡數據,并且基于文件構造的 ZoneInfo
對象(即使是指定了 key
值的對象)不能被封存。
ZoneInfo
文件的行為取決于它的構造方式:
ZoneInfo(key)
: 當使用主構造器構造時(shí),會(huì )基于鍵序列化一個(gè)ZoneInfo
對象,而當反序列化時(shí),反序列化過(guò)程會(huì )使用主構造器,因此預期它們與其他對同一時(shí)區的引用會(huì )是同一對象。 例如,如果europe_berlin_pkl
是一個(gè)包含基于ZoneInfo("Europe/Berlin")
構建的封存數據的字符串,你可以預期出現以下的行為:>>> a = ZoneInfo("Europe/Berlin") >>> b = pickle.loads(europe_berlin_pkl) >>> a is b True
ZoneInfo.no_cache(key)
: 當通過(guò)繞過(guò)緩存的構造器構造時(shí),ZoneInfo
對象也會(huì )基于鍵序列化,但當反序列化時(shí),反序列化過(guò)程會(huì )使用繞過(guò)緩存的構造器。 如果europe_berlin_pkl_nc
是一個(gè)包含基于ZoneInfo.no_cache("Europe/Berlin")
構造的封存數據的字符串,你可以預期出現以下的行為:>>> a = ZoneInfo("Europe/Berlin") >>> b = pickle.loads(europe_berlin_pkl_nc) >>> a is b False
ZoneInfo.from_file(fobj, /, key=None)
: 當通過(guò)文件構造時(shí),ZoneInfo
對象會(huì )在封存時(shí)引發(fā)異常。 如果最終用戶(hù)想要封存通過(guò)文件構造的ZoneInfo
,則推薦他們使用包裝類(lèi)型或自定義序列化函數:或者基于鍵序列化,或者存儲文件對象的內容并將其序列化。
該序列化方法要求所需鍵的時(shí)區數據在序列化和反序列化中均可用,類(lèi)似于在序列化和反序列化環(huán)境中都預期存在對類(lèi)和函數的引用的方式。 這還意味著(zhù)在具有不同時(shí)區數據版本的環(huán)境中當解封被封存的 ZoneInfo
時(shí)并不會(huì )保證結果的一致性。
函數?
- zoneinfo.available_timezones()?
獲取一個(gè)包含可用 IANA 時(shí)區的在時(shí)區路徑的任何位置均可用的全部有效鍵的集合。 每次調用該函數時(shí)都會(huì )重新計算。
此函數僅包括規范時(shí)區名稱(chēng)而不包括“特殊”時(shí)區如位于
posix/
和right/
目錄下的時(shí)區或posixrules
時(shí)區。小心
此函數可能會(huì )打開(kāi)大量的文件,因為確定時(shí)區路徑上某個(gè)文件是否為有效時(shí)區的最佳方式是讀取開(kāi)頭位置的“魔術(shù)字符串”。
備注
這些值并不被設計用來(lái)對外公開(kāi)給最終用戶(hù);對于面向用戶(hù)的元素,應用程序應當使用 CLDR (Unicode 通用區域數據存儲庫) 之類(lèi)來(lái)獲取更為用戶(hù)友好的字符串。 另請參閱
ZoneInfo.key
中的提示性說(shuō)明。
- zoneinfo.reset_tzpath(to=None)?
設置或重置模塊的時(shí)區搜索路徑 (
TZPATH
)。 當不帶參數調用時(shí),TZPATH
會(huì )被設為默認值。調用
reset_tzpath
將不會(huì )使ZoneInfo
緩存失效,因而在緩存未命中的情況下對主ZoneInfo
構造器的調用將只使用新的TZPATH
。to
形參必須是由字符串或os.PathLike
組成的 sequence 或而不是字符串,它們必須都是絕對路徑。 如果所傳入的不是絕對路徑則將引發(fā)ValueError
。
全局變量?
- zoneinfo.TZPATH?
一個(gè)表示時(shí)區搜索路徑的只讀序列 -- 當通過(guò)鍵構造
ZoneInfo
時(shí),鍵會(huì )與TZPATH
中的每個(gè)條目進(jìn)行合并,并使用所找到的第一個(gè)文件。TZPATH
可以只包含絕對路徑,絕不包含相對路徑,無(wú)論它是如何配置的。zoneinfo.TZPATH
所指向的對象可能隨著(zhù)對reset_tzpath()
的調用而改變,因此推薦使用zoneinfo.TZPATH
而不是從zoneinfo
導入TZPATH
或是將zoneinfo.TZPATH
賦值給一個(gè)長(cháng)期變量。有關(guān)配置時(shí)區搜索路徑的更多信息,請參閱 配置數據源。
異常與警告?
- exception zoneinfo.ZoneInfoNotFoundError?
當一個(gè)
ZoneInfo
對象的構造由于在系統中找不到指定的鍵而失敗時(shí)引發(fā)。 這是KeyError
的一個(gè)子類(lèi)。
- exception zoneinfo.InvalidTZPathWarning?
當
PYTHONTZPATH
包含將被過(guò)濾掉的無(wú)效組件,例如一個(gè)相對路徑時(shí)引發(fā)。