"zoneinfo" --- IANA 时区支持
****************************

3.9 版新加入.

======================================================================

"zoneinfo" 模块根据 **PEP 615** 的最初说明提供了具体的时区实现来支持
IANA 时区数据库。 按照默认设置，"zoneinfo" 会在可能的情况下使用系统的
时区数据；如果系统时区数据不可用，该库将回退为使用 PyPI 上提供的
tzdata 第一方包。

也參考:

  模块: "datetime"
     提供 "time" 和 "datetime" 类型，"ZoneInfo" 类被设计为可配合这两个
     类型使用。

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


使用 "ZoneInfo"
===============

"ZoneInfo" 是 "datetime.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

当执行来自另一时区的转换时，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" 模块不直接提供时区数据，而是在可能的情况下从系统时区数据库
或 PyPI 上的第一方包 tzdata 获取时区信息。 某些系统，重要的一点是
Windows 系统也包括在内，并没有可用的 IANA 数据库，因此对于要保证获取时
区信息的跨平台兼容性的项目，推荐对 tzdata 声明依赖。 如果系统数据和
tzdata 均不可用，则所有对 "ZoneInfo" 的调用都将引发
"ZoneInfoNotFoundError"。


配置数据源
----------

当 "ZoneInfo(key)" 被调用时，此构造器首先会在 "TZPATH" 所指定的目录下
搜索匹配 "key" 的文件，失败时则会在 tzdata 包中查找匹配。 此行为可通过
三种方式来配置:

1. 默认的 "TZPATH" 未通过其他方式指定时可在 编译时 进行配置。

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

3. 在 运行时，搜索路径可使用 "reset_tzpath()" 函数来修改。


编译时配置
~~~~~~~~~~

默认的 "TZPATH" 包括一些时区数据库的通用布署位置（Windows 除外，该系统
没有时区数据的“通用”位置）。 在 POSIX 系统中，下游分发者和从源码编译
Python 的开发者知道系统时区数据布署位置，他们可以通过指定编译时选项
"TZPATH" (或者更常见的是通过 "configure" 旗标 "--with-tzpath") 来改变
默认的时区路径，该选项应当是一个由 "os.pathsep" 分隔的字符串。

在所有平台上，配置值会在 "sysconfig.get_config_var()" 中以 "TZPATH" 键
的形式提供。


环境配置
~~~~~~~~

当初始化 "TZPATH" 时（在导入时或不带参数调用 "reset_tzpath()" 时），
"zoneinfo" 模块将使用环境变量 "PYTHONTZPATH"，如果变量存在则会设置搜索
路径。

PYTHONTZPATH

   这是一个以 "os.pathsep" 分隔的字符串，其中包含要使用的时区搜索路径
   。 它必须仅由绝对路径而非相对路径组成。 在 "PYTHONTZPATH" 中指定的
   相对路径部分将不会被使用，但在其他情况下当指定相对路径时的行为该实
   现是有定义的；CPython 将引发 "InvalidTZPathWarning"，而其他实现可自
   由地忽略错误部分或是引发异常。

要设置让系统忽略系统数据并改用 tzdata 包，请设置 "PYTHONTZPATH="""。


运行时配置
~~~~~~~~~~

TZ 搜索路径也可在运行时使用 "reset_tzpath()" 函数来配置。 通常并不建议
如此操作，不过在需要使用指定时区路径（或者需要禁止访问系统时区）的测试
函数中使用它则是合理的。


"ZoneInfo" 类
=============

class zoneinfo.ZoneInfo(key)

   一个具体的 "datetime.tzinfo" 子类，它代表一个由字符串 "key" 所指定
   的 IANA 时区。 对主构造器的调用将总是返回可进行标识比较的对象；但是
   另一种方式，对所有的 "key" 值通过 "ZoneInfo.clear_cache()" 禁止缓存
   失效，对以下断言将总是为真值:

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

   "key" 必须采用相对的标准化 POSIX 路径的形式，其中没有对上一层级的引
   用。 如果传入了不合要求的键则构造器将引发 "ValueError"。

   如果没有找到匹配 "key" 的文件，构造器将引发 "ZoneInfoNotFoundError"
   。

"ZoneInfo" 类具有两个替代构造器:

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

   基于一个返回字节串的文件类对象（例如一个以二进制模式打开的文件或是
   一个 "io.BytesIO" 对象）构造 "ZoneInfo" 对象。 不同于主构造器，此构
   造器总是会构造一个新对象。

   "key" 形参设置时区名称以供 "__str__()" 和 "__repr__()" 使用。

   由此构造器创建的对象不可被封存 (参见 pickling)。

classmethod ZoneInfo.no_cache(key)

   一个绕过构造器缓存的替代构造器。 它与主构造器很相似，但每次调用都会
   返回一个新对象。 此构造器在进行测试或演示时最为适用，但它也可以被用
   来创建具有不同缓存失效策略的系统。

   由此构造器创建的对象在被解封时也会绕过反序列化进程的缓存。

   警示:

     使用此构造器可以会以令人惊讶的方式改变日期时间对象的语义，只有在
     你确定你的需求时才使用它。

也可以使用以下的类方法:

classmethod ZoneInfo.clear_cache(*, only_keys=None)

   一个可在 "ZoneInfo" 类上禁用缓存的方法。 如果不传入参数，则会禁用所
   有缓存并且下次对每个键调用主构造器将返回一个新实例。

   如果将一个键名称的可迭代对象传给 "only_keys" 形参，则将只有指定的键
   会被从缓存中移除。 传给 "only_keys" 但在缓存中找不到的键会被忽略。

   警告:

     发起调用此函数可能会以令人惊讶的方式改变使用 "ZoneInfo" 的日期时
     间对象的语义；这会修改进程范围内的全局状态并因此可能产生大范围的
     影响。 只有在你确定你的需求时才使用它。

