Permalink
Cannot retrieve contributors at this time
203 lines (154 sloc)
6.88 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
peps/pep-0500.txt
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| PEP: 500 | |
| Title: A protocol for delegating datetime methods to their tzinfo implementations | |
| Version: $Revision$ | |
| Last-Modified: $Date$ | |
| Author: Alexander Belopolsky <alexander.belopolsky@gmail.com>, Tim Peters <tim.peters@gmail.com> | |
| Discussions-To: datetime-sig@python.org | |
| Status: Rejected | |
| Type: Standards Track | |
| Content-Type: text/x-rst | |
| Requires: 495 | |
| Created: 08-Aug-2015 | |
| Resolution: https://mail.python.org/pipermail/datetime-sig/2015-August/000354.html | |
| Abstract | |
| ======== | |
| This PEP specifies a new protocol (PDDM - "A Protocol for Delegating | |
| Datetime Methods") that can be used by concrete implementations of the | |
| ``datetime.tzinfo`` interface to override aware datetime arithmetics, | |
| formatting and parsing. We describe changes to the | |
| ``datetime.datetime`` class to support the new protocol and propose a | |
| new abstract class ``datetime.tzstrict`` that implements parts of this | |
| protocol necessary to make aware datetime instances to follow "strict" | |
| arithmetic rules. | |
| Rationale | |
| ========= | |
| As of Python 3.5, aware datetime instances that share a ``tzinfo`` | |
| object follow the rules of arithmetics that are induced by a simple | |
| bijection between (year, month, day, hour, minute, second, | |
| microsecond) 7-tuples and large integers. In this arithmetics, the | |
| difference between YEAR-11-02T12:00 and YEAR-11-01T12:00 is always 24 | |
| hours, even though in the US/Eastern timezone, for example, there are | |
| 25 hours between 2014-11-01T12:00 and 2014-11-02T12:00 because the | |
| local clocks were rolled back one hour at 2014-11-02T02:00, | |
| introducing an extra hour in the night between 2014-11-01 and | |
| 2014-11-02. | |
| Many business applications require the use of Python's simplified view | |
| of local dates. No self-respecting car rental company will charge its | |
| customers more for a week that straddles the end of DST than for any | |
| other week or require that they return the car an hour early. | |
| Therefore, changing the current rules for aware datetime arithmetics | |
| will not only create a backward compatibility nightmare, it will | |
| eliminate support for legitimate and common use cases. | |
| Since it is impossible to choose universal rules for local time | |
| arithmetics, we propose to delegate implementation of those rules to | |
| the classes that implement ``datetime.tzinfo`` interface. With such | |
| delegation in place, users will be able to choose between different | |
| arithmetics by simply picking instances of different classes for the | |
| value of ``tzinfo``. | |
| Protocol | |
| ======== | |
| Subtraction of datetime | |
| ----------------------- | |
| A ``tzinfo`` subclass supporting the PDDM, may define a method called | |
| ``__datetime_diff__`` that should take two ``datetime.datetime`` | |
| instances and return a ``datetime.timedelta`` instance representing | |
| the time elapsed from the time represented by the first datetime | |
| instance to another. | |
| Addition | |
| -------- | |
| A ``tzinfo`` subclass supporting the PDDM, may define a method called | |
| ``__datetime_add__`` that should take two arguments--a datetime and a | |
| timedelta instances--and return a datetime instance. | |
| Subtraction of timedelta | |
| ------------------------ | |
| A ``tzinfo`` subclass supporting the PDDM, may define a method called | |
| ``__datetime_sub__`` that should take two arguments--a datetime and a | |
| timedelta instances--and return a datetime instance. | |
| Formatting | |
| ---------- | |
| A ``tzinfo`` subclass supporting the PDDM, may define methods called | |
| ``__datetime_isoformat__`` and ``__datetime_strftime__``. | |
| The ``__datetime_isoformat__`` method should take a datetime instance | |
| and an optional separator and produce a string representation of the | |
| given datetime instance. | |
| The ``__datetime_strftime__`` method should take a datetime instance | |
| and a format string and produce a string representation of the given | |
| datetime instance formatted according to the given format. | |
| Parsing | |
| ------- | |
| A ``tzinfo`` subclass supporting the PDDM, may define a class method | |
| called ``__datetime_strptime__`` and register the "canonical" names of | |
| the timezones that it implements with a registry. **TODO** Describe a | |
| registry. | |
| Changes to datetime methods | |
| =========================== | |
| Subtraction | |
| ----------- | |
| :: | |
| class datetime: | |
| def __sub__(self, other): | |
| if isinstance(other, datetime): | |
| try: | |
| self_diff = self.tzinfo.__datetime_diff__ | |
| except AttributeError: | |
| self_diff = None | |
| try: | |
| other_diff = self.tzinfo.__datetime_diff__ | |
| except AttributeError: | |
| other_diff = None | |
| if self_diff is not None: | |
| if self_diff is not other_diff and self_diff.__func__ is not other_diff.__func__: | |
| raise ValueError("Cannot find difference of two datetimes with " | |
| "different tzinfo.__datetime_diff__ implementations.") | |
| return self_diff(self, other) | |
| elif isinstance(other, timedelta): | |
| try: | |
| sub = self.tzinfo.__datetime_sub__ | |
| except AttributeError: | |
| pass | |
| else: | |
| return sub(self, other) | |
| return self + -other | |
| else: | |
| return NotImplemented | |
| # current implementation | |
| Addition | |
| -------- | |
| Addition of a timedelta to a datetime instance will be delegated to the | |
| ``self.tzinfo.__datetime_add__`` method whenever it is defined. | |
| Strict arithmetics | |
| ================== | |
| A new abstract subclass of ``datetime.tzinfo`` class called ``datetime.tzstrict`` | |
| will be added to the ``datetime`` module. This subclass will not implement the | |
| ``utcoffset()``, ``tzname()`` or ``dst()`` methods, but will implement some of the | |
| methods of the PDDM. | |
| The PDDM methods implemented by ``tzstrict`` will be equivalent to the following:: | |
| class tzstrict(tzinfo): | |
| def __datetime_diff__(self, dt1, dt2): | |
| utc_dt1 = dt1.astimezone(timezone.utc) | |
| utc_dt2 = dt2.astimezone(timezone.utc) | |
| return utc_dt2 - utc_dt1 | |
| def __datetime_add__(self, dt, delta): | |
| utc_dt = dt.astimezone(timezone.utc) | |
| return (utc_dt + delta).astimezone(self) | |
| def __datetime_sub__(self, dt, delta): | |
| utc_dt = dt.astimezone(timezone.utc) | |
| return (utc_dt - delta).astimezone(self) | |
| Parsing and formatting | |
| ---------------------- | |
| Datetime methods ``strftime`` and ``isoformat`` will delegate to the namesake | |
| methods of their ``tzinfo`` members whenever those methods are defined. | |
| When the ``datetime.strptime`` method is given a format string that | |
| contains a ``%Z`` instruction, it will lookup the ``tzinfo`` | |
| implementation in the registry by the given timezone name and call its | |
| ``__datetime_strptime__`` method. | |
| Applications | |
| ============ | |
| This PEP will enable third party implementation of many different | |
| timekeeping schemes including: | |
| * Julian / Microsoft Excel calendar. | |
| * "Right" timezones with the leap second support. | |
| * French revolutionary calendar (with a lot of work). | |
| Copyright | |
| ========= | |
| This document has been placed in the public domain. |