PEP 431: Time zone support improvements
(By Lennart Regebro, with very minor formatting by Barry.)
This commit is contained in:
parent
270126b5d1
commit
1a6a86df93
|
@ -0,0 +1,261 @@
|
|||
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
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 11-Dec-2012
|
||||
Post-History: 11-Dec-2012
|
||||
|
||||
|
||||
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
|
||||
standard library, only a tzinfo baseclass, and since Python 3.2, one concrete
|
||||
time zone: UTC. 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.
|
||||
|
||||
Timezone support has therefore only been available through two third-party
|
||||
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
|
||||
most variants of Unix operating systems, including OS X.
|
||||
|
||||
This gives us the opportunity to include only the code that supports the
|
||||
zoneinfo data in the standard library, but by default use the operating
|
||||
systems copy of the data, which typically will be kept updated by the
|
||||
updating mechanism of the operating system or distribution.
|
||||
|
||||
For those who have an operating system that does not include the tz database,
|
||||
for example Windows, a distribution containing the latest tz database should
|
||||
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 recieving updates and
|
||||
therefore has an outdated database.
|
||||
|
||||
With such a mechanism Python would have full time zone support in the
|
||||
standard library on most platforms, and a simple package installation would
|
||||
provide time zone support on those platforms where the tz database isn't
|
||||
included, such as Windows.
|
||||
|
||||
The time zone support will be implemented by a new module called `timezone``,
|
||||
based on Stuart Bishop's ``pytz`` module.
|
||||
|
||||
|
||||
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
|
||||
are ambigious and therefore you can't rely on them to figure out which time
|
||||
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
|
||||
``tzlocal`` module into the new ``timezone`` module.
|
||||
|
||||
|
||||
Ambiguous times
|
||||
---------------
|
||||
|
||||
When changing over from daylight savings time 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. Similarily, when changing to daylight savings
|
||||
time, one hour goes missing.
|
||||
|
||||
The current time zone API can not differentiating between the two ambiguous
|
||||
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:
|
||||
>>> dt = datetime(2012, 11, 28, 2, 0, tzinfo=timezone('Europe/Stockholm'))
|
||||
# But we can not specify which:
|
||||
>>> dt.astimezone(timezone('UTC'))
|
||||
datetime.datetime(2012, 11, 28, 1, 0, tzinfo=<UTC>)
|
||||
|
||||
``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
|
||||
updating the
|
||||
|
||||
|
||||
Implementation API
|
||||
==================
|
||||
|
||||
The new ``timezone``-module
|
||||
---------------------------
|
||||
|
||||
The public API of the new ``timezone``-module contains one new class, one new
|
||||
function and one new exception.
|
||||
|
||||
* New class: ``DstTzInfo``
|
||||
|
||||
This class provides a concrete implementation of the ``zoneinfo`` base
|
||||
class that implements DST support.
|
||||
|
||||
|
||||
* New function :``get_timezone(name=None, db=None)``
|
||||
|
||||
This function takes a name string that must be a string specifying a
|
||||
valid zoneinfo timezone, ie "US/Eastern", "Europe/Warsaw" or "Etc/GMT+11".
|
||||
If not given, the local timezone will be looked up. If an invalid zone name
|
||||
are given, or the local timezone can not be retrieved, the function raises
|
||||
`UnknownTimeZoneError`.
|
||||
|
||||
The function also takes an optional path to the location of the zoneinfo
|
||||
database which should be used. If not specified, the function will check if
|
||||
the `timezonedata` module is installed, and then use that location or
|
||||
otherwise use the database in ``/usr/share/zoneinfo``.
|
||||
|
||||
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 ``timezonedata`` package.
|
||||
|
||||
* New Exception: ``UnknownTimeZoneError``
|
||||
|
||||
This exception is 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'
|
||||
|
||||
|
||||
Changes in the ``datetime``-module
|
||||
--------------------------------------
|
||||
|
||||
A new ``is_dst`` parameter is added to several of the `tzinfo` methods to
|
||||
handle time ambiguity during DST changeovers.
|
||||
|
||||
* ``tzinfo.utcoffset(self, dt, is_dst=True)``
|
||||
|
||||
* ``tzinfo.dst(self, dt, is_dst=True)``
|
||||
|
||||
* ``tzinfo.tzname(self, dt, is_dst=True)``
|
||||
|
||||
The ``is_dst`` parameter can be ``True`` (default), ``False``, or ``None``.
|
||||
|
||||
``True`` will specify that the given datetime should be interpreted as
|
||||
happening during daylight savings time, ie that the time specified is before
|
||||
the change from DST.
|
||||
|
||||
``False`` will specify that the given datetime should be interpreted as not
|
||||
happening during daylight savings time, ie that the time specified is after
|
||||
the change from DST.
|
||||
|
||||
``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.
|
||||
|
||||
There are also two new exceptions:
|
||||
|
||||
* ``AmbiguousTimeError``
|
||||
|
||||
This exception is raised when giving a datetime specification that are
|
||||
ambigious while setting ``is_dst`` to None::
|
||||
|
||||
>>> datetime(2012, 11, 28, 2, 0, tzinfo=timezone('Europe/Stockholm'), is_dst=None)
|
||||
>>>
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AmbiguousTimeError: 2012-10-28 02:00:00 is ambiguous in time zone Europe/Stockholm
|
||||
|
||||
|
||||
* ``NonExistentTimeError``
|
||||
|
||||
This exception is raised when giving a datetime specification that are
|
||||
ambigious while setting ``is_dst`` to None::
|
||||
|
||||
>>> datetime(2012, 3, 25, 2, 0, tzinfo=timezone('Europe/Stockholm'), is_dst=None)
|
||||
>>>
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NonExistentTimeError: 2012-03-25 02:00:00 does not exist in time zone Europe/Stockholm
|
||||
|
||||
|
||||
The ``timezonedata``-package
|
||||
-----------------------------
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Differences from the ``pytz`` API
|
||||
=================================
|
||||
|
||||
* ``pytz`` has the functions ``localize()`` and ``normalize()`` to work
|
||||
around that ``tzinfo`` doesn't have is_dst. When ``is_dst`` is
|
||||
implemented directly in ``datetime.tzinfo`` they are no longer needed.
|
||||
|
||||
* The ``pytz`` method ``timezone()`` is instead called ``get_timezone()`` for
|
||||
clarity.
|
||||
|
||||
* ``get_timezone()`` will return the local time zone if called without
|
||||
parameters.
|
||||
|
||||
* The class ``pytz.StaticTzInfo`` is there to provide the ``is_dst`` support
|
||||
for static timezones. When ``is_dst`` support is included in
|
||||
``datetime.tzinfo`` it is no longer needed.
|
||||
|
||||
|
||||
Discussion
|
||||
==========
|
||||
|
||||
Should the windows installer include the data package?
|
||||
------------------------------------------------------
|
||||
|
||||
It has been suggested that the Windows installer should include the data
|
||||
package. This would mean that an explicit installation no longer would be
|
||||
needed on Windows. On the other hand, that would mean that many using Windows
|
||||
would not be aware that the database quickly becomes outdated and would not
|
||||
keep it updated.
|
||||
|
||||
|
||||
Resources
|
||||
=========
|
||||
|
||||
* http://pytz.sourceforge.net/
|
||||
|
||||
* http://pypi.python.org/pypi/tzlocal
|
||||
|
||||
* http://pypi.python.org/pypi/python-dateutil
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
Loading…
Reference in New Issue