Skip to content

Commit b17e49e

Browse files
pgansslevstinner
andauthored
bpo-40503: Add documentation and what's new entry for zoneinfo (GH-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 GH-19909: #19909 bpo-40503: https://bugs.python.org/issue40503 Co-authored-by: Victor Stinner <[email protected]>
1 parent 1b97b9b commit b17e49e

File tree

4 files changed

+430
-1
lines changed

4 files changed

+430
-1
lines changed

Doc/library/datatypes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The following modules are documented in this chapter:
2020
.. toctree::
2121

2222
datetime.rst
23+
zoneinfo.rst
2324
calendar.rst
2425
collections.rst
2526
collections.abc.rst

Doc/library/zoneinfo.rst

Lines changed: 390 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
:mod:`zoneinfo` --- IANA time zone support
2+
==========================================
3+
4+
.. module:: zoneinfo
5+
:synopsis: IANA time zone support
6+
7+
.. versionadded:: 3.9
8+
9+
.. moduleauthor:: Paul Ganssle <[email protected]>
10+
.. sectionauthor:: Paul Ganssle <[email protected]>
11+
12+
--------------
13+
14+
The :mod:`zoneinfo` module provides a concrete time zone implementation to
15+
support the IANA time zone database as originally specified in :pep:`615`. By
16+
default, :mod:`zoneinfo` uses the system's time zone data if available; if no
17+
system time zone data is available, the library will fall back to using the
18+
first-party `tzdata`_ package available on PyPI.
19+
20+
.. seealso::
21+
22+
Module: :mod:`datetime`
23+
Provides the :class:`~datetime.time` and :class:`~datetime.datetime`
24+
types with which the :class:`ZoneInfo` class is designed to be used.
25+
26+
Package `tzdata`_
27+
First-party package maintained by the CPython core developers to supply
28+
time zone data via PyPI.
29+
30+
31+
Using ``ZoneInfo``
32+
------------------
33+
34+
:class:`ZoneInfo` is a concrete implementation of the :class:`datetime.tzinfo`
35+
abstract base class, and is intended to be attached to ``tzinfo``, either via
36+
the constructor, the :meth:`datetime.replace <datetime.datetime.replace>`
37+
method or :meth:`datetime.astimezone <datetime.datetime.astimezone>`::
38+
39+
>>> from zoneinfo import ZoneInfo
40+
>>> from datetime import datetime, timedelta
41+
42+
>>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
43+
>>> print(dt)
44+
2020-10-31 12:00:00-07:00
45+
46+
>>> dt.tzname()
47+
'PDT'
48+
49+
Datetimes constructed in this way are compatible with datetime arithmetic and
50+
handle daylight saving time transitions with no further intervention::
51+
52+
>>> dt_add = dt + timedelta(days=1)
53+
54+
>>> print(dt_add)
55+
2020-11-01 12:00:00-08:00
56+
57+
>>> dt_add.tzname()
58+
'PST'
59+
60+
These time zones also support the :attr:`~datetime.datetime.fold` attribute
61+
introduced in :pep:`495`. During offset transitions which induce ambiguous
62+
times (such as a daylight saving time to standard time transition), the offset
63+
from *before* the transition is used when ``fold=0``, and the offset *after*
64+
the transition is used when ``fold=1``, for example::
65+
66+
>>> dt = datetime(2020, 11, 1, 1, tzinfo=ZoneInfo("America/Los_Angeles"))
67+
>>> print(dt)
68+
2020-11-01 01:00:00-07:00
69+
70+
>>> print(dt.replace(fold=1))
71+
2020-11-01 01:00:00-08:00
72+
73+
When converting from another time zone, the fold will be set to the correct
74+
value::
75+
76+
>>> from datetime import timezone
77+
>>> LOS_ANGELES = ZoneInfo("America/Los_Angeles")
78+
>>> dt_utc = datetime(2020, 11, 1, 8, tzinfo=timezone.utc)
79+
80+
>>> # Before the PDT -> PST transition
81+
>>> print(dt_utc.astimezone(LOS_ANGELES))
82+
2020-11-01 01:00:00-07:00
83+
84+
>>> # After the PDT -> PST transition
85+
>>> print((dt_utc + timedelta(hours=1)).astimezone(LOS_ANGELES))
86+
2020-11-01 01:00:00-08:00
87+
88+
Data sources
89+
------------
90+
91+
The ``zoneinfo`` module does not directly provide time zone data, and instead
92+
pulls time zone information from the system time zone database or the
93+
first-party PyPI package `tzdata`_, if available. Some systems, including
94+
notably Windows systems, do not have an IANA database available, and so for
95+
projects targeting cross-platform compatibility that require time zone data, it
96+
is recommended to declare a dependency on tzdata. If neither system data nor
97+
tzdata are available, all calls to :class:`ZoneInfo` will raise
98+
:exc:`ZoneInfoNotFoundError`.
99+
100+
.. _zoneinfo_data_configuration:
101+
102+
Configuring the data sources
103+
****************************
104+
105+
When ``ZoneInfo(key)`` is called, the constructor first searches the
106+
directories specified in :data:`TZPATH` for a file matching ``key``, and on
107+
failure looks for a match in the tzdata package. This behavior can be
108+
configured in three ways:
109+
110+
1. The default :data:`TZPATH` when not otherwise specified can be configured at
111+
:ref:`compile time <zoneinfo_data_compile_time_config>`.
112+
2. :data:`TZPATH` can be configured using :ref:`an environment variable
113+
<zoneinfo_data_environment_var>`.
114+
3. At :ref:`runtime <zoneinfo_data_runtime_config>`, the search path can be
115+
manipulated using the :func:`reset_tzpath` function.
116+
117+
.. _zoneinfo_data_compile_time_config:
118+
119+
Compile-time configuration
120+
^^^^^^^^^^^^^^^^^^^^^^^^^^
121+
122+
The default :data:`TZPATH` includes several common deployment locations for the
123+
time zone database (except on Windows, where there are no "well-known"
124+
locations for time zone data). On POSIX systems, downstream distributors and
125+
those building Python from source who know where their system
126+
time zone data is deployed may change the default time zone path by specifying
127+
the compile-time option ``TZPATH`` (or, more likely, the ``configure`` flag
128+
``--with-tzpath``), which should be a string delimited by :data:`os.pathsep`.
129+
130+
On all platforms, the configured value is available as the ``TZPATH`` key in
131+
:func:`sysconfig.get_config_var`.
132+
133+
.. _zoneinfo_data_environment_var:
134+
135+
Environment configuration
136+
^^^^^^^^^^^^^^^^^^^^^^^^^
137+
138+
When initializing :data:`TZPATH` (either at import time or whenever
139+
:func:`reset_tzpath` is called with no arguments), the ``zoneinfo`` module will
140+
use the environment variable ``PYTHONTZPATH``, if it exists, to set the search
141+
path.
142+
143+
.. envvar:: PYTHONTZPATH
144+
145+
This is an :data:`os.pathsep`-separated string containing the time zone
146+
search path to use. It must consist of only absolute rather than relative
147+
paths. Relative components specified in ``PYTHONTZPATH`` will not be used,
148+
but otherwise the behavior when a relative path is specified is
149+
implementation-defined; CPython will raise :exc:`InvalidTZPathWarning`, but
150+
other implementations are free to silently ignore the erroneous component
151+
or raise an exception.
152+
153+
To set the system to ignore the system data and use the tzdata package
154+
instead, set ``PYTHONTZPATH=""``.
155+
156+
.. _zoneinfo_data_runtime_config:
157+
158+
Runtime configuration
159+
^^^^^^^^^^^^^^^^^^^^^
160+
161+
The TZ search path can also be configured at runtime using the
162+
:func:`reset_tzpath` function. This is generally not an advisable operation,
163+
though it is reasonable to use it in test functions that require the use of a
164+
specific time zone path (or require disabling access to the system time zones).
165+
166+
167+
The ``ZoneInfo`` class
168+
----------------------
169+
170+
.. class:: ZoneInfo(key)
171+
172+
A concrete :class:`datetime.tzinfo` subclass that represents an IANA time
173+
zone specified by the string ``key``. Calls to the primary constructor will
174+
always return objects that compare identically; put another way, barring
175+
cache invalidation via :meth:`ZoneInfo.clear_cache`, for all values of
176+
``key``, the following assertion will always be true:
177+
178+
.. code-block:: python
179+
180+
a = ZoneInfo(key)
181+
b = ZoneInfo(key)
182+
assert a is b
183+
184+
``key`` must be in the form of a relative, normalized POSIX path, with no
185+
up-level references. The constructor will raise :exc:`ValueError` if a
186+
non-conforming key is passed.
187+
188+
If no file matching ``key`` is found, the constructor will raise
189+
:exc:`ZoneInfoNotFoundError`.
190+
191+
192+
The ``ZoneInfo`` class has two alternate constructors:
193+
194+
.. classmethod:: ZoneInfo.from_file(fobj, /, key=None)
195+
196+
Constructs a ``ZoneInfo`` object from a file-like object returning bytes
197+
(e.g. a file opened in binary mode or an :class:`io.BytesIO` object).
198+
Unlike the primary constructor, this always constructs a new object.
199+
200+
The ``key`` parameter sets the name of the zone for the purposes of
201+
:py:meth:`~object.__str__` and :py:meth:`~object.__repr__`.
202+
203+
Objects created via this constructor cannot be pickled (see `pickling`_).
204+
205+
.. classmethod:: ZoneInfo.no_cache(key)
206+
207+
An alternate constructor that bypasses the constructor's cache. It is
208+
identical to the primary constructor, but returns a new object on each
209+
call. This is most likely to be useful for testing or demonstration
210+
purposes, but it can also be used to create a system with a different cache
211+
invalidation strategy.
212+
213+
Objects created via this constructor will also bypass the cache of a
214+
deserializing process when unpickled.
215+
216+
.. TODO: Add "See `cache_behavior`_" reference when that section is ready.
217+
218+
.. caution::
219+
220+
Using this constructor may change the semantics of your datetimes in
221+
surprising ways, only use it if you know that you need to.
222+
223+
The following class methods are also available:
224+
225+
.. classmethod:: ZoneInfo.clear_cache(*, only_keys=None)
226+
227+
A method for invalidating the cache on the ``ZoneInfo`` class. If no
228+
arguments are passed, all caches are invalidated and the next call to
229+
the primary constructor for each key will return a new instance.
230+
231+
If an iterable of key names is passed to the ``only_keys`` parameter, only
232+
the specified keys will be removed from the cache. Keys passed to
233+
``only_keys`` but not found in the cache are ignored.
234+
235+
.. TODO: Add "See `cache_behavior`_" reference when that section is ready.
236+
237+
.. warning::
238+
239+
Invoking this function may change the semantics of datetimes using
240+
``ZoneInfo`` in surprising ways; this modifies process-wide global state
241+
and thus may have wide-ranging effects. Only use it if you know that you
242+
need to.
243+
244+
The class has one attribute:
245+
246+
.. attribute:: ZoneInfo.key
247+
248+
This is a read-only :term:`attribute` that returns the value of ``key``
249+
passed to the constructor, which should be a lookup key in the IANA time
250+
zone database (e.g. ``America/New_York``, ``Europe/Paris`` or
251+
``Asia/Tokyo``).
252+
253+
For zones constructed from file without specifying a ``key`` parameter,
254+
this will be set to ``None``.
255+
256+
.. note::
257+
258+
Although it is a somewhat common practice to expose these to end users,
259+
these values are designed to be primary keys for representing the
260+
relevant zones and not necessarily user-facing elements. Projects like
261+
CLDR (the Unicode Common Locale Data Repository) can be used to get
262+
more user-friendly strings from these keys.
263+
264+
String representations
265+
**********************
266+
267+
The string representation returned when calling :py:class:`str` on a
268+
:class:`ZoneInfo` object defaults to using the :attr:`ZoneInfo.key` attribute (see
269+
the note on usage in the attribute documentation)::
270+
271+
>>> zone = ZoneInfo("Pacific/Kwajalein")
272+
>>> str(zone)
273+
'Pacific/Kwajalein'
274+
275+
>>> dt = datetime(2020, 4, 1, 3, 15, tzinfo=zone)
276+
>>> f"{dt.isoformat()} [{dt.tzinfo}]"
277+
'2020-04-01T03:15:00+12:00 [Pacific/Kwajalein]'
278+
279+
For objects constructed from a file without specifying a ``key`` parameter,
280+
``str`` falls back to calling :func:`repr`. ``ZoneInfo``'s ``repr`` is
281+
implementation-defined and not necessarily stable between versions, but it is
282+
guaranteed not to be a valid ``ZoneInfo`` key.
283+
284+
.. _pickling:
285+
286+
Pickle serialization
287+
********************
288+
289+
Rather than serializing all transition data, ``ZoneInfo`` objects are
290+
serialized by key, and ``ZoneInfo`` objects constructed from files (even those
291+
with a value for ``key`` specified) cannot be pickled.
292+
293+
The behavior of a ``ZoneInfo`` file depends on how it was constructed:
294+
295+
1. ``ZoneInfo(key)``: When constructed with the primary constructor, a
296+
``ZoneInfo`` object is serialized by key, and when deserialized, the
297+
deserializing process uses the primary and thus it is expected that these
298+
are expected to be the same object as other references to the same time
299+
zone. For example, if ``europe_berlin_pkl`` is a string containing a pickle
300+
constructed from ``ZoneInfo("Europe/Berlin")``, one would expect the
301+
following behavior:
302+
303+
.. code-block::
304+
305+
>>> a = ZoneInfo("Europe/Berlin")
306+
>>> b = pickle.loads(europe_berlin_pkl)
307+
>>> a is b
308+
True
309+
310+
2. ``ZoneInfo.no_cache(key)``: When constructed from the cache-bypassing
311+
constructor, the ``ZoneInfo`` object is also serialized by key, but when
312+
deserialized, the deserializing process uses the cache bypassing
313+
constructor. If ``europe_berlin_pkl_nc`` is a string containing a pickle
314+
constructed from ``ZoneInfo.no_cache("Europe/Berlin")``, one would expect
315+
the following behavior:
316+
317+
.. code-block::
318+
319+
>>> a = ZoneInfo("Europe/Berlin")
320+
>>> b = pickle.loads(europe_berlin_pkl_nc)
321+
>>> a is b
322+
False
323+
324+
3. ``ZoneInfo.from_file(fobj, /, key=None)``: When constructed from a file, the
325+
``ZoneInfo`` object raises an exception on pickling. If an end user wants to
326+
pickle a ``ZoneInfo`` constructed from a file, it is recommended that they
327+
use a wrapper type or a custom serialization function: either serializing by
328+
key or storing the contents of the file object and serializing that.
329+
330+
This method of serialization requires that the time zone data for the required
331+
key be available on both the serializing and deserializing side, similar to the
332+
way that references to classes and functions are expected to exist in both the
333+
serializing and deserializing environments. It also means that no guarantees
334+
are made about the consistency of results when unpickling a ``ZoneInfo``
335+
pickled in an environment with a different version of the time zone data.
336+
337+
Functions
338+
---------
339+
340+
.. function:: reset_tzpath(to=None)
341+
342+
Sets or resets the time zone search path (:data:`TZPATH`) for the module.
343+
When called with no arguments, :data:`TZPATH` is set to the default value.
344+
345+
Calling ``reset_tzpath`` will not invalidate the :class:`ZoneInfo` cache,
346+
and so calls to the primary ``ZoneInfo`` constructor will only use the new
347+
``TZPATH`` in the case of a cache miss.
348+
349+
The ``to`` parameter must be a :term:`sequence` of strings or
350+
:class:`os.PathLike` and not a string, all of which must be absolute paths.
351+
:exc:`ValueError` will be raised if something other than an absolute path
352+
is passed.
353+
354+
Globals
355+
-------
356+
357+
.. data:: TZPATH
358+
359+
A read-only sequence representing the time zone search path -- when
360+
constructing a ``ZoneInfo`` from a key, the key is joined to each entry in
361+
the ``TZPATH``, and the first file found is used.
362+
363+
``TZPATH`` may contain only absolute paths, never relative paths,
364+
regardless of how it is configured.
365+
366+
The object that ``zoneinfo.TZPATH`` points to may change in response to a
367+
call to :func:`reset_tzpath`, so it is recommended to use
368+
``zoneinfo.TZPATH`` rather than importing ``TZPATH`` from ``zoneinfo`` or
369+
assigning a long-lived variable to ``zoneinfo.TZPATH``.
370+
371+
For more information on configuring the time zone search path, see
372+
:ref:`zoneinfo_data_configuration`.
373+
374+
Exceptions and warnings
375+
-----------------------
376+
377+
.. exception:: ZoneInfoNotFoundError
378+
379+
Raised when construction of a :class:`ZoneInfo` object fails because the
380+
specified key could not be found on the system. This is a subclass of
381+
:exc:`KeyError`.
382+
383+
.. exception:: InvalidTZPathWarning
384+
385+
Raised when :envvar:`PYTHONTZPATH` contains an invalid component that will
386+
be filtered out, such as a relative path.
387+
388+
.. Links and references:
389+
390+
.. _tzdata: https://pypi.org/project/tzdata/

0 commit comments

Comments
 (0)