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-01-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”或“Olsen 数据库”,是时区的实际标准时区数据库,它包含在大多数 Unix 和类 Unix 操作系统中,包括 OS X。

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

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

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

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

获取本地时区

在 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

在几个方法中添加了一个新的 `is_dst` 参数来处理 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` 将指定给定日期时间应解释为未在夏令时期间发生,即指定的时间在从 DST 更改之后。这是默认值以保留现有行为。

`True` 将指定给定日期时间应解释为在夏令时期间发生,即指定的时间在从 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

    此异常作为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中时,它将不再需要。
  • InvalidTimeError继承自ValueError

资源


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

上次修改:2023-09-09 17:39:29 GMT