From 983039fed21328d653570752715054a8a87b2679 Mon Sep 17 00:00:00 2001 From: Alexander Belopolsky Date: Sat, 8 Aug 2015 18:07:27 -0400 Subject: [PATCH] PEP-0500: A protocol for delegating datetime methods --- pep-0500.txt | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 pep-0500.txt diff --git a/pep-0500.txt b/pep-0500.txt new file mode 100644 index 000000000..122f68e81 --- /dev/null +++ b/pep-0500.txt @@ -0,0 +1,204 @@ +PEP: 500 +Title: A protocol for delegating datetime methods to their + tzinfo implementations +Version: $Revision$ +Last-Modified: $Date$ +Author: Alexander Belopolsky +Discussions-To: Datetime-SIG +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Requires: 495 +Created: 08-Aug-2015 + + +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 requre 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 arithmentics +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 elapced 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.