forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bpo-40503: Add documentation and what's new entry for zoneinfo (pytho…
…nGH-20006) This adds the documentation for the `zoneinfo` module added in PEP 615: https://www.python.org/dev/peps/pep-0615/ The implementation itself was pythonGH-19909: python#19909 bpo-40503: https://bugs.python.org/issue40503 Co-authored-by: Victor Stinner <[email protected]>
- Loading branch information
Showing
4 changed files
with
430 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,390 @@ | ||
:mod:`zoneinfo` --- IANA time zone support | ||
========================================== | ||
|
||
.. module:: zoneinfo | ||
:synopsis: IANA time zone support | ||
|
||
.. versionadded:: 3.9 | ||
|
||
.. moduleauthor:: Paul Ganssle <[email protected]> | ||
.. sectionauthor:: Paul Ganssle <[email protected]> | ||
|
||
-------------- | ||
|
||
The :mod:`zoneinfo` module provides a concrete time zone implementation to | ||
support the IANA time zone database as originally specified in :pep:`615`. By | ||
default, :mod:`zoneinfo` uses the system's time zone data if available; if no | ||
system time zone data is available, the library will fall back to using the | ||
first-party `tzdata`_ package available on PyPI. | ||
|
||
.. seealso:: | ||
|
||
Module: :mod:`datetime` | ||
Provides the :class:`~datetime.time` and :class:`~datetime.datetime` | ||
types with which the :class:`ZoneInfo` class is designed to be used. | ||
|
||
Package `tzdata`_ | ||
First-party package maintained by the CPython core developers to supply | ||
time zone data via PyPI. | ||
|
||
|
||
Using ``ZoneInfo`` | ||
------------------ | ||
|
||
:class:`ZoneInfo` is a concrete implementation of the :class:`datetime.tzinfo` | ||
abstract base class, and is intended to be attached to ``tzinfo``, either via | ||
the constructor, the :meth:`datetime.replace <datetime.datetime.replace>` | ||
method or :meth:`datetime.astimezone <datetime.datetime.astimezone>`:: | ||
|
||
>>> 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' | ||
|
||
Datetimes constructed in this way are compatible with datetime arithmetic and | ||
handle daylight saving time transitions with no further intervention:: | ||
|
||
>>> dt_add = dt + timedelta(days=1) | ||
|
||
>>> print(dt_add) | ||
2020-11-01 12:00:00-08:00 | ||
|
||
>>> dt_add.tzname() | ||
'PST' | ||
|
||
These time zones also support the :attr:`~datetime.datetime.fold` attribute | ||
introduced in :pep:`495`. During offset transitions which induce ambiguous | ||
times (such as a daylight saving time to standard time transition), the offset | ||
from *before* the transition is used when ``fold=0``, and the offset *after* | ||
the transition is used when ``fold=1``, for example:: | ||
|
||
>>> 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 | ||
|
||
When converting from another time zone, the fold will be set to the correct | ||
value:: | ||
|
||
>>> 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 | ||
|
||
Data sources | ||
------------ | ||
|
||
The ``zoneinfo`` module does not directly provide time zone data, and instead | ||
pulls time zone information from the system time zone database or the | ||
first-party PyPI package `tzdata`_, if available. Some systems, including | ||
notably Windows systems, do not have an IANA database available, and so for | ||
projects targeting cross-platform compatibility that require time zone data, it | ||
is recommended to declare a dependency on tzdata. If neither system data nor | ||
tzdata are available, all calls to :class:`ZoneInfo` will raise | ||
:exc:`ZoneInfoNotFoundError`. | ||
|
||
.. _zoneinfo_data_configuration: | ||
|
||
Configuring the data sources | ||
**************************** | ||
|
||
When ``ZoneInfo(key)`` is called, the constructor first searches the | ||
directories specified in :data:`TZPATH` for a file matching ``key``, and on | ||
failure looks for a match in the tzdata package. This behavior can be | ||
configured in three ways: | ||
|
||
1. The default :data:`TZPATH` when not otherwise specified can be configured at | ||
:ref:`compile time <zoneinfo_data_compile_time_config>`. | ||
2. :data:`TZPATH` can be configured using :ref:`an environment variable | ||
<zoneinfo_data_environment_var>`. | ||
3. At :ref:`runtime <zoneinfo_data_runtime_config>`, the search path can be | ||
manipulated using the :func:`reset_tzpath` function. | ||
|
||
.. _zoneinfo_data_compile_time_config: | ||
|
||
Compile-time configuration | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
The default :data:`TZPATH` includes several common deployment locations for the | ||
time zone database (except on Windows, where there are no "well-known" | ||
locations for time zone data). On POSIX systems, downstream distributors and | ||
those building Python from source who know where their system | ||
time zone data is deployed may change the default time zone path by specifying | ||
the compile-time option ``TZPATH`` (or, more likely, the ``configure`` flag | ||
``--with-tzpath``), which should be a string delimited by :data:`os.pathsep`. | ||
|
||
On all platforms, the configured value is available as the ``TZPATH`` key in | ||
:func:`sysconfig.get_config_var`. | ||
|
||
.. _zoneinfo_data_environment_var: | ||
|
||
Environment configuration | ||
^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
When initializing :data:`TZPATH` (either at import time or whenever | ||
:func:`reset_tzpath` is called with no arguments), the ``zoneinfo`` module will | ||
use the environment variable ``PYTHONTZPATH``, if it exists, to set the search | ||
path. | ||
|
||
.. envvar:: PYTHONTZPATH | ||
|
||
This is an :data:`os.pathsep`-separated string containing the time zone | ||
search path to use. It must consist of only absolute rather than relative | ||
paths. Relative components specified in ``PYTHONTZPATH`` will not be used, | ||
but otherwise the behavior when a relative path is specified is | ||
implementation-defined; CPython will raise :exc:`InvalidTZPathWarning`, but | ||
other implementations are free to silently ignore the erroneous component | ||
or raise an exception. | ||
|
||
To set the system to ignore the system data and use the tzdata package | ||
instead, set ``PYTHONTZPATH=""``. | ||
|
||
.. _zoneinfo_data_runtime_config: | ||
|
||
Runtime configuration | ||
^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
The TZ search path can also be configured at runtime using the | ||
:func:`reset_tzpath` function. This is generally not an advisable operation, | ||
though it is reasonable to use it in test functions that require the use of a | ||
specific time zone path (or require disabling access to the system time zones). | ||
|
||
|
||
The ``ZoneInfo`` class | ||
---------------------- | ||
|
||
.. class:: ZoneInfo(key) | ||
|
||
A concrete :class:`datetime.tzinfo` subclass that represents an IANA time | ||
zone specified by the string ``key``. Calls to the primary constructor will | ||
always return objects that compare identically; put another way, barring | ||
cache invalidation via :meth:`ZoneInfo.clear_cache`, for all values of | ||
``key``, the following assertion will always be true: | ||
|
||
.. code-block:: python | ||
a = ZoneInfo(key) | ||
b = ZoneInfo(key) | ||
assert a is b | ||
``key`` must be in the form of a relative, normalized POSIX path, with no | ||
up-level references. The constructor will raise :exc:`ValueError` if a | ||
non-conforming key is passed. | ||
|
||
If no file matching ``key`` is found, the constructor will raise | ||
:exc:`ZoneInfoNotFoundError`. | ||
|
||
|
||
The ``ZoneInfo`` class has two alternate constructors: | ||
|
||
.. classmethod:: ZoneInfo.from_file(fobj, /, key=None) | ||
|
||
Constructs a ``ZoneInfo`` object from a file-like object returning bytes | ||
(e.g. a file opened in binary mode or an :class:`io.BytesIO` object). | ||
Unlike the primary constructor, this always constructs a new object. | ||
|
||
The ``key`` parameter sets the name of the zone for the purposes of | ||
:py:meth:`~object.__str__` and :py:meth:`~object.__repr__`. | ||
|
||
Objects created via this constructor cannot be pickled (see `pickling`_). | ||
|
||
.. classmethod:: ZoneInfo.no_cache(key) | ||
|
||
An alternate constructor that bypasses the constructor's cache. It is | ||
identical to the primary constructor, but returns a new object on each | ||
call. This is most likely to be useful for testing or demonstration | ||
purposes, but it can also be used to create a system with a different cache | ||
invalidation strategy. | ||
|
||
Objects created via this constructor will also bypass the cache of a | ||
deserializing process when unpickled. | ||
|
||
.. TODO: Add "See `cache_behavior`_" reference when that section is ready. | ||
.. caution:: | ||
|
||
Using this constructor may change the semantics of your datetimes in | ||
surprising ways, only use it if you know that you need to. | ||
|
||
The following class methods are also available: | ||
|
||
.. classmethod:: ZoneInfo.clear_cache(*, only_keys=None) | ||
|
||
A method for invalidating the cache on the ``ZoneInfo`` class. If no | ||
arguments are passed, all caches are invalidated and the next call to | ||
the primary constructor for each key will return a new instance. | ||
|
||
If an iterable of key names is passed to the ``only_keys`` parameter, only | ||
the specified keys will be removed from the cache. Keys passed to | ||
``only_keys`` but not found in the cache are ignored. | ||
|
||
.. TODO: Add "See `cache_behavior`_" reference when that section is ready. | ||
.. warning:: | ||
|
||
Invoking this function may change the semantics of datetimes using | ||
``ZoneInfo`` in surprising ways; this modifies process-wide global state | ||
and thus may have wide-ranging effects. Only use it if you know that you | ||
need to. | ||
|
||
The class has one attribute: | ||
|
||
.. attribute:: ZoneInfo.key | ||
|
||
This is a read-only :term:`attribute` that returns the value of ``key`` | ||
passed to the constructor, which should be a lookup key in the IANA time | ||
zone database (e.g. ``America/New_York``, ``Europe/Paris`` or | ||
``Asia/Tokyo``). | ||
|
||
For zones constructed from file without specifying a ``key`` parameter, | ||
this will be set to ``None``. | ||
|
||
.. note:: | ||
|
||
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 :py:class:`str` on a | ||
:class:`ZoneInfo` object defaults to using the :attr:`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 :func:`repr`. ``ZoneInfo``'s ``repr`` is | ||
implementation-defined and not necessarily stable between versions, but it is | ||
guaranteed not to be a valid ``ZoneInfo`` key. | ||
|
||
.. _pickling: | ||
|
||
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: | ||
|
||
.. code-block:: | ||
>>> 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: | ||
|
||
.. code-block:: | ||
>>> 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. | ||
|
||
Functions | ||
--------- | ||
|
||
.. function:: reset_tzpath(to=None) | ||
|
||
Sets or resets the time zone search path (:data:`TZPATH`) for the module. | ||
When called with no arguments, :data:`TZPATH` is set to the default value. | ||
|
||
Calling ``reset_tzpath`` will not invalidate the :class:`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 :term:`sequence` of strings or | ||
:class:`os.PathLike` and not a string, all of which must be absolute paths. | ||
:exc:`ValueError` will be raised if something other than an absolute path | ||
is passed. | ||
|
||
Globals | ||
------- | ||
|
||
.. data:: 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 :func:`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 | ||
:ref:`zoneinfo_data_configuration`. | ||
|
||
Exceptions and warnings | ||
----------------------- | ||
|
||
.. exception:: ZoneInfoNotFoundError | ||
|
||
Raised when construction of a :class:`ZoneInfo` object fails because the | ||
specified key could not be found on the system. This is a subclass of | ||
:exc:`KeyError`. | ||
|
||
.. exception:: InvalidTZPathWarning | ||
|
||
Raised when :envvar:`PYTHONTZPATH` contains an invalid component that will | ||
be filtered out, such as a relative path. | ||
|
||
.. Links and references: | ||
.. _tzdata: https://pypi.org/project/tzdata/ |
Oops, something went wrong.