Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 431 – 时区支持改进

作者:
Lennart Regebro <regebro at gmail.com>
BDFL 委托
Barry Warsaw <barry at python.org>
状态:
已取代
类型:
标准跟踪
创建日期:
2012年12月11日
发布历史:
2012年12月11日,2012年12月28日,2013年1月28日
取代者:
615

目录

摘要

本 PEP 提议在 Python 标准库中实现具体的时区支持,并改进时区 API 以处理夏令时 (DST) 变更期间的模糊时间规范。

撤回

经过长时间的讨论,我发现我原以为是 datetime 实现中的问题,实际上是有意为之。这些问题包括在进行日期时间算术时完全忽略 DST 转换。这使得本 PEP 中的 is_dst 标志变得毫无意义,因为它们没有有用的功能。datetime 在设计上不区分模糊日期时间,也永远不会。

因此,我撤回本 PEP。

更新PEP 615“标准库中对 IANA 时区数据库的支持”已将 zoneinfo 模块添加到 Python 3.9 并取代了本 PEP。

提案

具体的时区支持

Python 中的时区支持在标准库中没有具体的实现,除了支持固定偏移的 tzinfo 基类。要正确支持时区,您需要包含一个包含所有时区(包括当前和历史时区)以及夏令时变更的数据库。但是此类信息会频繁更改,因此即使我们在 Python 版本中包含最新信息,该信息也将在几个月后过时。

因此,时区支持只能通过两个第三方模块获得:pytzdateutil,两者都包含并封装了“zoneinfo”数据库。这个数据库,也称为“tz”或“The Olsen database”,是事实上的时区标准数据库,它包含在大多数 Unix 和类 Unix 操作系统中,包括 OS X。

这为我们提供了将支持 zoneinfo 数据的代码包含在标准库中的机会,但默认情况下使用操作系统的副本数据,该数据通常会通过操作系统或发行版的更新机制保持最新。

对于不包含 zoneinfo 数据库的操作系统(例如 Windows),Python 源代码分发将包含 zoneinfo 数据库的副本,并且包含最新 zoneinfo 数据库的分发也将在 Python Package Index 上提供,因此可以使用 Python 打包工具(例如 easy_installpip)轻松安装。这也可以在不再接收更新的 Unix 系统上完成,因为这些系统具有过时数据库。

通过这种机制,Python 将在任何平台上的标准库中拥有全面的时区支持,并且一个简单的包安装将为那些未包含 zoneinfo 数据库的平台(例如 Windows)或不再提供操作系统更新的平台提供更新的时区数据库。

时区支持将通过将 datetime 模块转换为包,并在 datetime 中添加基于 Stuart Bishop 的 pytz 模块的时区支持来实现。

获取本地时区

在 Unix 系统上,没有标准方法可以找到正在使用的时区名称。所有可用的信息都是时区缩写,例如 ESTPDT,但这些缩写中的许多都是模糊的,因此您不能依赖它们来确定您所在的地区。

然而,有一个标准可以找到已编译的时区信息,因为它位于 /etc/localtime 中。因此,即使您不知道时区名称,也可以创建一个具有正确时区信息的本地时区对象。datetime 中应该提供一个函数来返回本地时区。

对此的支持将通过将 Lennart Regebro 的 tzlocal 模块集成到新的 datetime 模块中来实现。

对于 Windows,它将查找本地 Windows 时区名称,并使用 Unicode 联盟提供的 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 提议将这些 is_dst 参数添加到 datetime API 的相关方法中,从而将此功能直接添加到 datetime 中。这可能是本 PEP 最难的部分,因为它涉及使用此功能更新 datetime 库的 C 版本,因为这涉及编写新代码,而不仅仅是重组现有的外部库。

实现API

zoneinfo 数据库

最新版本的 zoneinfo 数据库应存在于 Python 源代码控制系统的 Lib/tzdata 目录中。此数据库副本应在每个 Python 功能和错误修复版本发布之前更新,但对于处于仅安全修复模式的 Python 版本发布则不更新。

更新数据库的脚本将位于 Tools/ 中,发布说明将更新以包含此更新。

将实现新的配置选项 --enable-internal-timezone-database--disable-internal-timezone-database,以在从源代码安装时启用和禁用此数据库的安装。源代码安装将默认安装它们。

对于具有系统提供的 zoneinfo 数据库的系统的二进制安装程序,可以跳过安装包含的数据库,因为它永远不会用于这些平台。对于其他平台,例如 Windows,二进制安装程序必须安装包含的数据库。

datetime 模块的更改

新时区支持的公共 API 包含一个新类、一个新函数、一个新异常和四个新集合。除此之外,datetime 对象上的几个方法获得了新的 is_dst 参数。

新类 dsttimezone

此类提供了 tzinfo 基类的具体实现,该基类实现了 DST 支持。

新函数 zoneinfo(name=None, db_path=None)

此函数接受一个名称字符串,该字符串必须是指定有效 zoneinfo 时区的字符串,即“US/Eastern”、“Europe/Warsaw”或“Etc/GMT”。如果未给出,将查找本地时区。如果给出了无效的时区名称,或者无法检索本地时区,则该函数将引发 UnknownTimeZoneError

该函数还接受 zoneinfo 数据库位置的可选路径,该路径应使用。如果未指定,该函数将按以下顺序查找数据库

  1. 检查 tzdata-update 模块是否已安装,然后使用该数据库。
  2. 如果存在,使用 /usr/share/zoneinfo 中的数据库。
  3. 使用 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 (默认值)、TrueNone

False 将指定给定的 datetime 应解释为未发生在夏令时期间,即指定的时间在 DST 转换之后。这是默认值,以保留现有行为。

True 将指定给定的 datetime 应解释为发生在夏令时期间,即指定的时间在 DST 转换之前。

如果指定的时间在 DST 转换期间,则 None 将引发 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

    此异常作为 AmbiguousTimeErrorNonExistentTimeError 的基类,使您能够分别捕获这两个异常。它将是 ValueError 的子类,因此您可以将其与 2011 年 2 月 29 日等输入一起捕获。

  • AmbiguousTimeError

    在将 is_dst 设置为 None 时,如果给定的日期时间规范不明确,则会引发此异常

    >>> 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(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 具有 localize()normalize() 函数,用于解决 tzinfo 没有 is_dst 的问题。当 is_dst 直接在 datetime.tzinfo 中实现时,它们就不再需要了。
  • timezone() 函数被称为 zoneinfo(),以避免与 Python 3.2 中引入的 timezone 类冲突。
  • 如果没有参数调用 zoneinfo(),它将返回本地时区。
  • pytz.StaticTzInfo 用于为静态时区提供 is_dst 支持。当 is_dst 支持包含在 datetime.tzinfo 中时,它就不再需要了。
  • InvalidTimeErrorValueError 的子类。

资源


来源:https://github.com/python/peps/blob/main/peps/pep-0431.rst

最后修改时间:2025-02-01 08:59:27 GMT