A variety of small edits and clarifications to PEP 495.

This commit is contained in:
Guido van Rossum 2015-09-21 13:21:26 -07:00
parent c5bfd7e3d0
commit 32b6a542bd
1 changed files with 49 additions and 25 deletions

View File

@ -41,7 +41,7 @@ will enumerate the two ambiguous times.
.. [#] People who live in locations observing the Daylight Saving
Time (DST) move their clocks back (usually one hour) every Fall.
It is less common, but occasionally clocks can be moved back for
other reasons. For example, Ukraine skipped the spring-forward
transition in March 1990 and instead, moved their clocks back on
@ -122,7 +122,11 @@ or 1, the new instance returned by ``replace()`` will have its
``fold`` attribute set to that value. In CPython, any non-integer
value of ``fold`` will raise a ``TypeError``, but other
implementations may allow the value ``None`` to behave the same as
when ``fold`` is not given. [#]_ If the ``fold`` argument is not
when ``fold`` is not given. [#]_ (This is
a nod to the existing difference in treatment of ``None`` arguments
in other positions of this method across Python implementations;
it is not intended to leave the door open for future alternative
interpretation of ``fold=None``.) If the ``fold`` argument is not
specified, the original value of the ``fold`` attribute is copied to
the result.
@ -176,18 +180,23 @@ Affected Behaviors
What time is it?
................
The ``datetime.now()`` method called with no arguments, will set
The ``datetime.now()`` method called without arguments will set
``fold=1`` when returning the second of the two ambiguous times in a
system local time fold. When called with a ``tzinfo`` argument, the
value of the ``fold`` will be determined by the ``tzinfo.fromutc()``
implementation. If an instance of the ``datetime.timezone`` class
(*e.g.* ``datetime.timezone.utc``) is passed as ``tzinfo``, the
implementation. When an instance of the ``datetime.timezone`` class
(the stdlib's fixed-offset ``tzinfo`` subclass,
*e.g.* ``datetime.timezone.utc``) is passed as ``tzinfo``, the
returned datetime instance will always have ``fold=0``.
The ``datetime.utcnow()`` method is unaffected.
Conversion from naive to aware
..............................
A new feature is proposed to facilitate conversion from naive datetime
instances to aware.
The ``astimezone()`` method will now work for naive ``self``. The
system local timezone will be assumed in this case and the ``fold``
flag will be used to determine which local timezone is in effect
@ -201,6 +210,11 @@ For example, on a system set to US/Eastern timezone::
>>> dt.replace(fold=1).astimezone().strftime('%D %T %Z%z')
'11/02/14 01:30:00 EST-0500'
An implication is that ``datetime.now(tz)`` is fully equivalent to
``datetime.now().astimezone(tz)`` (assuming ``tz`` is an instance of a
post-PEP ``tzinfo`` implementation, i.e. one that correctly handles
and sets ``fold``).
Conversion from POSIX seconds from EPOCH
........................................
@ -229,6 +243,8 @@ time, there are two values ``s0`` and ``s1`` such that::
datetime.fromtimestamp(s0) == datetime.fromtimestamp(s1) == dt
(This is because ``==`` disregards the value of fold -- see below.)
In this case, ``dt.timestamp()`` will return the smaller of ``s0``
and ``s1`` values if ``dt.fold == 0`` and the larger otherwise.
@ -240,7 +256,6 @@ For example, on a system set to US/Eastern timezone::
>>> datetime(2014, 11, 2, 1, 30, fold=1).timestamp()
1414909800.0
When a ``datetime.datetime`` instance ``dt`` represents a missing
time, there is no value ``s`` for which::
@ -256,6 +271,8 @@ is always the same as the offset right after the gap.
The value returned by ``dt.timestamp()`` given a missing
``dt`` will be the greater of the two "nice to know" values
if ``dt.fold == 0`` and the smaller otherwise.
(This is not a typo -- it's intentionally backwards from the rule for
ambiguous times.)
For example, on a system set to US/Eastern timezone::
@ -272,13 +289,14 @@ Users of pre-PEP implementations of ``tzinfo`` will not see any
changes in the behavior of their aware datetime instances. Two such
instances that differ only by the value of the ``fold`` attribute will
not be distinguishable by any means other than an explicit access to
the ``fold`` value.
the ``fold`` value. (This is because these pre-PEP implementations
are not using the ``fold`` attribute.)
On the other hand, if an object's ``tzinfo`` is set to a fold-aware
implementation, then the value of ``fold`` will affect the result of
several methods, but only if the corresponding time is in a fold or in
a gap: ``utcoffset()``, ``dst()``, ``tzname()``, ``astimezone()``,
``strftime()`` (if "%Z" or "%z" directive is used in the format
implementation, then in a fold or gap the value of ``fold`` will
affect the result of several methods:
``utcoffset()``, ``dst()``, ``tzname()``, ``astimezone()``,
``strftime()`` (if the "%Z" or "%z" directive is used in the format
specification), ``isoformat()``, and ``timetuple()``.
@ -300,8 +318,9 @@ with protocol version 4 (introduced in Python 3.4) or greater.
Pickle sizes for the ``datetime.datetime`` and ``datetime.time``
objects will not change. The ``fold`` value will be encoded in the
first bit of the 3rd (1st) byte of ``datetime.datetime``
(``datetime.time``) pickle payload. In the `current implementation`_
first bit of the 3rd byte of the ``datetime.datetime``
pickle payload; and in the first bit of the 1st byte of the
``datetime.time`` payload. In the `current implementation`_
these bytes are used to store the month (1-12) and hour (0-23) values
and the first bit is always 0. We picked these bytes because they are
the only bytes that are checked by the current unpickle code. Thus
@ -324,8 +343,11 @@ The basic implementation of ``fromutc()`` in the abstract
``datetime.tzinfo`` class will not change. It is currently not used
anywhere in the stdlib because the only included ``tzinfo``
implementation (the ``datetime.timezone`` class implementing fixed
offset timezones) override ``fromutc()``.
offset timezones) override ``fromutc()``. Keeping the default
implementation unchanged has the benefit that pre-PEP 3rd party
implementations that inherit the default ``fromutc()`` are not
accidentally affected.
Guidelines for New tzinfo Implementations
=========================================
@ -381,7 +403,7 @@ Mind the Gap
The ``fromutc()`` method should never produce a time in the gap.
If ``utcoffset()``, ``tzname()`` or ``dst()`` method is called on a
If the ``utcoffset()``, ``tzname()`` or ``dst()`` method is called on a
local time that falls in a gap, the rules in effect before the
transition should be used if ``fold=0``. Otherwise, the rules in
effect after the transition should be used.
@ -477,7 +499,7 @@ with naive datetime instances. As a consequence, naive
by the value of ``fold`` will compare as equal. Applications that
need to differentiate between such instances should check the value of
``fold`` explicitly or convert those instances to a timezone that does
not have ambiguous times.
not have ambiguous times (such as UTC).
The value of ``fold`` will also be ignored whenever a timedelta is
added to or subtracted from a datetime instance which may be either
@ -495,7 +517,9 @@ previous paragraph, timedelta addition ignores both ``fold`` and
subtraction.
Naive and intra-zone comparisons will ignore the value of ``fold`` and
return the same results as they do now.
return the same results as they do now. (This is the only way to
preserve backward compatibility. If you need an aware intra-zone
comparison that uses the fold, convert both sides to UTC first.)
The inter-zone subtraction will be defined as it is now: ``t - s`` is
computed as ``(t - t.utcoffset()) - (s -
@ -506,14 +530,14 @@ depend on the values of ``t.fold`` and ``s.fold`` when either
.. [#] Note that the new rules may result in a paradoxical situation
when ``s == t`` but ``s - u != t - u``. Such paradoxes are
not really new and are inherent in the overloading of the minus
operator as two different intra- and inter-zone operations. For
operator differently for intra- and inter-zone operations. For
example, one can easily construct datetime instances ``t`` and ``s``
with some variable offset ``tzinfo`` and a datetime ``u`` with
``tzinfo=timezone.utc`` such that ``(t - u) - (s - u) != t - s``.
The explanation for this paradox is that the minuses inside the
parentheses and the two other minuses are really three different
operations: inter-zone datetime subtraction, timedelta subtraction
and intra-zone datetime subtraction which have the mathematical
operations: inter-zone datetime subtraction, timedelta subtraction,
and intra-zone datetime subtraction, which each have the mathematical
properties of subtraction separately, but not when combined in a
single expression.
@ -522,9 +546,9 @@ Aware datetime Equality Comparison
----------------------------------
The aware datetime comparison operators will work the same as they do
now with results indirectly affected by the value of ``fold`` whenever
``utcoffset()`` value of one of the operands depends on it, with one
exception. Whenever one of the operands in inter-zone comparison is
now, with results indirectly affected by the value of ``fold`` whenever
the ``utcoffset()`` value of one of the operands depends on it, with one
exception. Whenever one or both of the operands in inter-zone comparison is
such that its ``utcoffset()`` depends on the value of its ``fold``
fold attribute, the result is ``False``. [#]_
@ -541,7 +565,7 @@ value of ``fold``:
def toutc(t, fold):
u = t - t.replace(fold=fold).utcoffset()
return u.replace(tzinfo=None)
return u.replace(tzinfo=None)
Then ``t == s`` is equivalent to