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