该类具有一个属性:

ZoneInfo.key

   这是一个只读的 *attribute*，它返回传给构造器的 "key" 的值，该值应为
   一个 IANA 时区数据库的查找键 (例如 "America/New_York",
   "Europe/Paris" 或 "Asia/Tokyo")。

   对于不指定 "key" 形参而是基于文件构造时区，该属性将设为 "None"。

   備註:

     Although it is a somewhat common practice to expose these to end
     users, these values are designed to be primary keys for
     representing the relevant zones and not necessarily user-facing
     elements.  Projects like CLDR (the Unicode Common Locale Data
     Repository) can be used to get more user-friendly strings from
     these keys.


String representations
----------------------

The string representation returned when calling "str" on a "ZoneInfo"
object defaults to using the "ZoneInfo.key" attribute (see the note on
usage in the attribute documentation):

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

For objects constructed from a file without specifying a "key"
parameter, "str" falls back to calling "repr()". "ZoneInfo"'s "repr"
is implementation-defined and not necessarily stable between versions,
but it is guaranteed not to be a valid "ZoneInfo" key.


Pickle serialization
--------------------

Rather than serializing all transition data, "ZoneInfo" objects are
serialized by key, and "ZoneInfo" objects constructed from files (even
those with a value for "key" specified) cannot be pickled.

The behavior of a "ZoneInfo" file depends on how it was constructed:

1. "ZoneInfo(key)": When constructed with the primary constructor, a
   "ZoneInfo" object is serialized by key, and when deserialized, the
   deserializing process uses the primary and thus it is expected that
   these are expected to be the same object as other references to the
   same time zone.  For example, if "europe_berlin_pkl" is a string
   containing a pickle constructed from "ZoneInfo("Europe/Berlin")",
   one would expect the following behavior:

      >>> a = ZoneInfo("Europe/Berlin")
      >>> b = pickle.loads(europe_berlin_pkl)
      >>> a is b
      True

2. "ZoneInfo.no_cache(key)": When constructed from the cache-bypassing
   constructor, the "ZoneInfo" object is also serialized by key, but
   when deserialized, the deserializing process uses the cache
   bypassing constructor. If "europe_berlin_pkl_nc" is a string
   containing a pickle constructed from
   "ZoneInfo.no_cache("Europe/Berlin")", one would expect the
   following behavior:

      >>> a = ZoneInfo("Europe/Berlin")
      >>> b = pickle.loads(europe_berlin_pkl_nc)
      >>> a is b
      False

3. "ZoneInfo.from_file(fobj, /, key=None)": When constructed from a
   file, the "ZoneInfo" object raises an exception on pickling. If an
   end user wants to pickle a "ZoneInfo" constructed from a file, it
   is recommended that they use a wrapper type or a custom
   serialization function: either serializing by key or storing the
   contents of the file object and serializing that.

This method of serialization requires that the time zone data for the
required key be available on both the serializing and deserializing
side, similar to the way that references to classes and functions are
expected to exist in both the serializing and deserializing
environments. It also means that no guarantees are made about the
consistency of results when unpickling a "ZoneInfo" pickled in an
environment with a different version of the time zone data.


函数
====

zoneinfo.available_timezones()

   Get a set containing all the valid keys for IANA time zones
   available anywhere on the time zone path. This is recalculated on
   every call to the function.

   This function only includes canonical zone names and does not
   include "special" zones such as those under the "posix/" and
   "right/" directories, or the "posixrules" zone.

   警示:

     This function may open a large number of files, as the best way
     to determine if a file on the time zone path is a valid time zone
     is to read the "magic string" at the beginning.

   備註:

     These values are not designed to be exposed to end-users; for
     user facing elements, applications should use something like CLDR
     (the Unicode Common Locale Data Repository) to get more user-
     friendly strings. See also the cautionary note on "ZoneInfo.key".

zoneinfo.reset_tzpath(to=None)

   Sets or resets the time zone search path ("TZPATH") for the module.
   When called with no arguments, "TZPATH" is set to the default
   value.

   Calling "reset_tzpath" will not invalidate the "ZoneInfo" cache,
   and so calls to the primary "ZoneInfo" constructor will only use
   the new "TZPATH" in the case of a cache miss.

   The "to" parameter must be a *sequence* of strings or "os.PathLike"
   and not a string, all of which must be absolute paths. "ValueError"
   will be raised if something other than an absolute path is passed.


Globals
=======

zoneinfo.TZPATH

   A read-only sequence representing the time zone search path -- when
   constructing a "ZoneInfo" from a key, the key is joined to each
   entry in the "TZPATH", and the first file found is used.

   "TZPATH" may contain only absolute paths, never relative paths,
   regardless of how it is configured.

   The object that "zoneinfo.TZPATH" points to may change in response
   to a call to "reset_tzpath()", so it is recommended to use
   "zoneinfo.TZPATH" rather than importing "TZPATH" from "zoneinfo" or
   assigning a long-lived variable to "zoneinfo.TZPATH".

   For more information on configuring the time zone search path, see
   配置数据源.


Exceptions and warnings
=======================

exception zoneinfo.ZoneInfoNotFoundError

   Raised when construction of a "ZoneInfo" object fails because the
   specified key could not be found on the system. This is a subclass
   of "KeyError".

exception zoneinfo.InvalidTZPathWarning

   Raised when "PYTHONTZPATH" contains an invalid component that will
   be filtered out, such as a relative path.
