| :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 ``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:: 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/ |