mirror of https://github.com/python/cpython
415 lines
16 KiB
ReStructuredText
415 lines
16 KiB
ReStructuredText
:mod:`zoneinfo` --- IANA time zone support
|
|
==========================================
|
|
|
|
.. module:: zoneinfo
|
|
:synopsis: IANA time zone support
|
|
|
|
.. versionadded:: 3.9
|
|
|
|
.. moduleauthor:: Paul Ganssle <paul@ganssle.io>
|
|
.. sectionauthor:: Paul Ganssle <paul@ganssle.io>
|
|
|
|
--------------
|
|
|
|
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 :option:`configure
|
|
flag --with-tzpath <--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:: pycon
|
|
|
|
>>> 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:: pycon
|
|
|
|
>>> 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:: 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.
|
|
|
|
.. caution::
|
|
|
|
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.
|
|
|
|
.. note::
|
|
|
|
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 :attr:`ZoneInfo.key`.
|
|
|
|
.. 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/
|