Skip to content

Commit 8b10cb3

Browse files
committed
Add documentation for zoneinfo module
1 parent 1b97b9b commit 8b10cb3

File tree

2 files changed

+388
-0
lines changed

2 files changed

+388
-0
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: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
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). Downstream distributors and those building
125+
Python from source who know where their system time zone data is deployed may
126+
change the default time zone path by specifying the compile-time option
127+
``PYTHONTZPATHDEFAULT``, which should be a string delimited by
128+
:data:`os.pathsep`.
129+
130+
.. _zoneinfo_data_environment_var:
131+
132+
Environment configuration
133+
^^^^^^^^^^^^^^^^^^^^^^^^^
134+
135+
When initializing :data:`TZPATH` (either at import time or whenever
136+
:func:`reset_tzpath` is called with no arguments), the ``zoneinfo`` module will
137+
use the environment variable ``PYTHONTZPATH``, if it exists, to set the search
138+
path.
139+
140+
.. envvar:: PYTHONTZPATH
141+
142+
This is an :data:`os.pathsep`-separated string containing the time zone
143+
search path to use. It must consist of only absolute rather than relative
144+
paths. Relative components specified in ``PYTHONTZPATH`` will not be used,
145+
but otherwise the behavior when a relative path is specified is
146+
implementation-defined; CPython will raise :exc:`InvalidTZPathWarning`, but
147+
other implementations are free to silently ignore the erroneous component
148+
or raise an exception.
149+
150+
To set the system to ignore the system data and use the tzdata package
151+
instead, set ``PYTHONTZPATH=""``.
152+
153+
.. _zoneinfo_data_runtime_config:
154+
155+
Runtime configuration
156+
^^^^^^^^^^^^^^^^^^^^^
157+
158+
The TZ search path can also be configured at runtime using the
159+
:func:`reset_tzpath` function. This is generally not an advisable operation,
160+
though it is reasonable to use it in test functions that require the use of a
161+
specific time zone path (or require disabling access to the system time zones).
162+
163+
164+
The ``ZoneInfo`` class
165+
----------------------
166+
167+
.. class:: ZoneInfo(key)
168+
169+
A concrete :class:`datetime.tzinfo` subclass that represents an IANA time
170+
zone specified by the string ``key``. Calls to the primary constructor will
171+
always return objects that compare identically; put another way, barring
172+
cache invalidation via :meth:`ZoneInfo.clear_cache`, for all values of
173+
``key``, the following assertion will always be true:
174+
175+
.. code-block:: python
176+
177+
a = ZoneInfo(key)
178+
b = ZoneInfo(key)
179+
assert a is b
180+
181+
``key`` must be in the form of a relative, normalized POSIX path, with no
182+
up-level references. The constructor will raise :exc:`ValueError` if a
183+
non-conforming key is passed.
184+
185+
If no file matching ``key`` is found, the constructor will raise
186+
:exc:`ZoneInfoNotFoundError`.
187+
188+
189+
The ``ZoneInfo`` class has two alternate constructors:
190+
191+
.. classmethod:: ZoneInfo.from_file(fobj, /, key=None)
192+
193+
Constructs a ``ZoneInfo`` object from a file-like object returning bytes
194+
(e.g. a file opened in binary mode or an :class:`io.BytesIO` object).
195+
Unlike the primary constructor, this always constructs a new object.
196+
197+
The ``key`` parameter sets the name of the zone for the purposes of
198+
:py:meth:`~object.__str__` and :py:meth:`~object.__repr__`.
199+
200+
Objects created via this constructor cannot be pickled (see `pickling`_).
201+
202+
.. classmethod:: ZoneInfo.no_cache(key)
203+
204+
An alternate constructor that bypasses the constructor's cache. It is
205+
identical to the primary constructor, but returns a new object on each
206+
call. This is most likely to be useful for testing or demonstration
207+
purposes, but it can also be used to create a system with a different cache
208+
invalidation strategy.
209+
210+
Objects created via this constructor will also bypass the cache of a
211+
deserializing process when unpickled.
212+
213+
.. TODO: Add "See `cache_behavior`_" reference when that section is ready.
214+
215+
.. caution::
216+
217+
Using this constructor may change the semantics of your datetimes in
218+
surprising ways, only use it if you know that you need to.
219+
220+
The following class methods are also available:
221+
222+
.. classmethod:: ZoneInfo.clear_cache(*, only_keys=None)
223+
224+
A method for invalidating the cache on the ``ZoneInfo`` class. If no
225+
arguments are passed, all caches are invalidated and the next call to
226+
the primary constructor for each key will return a new instance.
227+
228+
If an iterable of key names is passed to the ``only_keys`` parameter, only
229+
the specified keys will be removed from the cache. Keys passed to
230+
``only_keys`` but not found in the cache are ignored.
231+
232+
.. TODO: Add "See `cache_behavior`_" reference when that section is ready.
233+
234+
.. warning::
235+
236+
Invoking this function may change the semantics of datetimes using
237+
``ZoneInfo`` in surprising ways; this modifies process-wide global state
238+
and thus may have wide-ranging effects. Only use it if you know that you
239+
need to.
240+
241+
The class has one attribute:
242+
243+
.. attribute:: ZoneInfo.key
244+
245+
This is a read-only :term:`attribute` that returns the value of ``key``
246+
passed to the constructor, which should be a lookup key in the IANA time
247+
zone database (e.g. ``America/New_York``, ``Europe/Paris`` or
248+
``Asia/Tokyo``).
249+
250+
For zones constructed from file without specifying a ``key`` parameter,
251+
this will be set to ``None``.
252+
253+
.. note::
254+
255+
Although it is a somewhat common practice to expose these to end users,
256+
these values are designed to be primary keys for representing the
257+
relevant zones and not necessarily user-facing elements. Projects like
258+
CLDR (the Unicode Common Locale Data Repository) can be used to get
259+
more user-friendly strings from these keys.
260+
261+
String representations
262+
**********************
263+
264+
The string representation returned when calling :py:class:`str` on a
265+
:class:`ZoneInfo` object defaults to using the :attr:`ZoneInfo.key` attribute (see
266+
the note on usage in the attribute documentation)::
267+
268+
>>> zone = ZoneInfo("Pacific/Kwajalein")
269+
>>> str(zone)
270+
'Pacific/Kwajalein'
271+
272+
>>> dt = datetime(2020, 4, 1, 3, 15, tzinfo=zone)
273+
>>> f"{dt.isoformat()} [{dt.tzinfo}]"
274+
'2020-04-01T03:15:00+12:00 [Pacific/Kwajalein]'
275+
276+
For objects constructed from a file without specifying a ``key`` parameter,
277+
``str`` falls back to calling :func:`repr`. ``ZoneInfo``'s ``repr`` is
278+
implementation-defined and not necessarily stable between versions, but it is
279+
guaranteed not to be a valid ``ZoneInfo`` key.
280+
281+
.. _pickling:
282+
283+
Pickle serialization
284+
********************
285+
286+
Rather than serializing all transition data, ``ZoneInfo`` objects are
287+
serialized by key, and ``ZoneInfo`` objects constructed from files (even those
288+
with a value for ``key`` specified) cannot be pickled.
289+
290+
The behavior of a ``ZoneInfo`` file depends on how it was constructed:
291+
292+
1. ``ZoneInfo(key)``: When constructed with the primary constructor, a
293+
``ZoneInfo`` object is serialized by key, and when deserialized, the
294+
deserializing process uses the primary and thus it is expected that these
295+
are expected to be the same object as other references to the same time
296+
zone. For example, if ``europe_berlin_pkl`` is a string containing a pickle
297+
constructed from ``ZoneInfo("Europe/Berlin")``, one would expect the
298+
following behavior:
299+
300+
.. code-block::
301+
302+
>>> a = ZoneInfo("Europe/Berlin")
303+
>>> b = pickle.loads(europe_berlin_pkl)
304+
>>> a is b
305+
True
306+
307+
2. ``ZoneInfo.no_cache(key)``: When constructed from the cache-bypassing
308+
constructor, the ``ZoneInfo`` object is also serialized by key, but when
309+
deserialized, the deserializing process uses the cache bypassing
310+
constructor. If ``europe_berlin_pkl_nc`` is a string containing a pickle
311+
constructed from ``ZoneInfo.no_cache("Europe/Berlin")``, one would expect
312+
the following behavior:
313+
314+
.. code-block::
315+
316+
>>> a = ZoneInfo("Europe/Berlin")
317+
>>> b = pickle.loads(europe_berlin_pkl_nc)
318+
>>> a is b
319+
False
320+
321+
3. ``ZoneInfo.from_file(fobj, /, key=None)``: When constructed from a file, the
322+
``ZoneInfo`` object raises an exception on pickling. If an end user wants to
323+
pickle a ``ZoneInfo`` constructed from a file, it is recommended that they
324+
use a wrapper type or a custom serialization function: either serializing by
325+
key or storing the contents of the file object and serializing that.
326+
327+
This method of serialization requires that the time zone data for the required
328+
key be available on both the serializing and deserializing side, similar to the
329+
way that references to classes and functions are expected to exist in both the
330+
serializing and deserializing environments. It also means that no guarantees
331+
are made about the consistency of results when unpickling a ``ZoneInfo``
332+
pickled in an environment with a different version of the time zone data.
333+
334+
Functions
335+
---------
336+
337+
.. function:: reset_tzpath(to=None)
338+
339+
Sets or resets the time zone search path (:data:`TZPATH`) for the module.
340+
When called with no arguments, :data:`TZPATH` is set to the default value.
341+
342+
Calling ``reset_tzpath`` will not invalidate the :class:`ZoneInfo` cache,
343+
and so calls to the primary ``ZoneInfo`` constructor will only use the new
344+
``TZPATH`` in the case of a cache miss.
345+
346+
The ``to`` parameter must be a :term:`sequence` of strings or
347+
:class:`os.PathLike` and not a string, all of which must be absolute paths.
348+
:exc:`ValueError` will be raised if something other than an absolute path
349+
is passed.
350+
351+
Globals
352+
-------
353+
354+
.. data:: TZPATH
355+
356+
A read-only sequence representing the time zone search path -- when
357+
constructing a ``ZoneInfo`` from a key, the key is joined to each entry in
358+
the ``TZPATH``, and the first file found is used.
359+
360+
``TZPATH`` may contain only absolute paths, never relative paths,
361+
regardless of how it is configured.
362+
363+
The object that ``zoneinfo.TZPATH`` points to may change in response to a
364+
call to :func:`reset_tzpath`, so it is recommended to use
365+
``zoneinfo.TZPATH`` rather than importing ``TZPATH`` from ``zoneinfo`` or
366+
assigning a long-lived variable to ``zoneinfo.TZPATH``.
367+
368+
For more information on configuring the time zone search path, see
369+
:ref:`zoneinfo_data_configuration`.
370+
371+
Exceptions and warnings
372+
-----------------------
373+
374+
.. exception:: ZoneInfoNotFoundError
375+
376+
Raised when construction of a :class:`ZoneInfo` object fails because the
377+
specified key could not be found on the system. This is a subclass of
378+
:exc:`KeyError`.
379+
380+
.. exception:: InvalidTZPathWarning
381+
382+
Raised when :envvar:`PYTHONTZPATH` contains an invalid component that will
383+
be filtered out, such as a relative path.
384+
385+
.. Links and references:
386+
387+
.. _tzdata: https://pypi.org/project/tzdata/

0 commit comments

Comments
 (0)