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