zoneinfo — IANA 时区支持

在 3.9 版本中新增。

源代码: Lib/zoneinfo


zoneinfo 模块提供了一个具体的时区实现,以支持最初在 PEP 615 中指定的 IANA 时区数据库。默认情况下,如果系统时区数据可用,zoneinfo 将使用系统时区数据;如果系统时区数据不可用,该库将回退到使用 PyPI 上可用的第一方 tzdata 包。

参见

模块: datetime

提供了 timedatetime 类型,ZoneInfo 类旨在与它们一起使用。

tzdata

由 CPython 核心开发者维护的第一方包,通过 PyPI 提供时区数据。

可用性:非 WASI。

此模块在 WebAssembly 上不起作用或不可用。有关更多信息,请参阅 WebAssembly 平台

使用 ZoneInfo

ZoneInfodatetime.tzinfo 抽象基类的具体实现,旨在通过构造函数、datetime.replace 方法或 datetime.astimezone 附加到 tzinfo

>>> 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'

以这种方式构建的日期时间与日期时间算术兼容,并能在不进一步干预的情况下处理夏令时转换。

>>> dt_add = dt + timedelta(days=1)

>>> print(dt_add)
2020-11-01 12:00:00-08:00

>>> dt_add.tzname()
'PST'

这些时区还支持 PEP 495 中引入的 fold 属性。在导致模糊时间的偏移转换(例如夏令时到标准时转换)期间,当 fold=0 时,使用转换 之前 的偏移量;当 fold=1 时,使用转换 之后 的偏移量,例如

>>> 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

当从另一个时区转换时,折叠将设置为正确的值。

>>> 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 模块不直接提供时区数据,而是从系统时区数据库或第一方 PyPI 包 tzdata(如果可用)中提取时区信息。有些系统,尤其是 Windows 系统,没有可用的 IANA 数据库,因此对于需要时区数据并针对跨平台兼容性的项目,建议声明对 tzdata 的依赖。如果系统数据和 tzdata 都不可用,则所有对 ZoneInfo 的调用都将引发 ZoneInfoNotFoundError

配置数据源

当调用 ZoneInfo(key) 时,构造函数首先在 TZPATH 中指定的目录中搜索与 key 匹配的文件,如果失败则在 tzdata 包中查找匹配项。此行为可以通过三种方式进行配置:

  1. 未另行指定时的默认 TZPATH 可以在 编译时 进行配置。

  2. TZPATH 可以使用 环境变量 进行配置。

  3. 运行时,可以使用 reset_tzpath() 函数来操作搜索路径。

编译时配置

默认的 TZPATH 包含时区数据库的几个常见部署位置(除了 Windows,因为 Windows 没有“众所周知”的时区数据位置)。在 POSIX 系统上,下游分销商和从源代码构建 Python 的人如果知道其系统时区数据部署在哪里,可以通过指定编译时选项 TZPATH(或更可能的是 configure flag --with-tzpath),这是一个由 os.pathsep 分隔的字符串,来更改默认时区路径。

在所有平台上,配置的值都可以在 sysconfig.get_config_var() 中以 TZPATH 键的形式获得。

环境变量配置

在初始化 TZPATH 时(无论是在导入时还是在调用 reset_tzpath() 且不带参数时),如果存在环境变量 PYTHONTZPATHzoneinfo 模块将使用它来设置搜索路径。

PYTHONTZPATH

这是一个由 os.pathsep 分隔的字符串,包含要使用的时区搜索路径。它必须只包含绝对路径,而不是相对路径。PYTHONTZPATH 中指定的相对组件将不会被使用,但当指定相对路径时,其行为是实现定义的;CPython 将引发 InvalidTZPathWarning,但其他实现可以自由地静默忽略错误的组件或引发异常。

要将系统设置为忽略系统数据而改用 tzdata 包,请设置 PYTHONTZPATH=""

运行时配置

TZ 搜索路径也可以在运行时使用 reset_tzpath() 函数进行配置。这通常不是一个值得推荐的操作,但在需要使用特定时区路径(或需要禁用对系统时区的访问)的测试函数中使用它是合理的。

ZoneInfo

class zoneinfo.ZoneInfo(key)

一个具体的 datetime.tzinfo 子类,它表示由字符串 key 指定的 IANA 时区。对主构造函数的调用将始终返回比较起来完全相同的对象;换句话说,除非通过 ZoneInfo.clear_cache() 使缓存失效,否则对于所有 key 的值,以下断言将始终为真

a = ZoneInfo(key)
b = ZoneInfo(key)
assert a is b

key 必须是相对的、标准化的 POSIX 路径形式,不含上级引用。如果传入不符合规范的键,构造函数将引发 ValueError

如果找不到与 key 匹配的文件,构造函数将引发 ZoneInfoNotFoundError

ZoneInfo 类有两个备用构造函数

classmethod ZoneInfo.from_file(file_obj, /, key=None)

从返回字节的类文件对象(例如以二进制模式打开的文件或 io.BytesIO 对象)构造一个 ZoneInfo 对象。与主构造函数不同,这总是构造一个新对象。

key 参数设置区域的名称,用于 __str__()__repr__()

