2012-12-11 15:28:45 -05:00
|
|
|
PEP: 431
|
|
|
|
Title: Time zone support improvements
|
|
|
|
Version: $Revision$
|
|
|
|
Last-Modified: $Date$
|
|
|
|
Author: Lennart Regebro <regebro@gmail.com>
|
|
|
|
BDFL-Delegate: Barry Warsaw <barry@python.org>
|
|
|
|
Status: Draft
|
2012-12-12 05:23:58 -05:00
|
|
|
Type: Standards Track
|
2012-12-11 15:28:45 -05:00
|
|
|
Content-Type: text/x-rst
|
2013-01-01 20:30:04 -05:00
|
|
|
Created: 11-Dec-2012
|
2013-01-25 12:32:59 -05:00
|
|
|
Post-History: 11-Dec-2012, 28-Dec-2012
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
========
|
|
|
|
|
|
|
|
This PEP proposes the implementation of concrete time zone support in the
|
|
|
|
Python standard library, and also improvements to the time zone API to deal
|
|
|
|
with ambiguous time specifications during DST changes.
|
|
|
|
|
|
|
|
|
|
|
|
Proposal
|
|
|
|
========
|
|
|
|
|
|
|
|
Concrete time zone support
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
The time zone support in Python has no concrete implementation in the
|
2013-01-25 12:32:59 -05:00
|
|
|
standard library outside of a tzinfo baseclass that supports fixed offsets.
|
|
|
|
To properly support time zones you need to include a database over all time
|
|
|
|
zones, both current and historical, including daylight saving changes.
|
|
|
|
But such information changes frequently, so even if we include the last
|
|
|
|
information in a Python release, that information would be outdated just a
|
|
|
|
few months later.
|
|
|
|
|
|
|
|
Time zone support has therefore only been available through two third-party
|
2012-12-11 15:28:45 -05:00
|
|
|
modules, ``pytz`` and ``dateutil``, both who include and wrap the "zoneinfo"
|
|
|
|
database. This database, also called "tz" or "The Olsen database", is the
|
|
|
|
de-facto standard time zone database over time zones, and it is included in
|
2013-01-25 12:32:59 -05:00
|
|
|
most Unix and Unix-like operating systems, including OS X.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
This gives us the opportunity to include the code that supports the zoneinfo
|
|
|
|
data in the standard library, but by default use the operating system's copy
|
|
|
|
of the data, which typically will be kept updated by the updating mechanism
|
|
|
|
of the operating system or distribution.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
For those who have an operating system that does not include the zoneinfo
|
|
|
|
database, for example Windows, the Python source distribution will include a
|
|
|
|
copy of the zoneinfo database, and a distribution containing the latest
|
|
|
|
zoneinfo database will also be available at the Python Package Index, so it
|
|
|
|
can be easily installed with the Python packaging tools such as
|
|
|
|
``easy_install`` or ``pip``. This could also be done on Unices that are no
|
|
|
|
longer receiving updates and therefore have an outdated database.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
With such a mechanism Python would have full time zone support in the
|
2013-01-25 12:32:59 -05:00
|
|
|
standard library on any platform, and a simple package installation would
|
|
|
|
provide an updated time zone database on those platforms where the zoneinfo
|
|
|
|
database isn't included, such as Windows, or on platforms where OS updates
|
|
|
|
are no longer provided.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
The time zone support will be implemented by making the ``datetime`` module
|
|
|
|
into a package, and adding time zone support to ``datetime`` based on Stuart
|
|
|
|
Bishop's ``pytz`` module.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
|
|
|
|
Getting the local time zone
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
On Unix there is no standard way of finding the name of the time zone that is
|
|
|
|
being used. All the information that is available is the time zone
|
|
|
|
abbreviations, such as ``EST`` and ``PDT``, but many of those abbreviations
|
2013-01-01 20:10:54 -05:00
|
|
|
are ambiguous and therefore you can't rely on them to figure out which time
|
2012-12-11 15:28:45 -05:00
|
|
|
zone you are located in.
|
|
|
|
|
|
|
|
There is however a standard for finding the compiled time zone information
|
|
|
|
since it's located in ``/etc/localtime``. Therefore it is possible to create
|
|
|
|
a local time zone object with the correct time zone information even though
|
|
|
|
you don't know the name of the time zone. A function in ``datetime`` should
|
|
|
|
be provided to return the local time zone.
|
|
|
|
|
|
|
|
The support for this will be made by integrating Lennart Regebro's
|
2013-01-25 12:32:59 -05:00
|
|
|
``tzlocal`` module into the new ``datetime`` module.
|
|
|
|
|
|
|
|
For Windows it will look up the local Windows time zone name, and use a
|
|
|
|
mapping between Windows time zone names and zoneinfo time zone names provided
|
|
|
|
by the Unicode consortium to convert that to a zoneinfo time zone.
|
|
|
|
|
|
|
|
The mapping should be updated before each major or bugfix release, scripts
|
|
|
|
for doing so will be provided in the ``Tools/`` directory.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
|
|
|
|
Ambiguous times
|
|
|
|
---------------
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
When changing over from daylight savings time (DST) the clock is turned back
|
|
|
|
one hour. This means that the times during that hour happens twice, once
|
|
|
|
without DST and then once with DST. Similarly, when changing to daylight
|
|
|
|
savings time, one hour goes missing.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-01 20:30:04 -05:00
|
|
|
The current time zone API can not differentiate between the two ambiguous
|
2012-12-11 15:28:45 -05:00
|
|
|
times during a change from DST. For example, in Stockholm the time of
|
|
|
|
2012-11-28 02:00:00 happens twice, both at UTC 2012-11-28 00:00:00 and also
|
|
|
|
at 2012-11-28 01:00:00.
|
|
|
|
|
|
|
|
The current time zone API can not disambiguate this and therefore it's
|
|
|
|
unclear which time should be returned::
|
|
|
|
|
|
|
|
# This could be either 00:00 or 01:00 UTC:
|
2013-01-25 12:32:59 -05:00
|
|
|
>>> dt = datetime(2012, 10, 28, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'))
|
2012-12-11 15:28:45 -05:00
|
|
|
# But we can not specify which:
|
2013-01-25 12:32:59 -05:00
|
|
|
>>> dt.astimezone(zoneinfo('UTC'))
|
|
|
|
datetime.datetime(2012, 10, 28, 1, 0, tzinfo=<UTC>)
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
``pytz`` solved this problem by adding ``is_dst`` parameters to several
|
|
|
|
methods of the tzinfo objects to make it possible to disambiguate times when
|
|
|
|
this is desired.
|
|
|
|
|
|
|
|
This PEP proposes to add these ``is_dst`` parameters to the relevant methods
|
|
|
|
of the ``datetime`` API, and therefore add this functionality directly to
|
|
|
|
``datetime``. This is likely the hardest part of this PEP as this involves
|
2013-01-25 12:32:59 -05:00
|
|
|
updating the C version of the ``datetime`` library with this functionality,
|
|
|
|
as this involved writing new code, and not just reorganizing existing
|
|
|
|
external libraries.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
|
|
|
|
Implementation API
|
|
|
|
==================
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
The zoneinfo database
|
|
|
|
---------------------
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
The latest version of the zoneinfo database should exist in the
|
|
|
|
``Lib/tzdata`` directory of the Python source control system. This copy of
|
|
|
|
the database should be updated before every Python feature and bug-fix
|
|
|
|
release, but not for releases of Python versions that are in
|
|
|
|
security-fix-only-mode.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
Scripts to update the database will be provided in ``Tools/``, and the
|
|
|
|
release instructions will be updated to include this update.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
New configure options ``--enable-internal-timezone-database`` and
|
|
|
|
``--disable-internal-timezone-database`` will be implemented to enable and
|
|
|
|
disable the installation of this database when installing from source. A
|
|
|
|
source install will default to installing them.
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
Binary installers for systems that have a system-provided zoneinfo database
|
|
|
|
may skip installing the included database since it would never be used for
|
|
|
|
these platforms. For other platforms, for example Windows, binary installers
|
|
|
|
must install the included database.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
Changes in the ``datetime``-module
|
|
|
|
----------------------------------
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
The public API of the new time zone support contains one new class, one new
|
|
|
|
function, one new exception and four new collections. In addition to this, several
|
|
|
|
methods on the datetime object gets a new ``is_dst`` parameter.
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
New class ``DstTzInfo``
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
This class provides a concrete implementation of the ``zoneinfo`` base
|
|
|
|
class that implements DST support.
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
New function ``zoneinfo(name=None, db_path=None)``
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
This function takes a name string that must be a string specifying a
|
|
|
|
valid zoneinfo time zone, i.e. "US/Eastern", "Europe/Warsaw" or "Etc/GMT".
|
|
|
|
If not given, the local time zone will be looked up. If an invalid zone name
|
|
|
|
is given, or the local time zone can not be retrieved, the function raises
|
|
|
|
`UnknownTimeZoneError`.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
The function also takes an optional path to the location of the zoneinfo
|
|
|
|
database which should be used. If not specified, the function will look for
|
|
|
|
databases in the following order:
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
1. Use the database in ``/usr/share/zoneinfo``, if it exists.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
2. Check if the `tzdata-update` module is installed, and then use that
|
|
|
|
database.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
3. Use the Python-provided database in ``Lib/tzdata``.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
If no database is found an ``UnknownTimeZoneError`` or subclass thereof will
|
|
|
|
be raised with a message explaining that no zoneinfo database can be found,
|
|
|
|
but that you can install one with the ``tzdata-update`` package.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
New parameter ``is_dst``
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
A new ``is_dst`` parameter is added to several methods to handle time
|
|
|
|
ambiguity during DST changeovers.
|
|
|
|
|
|
|
|
* ``tzinfo.utcoffset(dt, is_dst=False)``
|
|
|
|
|
|
|
|
* ``tzinfo.dst(dt, is_dst=False)``
|
|
|
|
|
|
|
|
* ``tzinfo.tzname(dt, is_dst=False)``
|
|
|
|
|
|
|
|
* ``datetime.astimezone(tz, is_dst=False)``
|
|
|
|
|
|
|
|
The ``is_dst`` parameter can be ``False`` (default), ``True``, or ``None``.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
``False`` will specify that the given datetime should be interpreted as not
|
2013-01-01 20:10:54 -05:00
|
|
|
happening during daylight savings time, i.e. that the time specified is after
|
2012-12-11 15:28:45 -05:00
|
|
|
the change from DST.
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
``True`` will specify that the given datetime should be interpreted as happening
|
|
|
|
during daylight savings time, i.e. that the time specified is before the change
|
|
|
|
from DST.
|
|
|
|
|
2012-12-11 15:28:45 -05:00
|
|
|
``None`` will raise an ``AmbiguousTimeError`` exception if the time specified
|
|
|
|
was during a DST change over. It will also raise a ``NonExistentTimeError``
|
|
|
|
if a time is specified during the "missing time" in a change to DST.
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
New exceptions
|
|
|
|
^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
* ``UnknownTimeZoneError``
|
|
|
|
|
|
|
|
This exception is a subclass of KeyError and raised when giving a time
|
|
|
|
zone specification that can't be found::
|
|
|
|
|
|
|
|
>>> datetime.Timezone('Europe/New_York')
|
|
|
|
Traceback (most recent call last):
|
|
|
|
...
|
|
|
|
UnknownTimeZoneError: There is no time zone called 'Europe/New_York'
|
|
|
|
|
|
|
|
* ``InvalidTimeError``
|
|
|
|
|
|
|
|
This exception serves as a base for ``AmbiguousTimeError`` and
|
|
|
|
``NonExistentTimeError``, to enable you to trap these two separately. It
|
|
|
|
will subclass from ValueError, so that you can catch these errors together
|
|
|
|
with inputs like the 29th of February 2011.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
* ``AmbiguousTimeError``
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
This exception is raised when giving a datetime specification that is ambiguous
|
|
|
|
while setting ``is_dst`` to None::
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
>>> datetime(2012, 11, 28, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'), is_dst=None)
|
|
|
|
>>>
|
2012-12-11 15:28:45 -05:00
|
|
|
Traceback (most recent call last):
|
|
|
|
...
|
|
|
|
AmbiguousTimeError: 2012-10-28 02:00:00 is ambiguous in time zone Europe/Stockholm
|
|
|
|
|
|
|
|
|
|
|
|
* ``NonExistentTimeError``
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
This exception is raised when giving a datetime specification that is ambiguous
|
|
|
|
while setting ``is_dst`` to None::
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
>>> datetime(2012, 3, 25, 2, 0, tzinfo=zoneinfo('Europe/Stockholm'), is_dst=None)
|
|
|
|
>>>
|
2012-12-11 15:28:45 -05:00
|
|
|
Traceback (most recent call last):
|
|
|
|
...
|
|
|
|
NonExistentTimeError: 2012-03-25 02:00:00 does not exist in time zone Europe/Stockholm
|
|
|
|
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
New collections
|
|
|
|
^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
* ``all_timezones`` is the exhaustive list of the time zone names that can
|
|
|
|
be used, listed alphabethically.
|
|
|
|
|
|
|
|
* ``all_timezones_set`` is a set of the time zones in ``all_timezones``.
|
|
|
|
|
|
|
|
* ``common_timezones`` is a list of useful, current time zones, listed
|
|
|
|
alphabethically.
|
|
|
|
|
|
|
|
* ``common_timezones_set`` is a set of the time zones in ``common_timezones``.
|
|
|
|
|
|
|
|
|
|
|
|
The ``tzdata-update``-package
|
2012-12-11 15:28:45 -05:00
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
The zoneinfo database will be packaged for easy installation with
|
|
|
|
``easy_install``/``pip``/``buildout``. This package will not install any
|
|
|
|
Python code, and will not contain any Python code except that which is needed
|
|
|
|
for installation.
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
It will be kept updated with the same tools as the internal database, but
|
|
|
|
released whenever the ``zoneinfo``-database is updated, and use the same
|
|
|
|
version schema.
|
|
|
|
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
Differences from the ``pytz`` API
|
|
|
|
=================================
|
|
|
|
|
|
|
|
* ``pytz`` has the functions ``localize()`` and ``normalize()`` to work
|
2013-01-01 20:30:04 -05:00
|
|
|
around that ``tzinfo`` doesn't have is_dst. When ``is_dst`` is
|
2012-12-11 15:28:45 -05:00
|
|
|
implemented directly in ``datetime.tzinfo`` they are no longer needed.
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
* The ``timezone()`` function is called ``zoneinfo()`` to avoid clashing with
|
|
|
|
the ``timezone`` class introduced in Python 3.2.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
* ``zoneinfo()`` will return the local time zone if called without arguments.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
* The class ``pytz.StaticTzInfo`` is there to provide the ``is_dst`` support for static
|
|
|
|
time zones. When ``is_dst`` support is included in ``datetime.tzinfo`` it is no longer needed.
|
2013-01-01 20:30:04 -05:00
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
* ``InvalidTimeError`` subclasses from ``ValueError``.
|
2012-12-11 15:28:45 -05:00
|
|
|
|
|
|
|
|
|
|
|
Resources
|
|
|
|
=========
|
|
|
|
|
|
|
|
* http://pytz.sourceforge.net/
|
|
|
|
|
|
|
|
* http://pypi.python.org/pypi/tzlocal
|
|
|
|
|
|
|
|
* http://pypi.python.org/pypi/python-dateutil
|
|
|
|
|
2013-01-25 12:32:59 -05:00
|
|
|
* http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
|
|
|
|
|
2012-12-11 15:28:45 -05:00
|
|
|
Copyright
|
|
|
|
=========
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|