Updated PEP 495.

This commit is contained in:
Alexander Belopolsky 2015-08-07 22:58:51 -04:00
parent 418063eb44
commit 72adbc95eb
1 changed files with 166 additions and 16 deletions

View File

@ -72,28 +72,170 @@ Methods
The ``replace()`` methods of the ``datetime.time`` and The ``replace()`` methods of the ``datetime.time`` and
``datetime.datetime`` classes will get a new keyword-only argument ``datetime.datetime`` classes will get a new keyword-only argument
called ``first`` with the default value ``True``. The value of the called ``first`` with the default value ``True``. It will
``first`` argument will be used to set the value of the ``first`` becave similarly to the other ``replace()`` arguments: if the ``first``
attribute in the returned instance. argument is specified and given a boolean value, the new instance
returned by ``replace()`` will have its ``first`` attribute set
to that value. In CPython, a non-boolean value of ``first`` will
raise a ``TypeError``, but other implementations may allow the value
``None`` to behave the same as when ``first`` is not given. If the
``first`` argument is not specified, the original value of the ``first``
attribute is copied to the result.
Affected Behaviors Affected Behaviors
------------------ ------------------
The ``timestamp()`` method of ``datetime.datetime`` will return value Conversion from naive to aware
advanced by 3600 if ``self`` represents an ambiguous hour and ..............................
``first`` is False.
The ``astimezone()`` method will now work for naive ``self``. The
system local timezone will be assumed in this case and the ``first``
flag will be used to determine which local timezone is in effect
in the ambiguous case.
For example, on a system set to US/Eastern timezone::
>>> dt = datetime(2014, 11, 2, 1, 30)
>>> dt.astimezone().strftime('%D %T %Z%z')
'11/02/14 01:30:00 EDT-0400'
>>> dt.replace(first=False).astimezone().strftime('%D %T %Z%z')
'11/02/14 01:30:00 EST-0500'
Conversion to POSIX seconds from EPOCH
......................................
The ``timestamp()`` method of ``datetime.datetime`` will return different
values for ``datetime.datetime`` instances that differ only by the value
of their ``first`` attribute if and only if these instances represent an
ambiguous or a non-existent value.
When a ``datetime.datetime`` instance ``dt`` represents an ambiguous
(repeated) time, there are two values ``s0`` and ``s1`` such that::
datetime.fromtimestamp(s0) == datetime.fromtimestamp(s1) == dt
In this case, ``dt.timestamp()`` will return the smaller of ``s0``
and ``s1`` values if ``dt.first == True`` and the larger otherwise.
For example, on a system set to US/Eastern timezone::
>>> datetime(2014, 11, 2, 1, 30, first=True).timestamp()
1414906200.0
>>> datetime(2014, 11, 2, 1, 30, first=False).timestamp()
1414909800.0
When a ``datetime.datetime`` instance ``dt`` represents an invalid
time, there is no value ``s`` for which::
datetime.fromtimestamp(s) == dt
but we can form two "nice to know" values of ``s`` that differ
by the size of the gap in seconds. One is the value of ``s``
that would correspond to ``dt`` in a timezone where the UTC offset
is always the same as the offset right before the gap and the
other is the similar value but in a timezone the UTC offset
is always the same as the offset right after the gap.
The value returned by ``dt.timestamp()`` given the invalid
``dt`` will be the larger of the two "nice to know" values
if ``dt.first == True`` and the larger otherwise.
For example, on a system set to US/Eastern timezone::
>>> datetime(2015, 3, 8, 2, 30, first=True).timestamp()
1425799800.0
>>> datetime(2015, 3, 8, 2, 30, first=False).timestamp()
1425796200.0
Conversion from POSIX seconds from EPOCH
........................................
The ``fromtimestamp()`` static method of ``datetime.datetime`` will The ``fromtimestamp()`` static method of ``datetime.datetime`` will
set the ``first`` attribute appropriately in the returned object. set the ``first`` attribute appropriately in the returned object.
For example, on a system set to US/Eastern timezone::
>>> datetime.fromtimestamp(1414906200)
datetime.datetime(2014, 11, 2, 1, 30)
>>> datetime.fromtimestamp(1414906200 + 3600)
datetime.datetime(2014, 11, 2, 1, 30, first=False)
Implementations of tzinfo in stdlib
...................................
No new implementations of ``datetime.tzinfo`` abstract class are
introduced in this PEP. The existing (fixed offset) timezones do
not introduce ambiguous local times and their ``utcoffset()``
implementation will return the same constant value as they do now
regardless of the value of ``first``.
New guidelines will be published for implementing concrete timezones
with variable UTC offset.
Guidelines for new tzinfo implementations
-----------------------------------------
Implementors of concrete ``datetime.tzinfo`` subclasses who want to
support variable UTC offsets (due to DST and other causes) must follow
these guidelines.
New subclasses should override the baseclass ``fromutc()`` method so
that in all cases where two UTC times ``u1`` and ``u2`` (``u1`` <``u2``)
corespond to the same local time ``fromutc(u1)`` will return an instance
with ``first=True`` and ``fromutc(u1)`` will return an instance
with ``first=False``.
New implementations of ``utcoffset()`` and ``dst()`` methods should
ignore the value of ``first`` unless they are called on the ambiguous
or invalid times.
On an ambiguous time introduced at the end of DST, the values returned
by ``utcoffset()`` and ``dst()`` methods should be as follows
+-----------------+----------------+------------------+
| | first=True | first=False |
+-----------------+----------------+------------------+
| utcoff() | stdoff + hour | stdoff |
+-----------------+----------------+------------------+
| dst() | hour | zero |
+-----------------+----------------+------------------+
where ``stdoff`` is the standard (non-DST) offset,
``hour = timedelta(hours=1)`` and ``zero = timedelta(0)``.
On an invalid time introduced at the start of DST, the values returned
by ``utcoffset()`` and ``dst()`` methods should be as follows
+-----------------+----------------+------------------+
| | first=True | first=False |
+-----------------+----------------+------------------+
| utcoff() | stdoff | stdoff + hour |
+-----------------+----------------+------------------+
| dst() | zero | hour |
+-----------------+----------------+------------------+
On ambiguous/invalid times introduced by the change in the standard time
offset, the ``dst()`` method should return the same value regardless of
the value of ``first`` and the ``utcoff()`` should return values
according to the following table:
+-----------------+----------------+-----------------------------+
| | first=True | first=False |
+-----------------+----------------+-----------------------------+
| ambiguous | oldoff | newoff = oldoff - delta |
+-----------------+----------------+-----------------------------+
| invalid | oldoff | newoff = oldoff + delta |
+-----------------+----------------+-----------------------------+
Implementations of tzinfo
.........................
Subclasses of ``datetime.tzinfo`` will read the values of ``first`` in
``utcoffset()`` and ``dst()`` methods and set it appropriately in the
instances returned by the ``fromutc()`` method. No change to the
signatures of these methods is proposed.
Pickle size Pickle size
----------- -----------
@ -117,7 +259,7 @@ Temporal Arithmetics
-------------------- --------------------
The value of "first" will be ignored in all operations except those The value of "first" will be ignored in all operations except those
that involve conversion between timezones. that involve conversion between timezones. [#]_
The result of addition (subtraction) of a timedelta to (from) a The result of addition (subtraction) of a timedelta to (from) a
datetime will always have ``first`` set to ``True`` even if the datetime will always have ``first`` set to ``True`` even if the
@ -125,9 +267,17 @@ original datetime instance had ``first=False``.
(The only methods that will be able to produce non-default value of (The only methods that will be able to produce non-default value of
"first" are ``__new__``, and ``replace()`` methods of the "first" are ``__new__``, and ``replace()`` methods of the
``datetime.datetime`` and ``datetime.time`` classes ``now()`` and ``datetime.datetime`` and ``datetime.time`` classes ``now()``,
``fromtimestamp()`` methods of the ``datetime.datetime`` class, and ``astimezone()`` and ``fromtimestamp()`` methods of the
``fromutc()`` method of some tzinfo implementations.) ``datetime.datetime`` class, and ``fromutc()`` method of some tzinfo
implementations.)
.. [#] As of Python 3.5, ``tzinfo`` is ignored whenever timedelta is
added or subtracted from a ``datetime.datetime`` instance or when
one ``datetime.datetime`` instance is subtracted from another with
the same (even not-None) ``tzinfo``. This may change in the future,
but such changes are outside of the scope of this PEP.
Comparison Comparison
---------- ----------