通过此构造函数创建的对象不能被 pickle 序列化(参见 pickling)。

classmethod ZoneInfo.no_cache(key)

一个绕过构造函数缓存的备用构造函数。它与主构造函数相同,但每次调用都返回一个新对象。这最有可能用于测试或演示目的,但它也可以用于创建具有不同缓存失效策略的系统。

通过此构造函数创建的对象在反序列化时也会绕过反序列化进程的缓存。

注意

使用此构造函数可能会以令人惊讶的方式改变您的日期时间语义,仅在您知道需要时才使用它。

还提供以下类方法

classmethod ZoneInfo.clear_cache(*, only_keys=None)

一个用于使 ZoneInfo 类上的缓存失效的方法。如果未传入任何参数,则所有缓存都将失效,并且下次为每个键调用主构造函数将返回一个新实例。

如果键名可迭代对象传入 only_keys 参数,则只有指定的键将从缓存中删除。only_keys 中传入但在缓存中找不到的键将被忽略。

警告

调用此函数可能会以令人惊讶的方式改变使用 ZoneInfo 的日期时间的语义;这会修改模块状态,因此可能产生广泛的影响。仅在您知道需要时才使用它。

该类有一个属性

ZoneInfo.key

这是一个只读 属性,返回传入构造函数的 key 值,该值应为 IANA 时区数据库中的查找键(例如 America/New_YorkEurope/ParisAsia/Tokyo)。

对于未指定 key 参数从文件构造的区域,此值将设置为 None

备注

尽管将这些值暴露给最终用户是一种常见做法,但这些值旨在作为表示相关区域的主键,而不一定是面向用户的元素。诸如 CLDR(Unicode Common Locale Data Repository)之类的项目可用于从这些键获取更用户友好的字符串。

字符串表示

当对 ZoneInfo 对象调用 str 时返回的字符串表示形式默认为使用 ZoneInfo.key 属性(请参见属性文档中的用法说明)

>>> 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 会回退到调用 repr()ZoneInforepr 是实现定义的,并且在不同版本之间不一定稳定,但保证它不是有效的 ZoneInfo 键。

Pickle 序列化

ZoneInfo 对象通过键进行序列化,而不是序列化所有转换数据,并且从文件构造的 ZoneInfo 对象(即使指定了 key 值)也无法进行 pickle 序列化。

ZoneInfo 文件的行为取决于它是如何构建的

  1. ZoneInfo(key): 当使用主构造函数构造时,ZoneInfo 对象通过键进行序列化,当反序列化时,反序列化过程使用主构造函数,因此这些对象预计与对同一时区的其他引用是相同的对象。例如,如果 europe_berlin_pkl 是一个包含从 ZoneInfo("Europe/Berlin") 构造的 pickle 的字符串,则预期会有以下行为:

    >>> a = ZoneInfo("Europe/Berlin")
    >>> b = pickle.loads(europe_berlin_pkl)
    >>> a is b
    True
    
  2. ZoneInfo.no_cache(key): 当从绕过缓存的构造函数构造时,ZoneInfo 对象也通过键进行序列化,但当反序列化时,反序列化过程使用绕过缓存的构造函数。如果 europe_berlin_pkl_nc 是一个包含从 ZoneInfo.no_cache("Europe/Berlin") 构造的 pickle 的字符串,则预期会有以下行为:

    >>> a = ZoneInfo("Europe/Berlin")
    >>> b = pickle.loads(europe_berlin_pkl_nc)
    >>> a is b
    False
    
  3. ZoneInfo.from_file(file_obj, /, key=None): 当从文件构造时,ZoneInfo 对象在 pickle 序列化时会引发异常。如果最终用户想要 pickle 序列化从文件构造的 ZoneInfo,建议他们使用包装类型或自定义序列化函数:要么按键序列化,要么存储文件对象的内容并序列化它。

这种序列化方法要求所需键的时区数据在序列化和反序列化端都可用,这类似于对类和函数的引用预计在序列化和反序列化环境中都存在的方式。这也意味着当在不同版本的时区数据的环境中反序列化 pickled ZoneInfo 时,不保证结果的一致性。

函数

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

全局变量

zoneinfo.TZPATH

一个只读序列,表示时区搜索路径——当从键构造 ZoneInfo 时,键将与 TZPATH 中的每个条目连接,并使用找到的第一个文件。

无论如何配置,TZPATH 只能包含绝对路径,绝不能包含相对路径。

zoneinfo.TZPATH 指向的对象可能会响应对 reset_tzpath() 的调用而改变,因此建议使用 zoneinfo.TZPATH,而不是从 zoneinfo 导入 TZPATH 或将一个长期存在的变量赋值给 zoneinfo.TZPATH

有关配置时区搜索路径的更多信息,请参见 配置数据源

异常和警告

exception zoneinfo.ZoneInfoNotFoundError

当构造 ZoneInfo 对象因系统上找不到指定键而失败时引发。这是 KeyError 的子类。

exception zoneinfo.InvalidTZPathWarning

PYTHONTZPATH 包含将被过滤掉的无效组件(例如相对路径)时引发。