mirror of https://github.com/python/cpython
"Premature" doc changes, for new astimezone() rules, and the new
tzinfo.fromutc() method. The C code doesn't implement any of this yet (well, not the C code on the machine I'm using now), nor does the test suite reflect it. The Python datetime.py implementation and test suite in the sandbox do match these doc changes. The C implementation probably won't catch up before Thursday (Wednesday is a scheduled "black hole" day this week <0.4 wink>).
This commit is contained in:
parent
51f3f1b7dc
commit
f196a0a4dd
|
@ -734,32 +734,71 @@ Instance methods:
|
|||
|
||||
\begin{methoddesc}{astimezone}{tz}
|
||||
Return a \class{datetime} object with new \member{tzinfo} member
|
||||
\var{tz}.
|
||||
\var{tz} must be \code{None}, or an instance of a \class{tzinfo} subclass.
|
||||
If \var{tz} is \code{None}, \var{self} is naive,
|
||||
or \code{self.tzinfo}\ is \var{tz},
|
||||
\code{self.astimezone(tz)} is equivalent to
|
||||
\code{self.replace(tzinfo=tz)}: a new time zone object is attached
|
||||
without any conversion of date or time members. Else \code{self.tzinfo}
|
||||
and \var{tz} must implement the \method{utcoffset()} and \method{dst()}
|
||||
\class{tzinfo} methods, and the date and time members are adjusted so
|
||||
that the result is local time in time zone \var{tz}, representing the
|
||||
same UTC time as \var{self}: after \code{astz = dt.astimezone(tz)},
|
||||
\code{astz - astz.utcoffset()} will usually have the same date and time
|
||||
members as \code{dt - dt.utcoffset()}. The discussion of class
|
||||
\class{tzinfo} explains the cases at Daylight Saving Time
|
||||
transition boundaries where this cannot be achieved (an issue only if
|
||||
\var{tz} models both standard and daylight time).
|
||||
\var{tz}, adjusting the date and time members so the result is the
|
||||
same UTC time as \var{self}, but in \var{tz}'s local time.
|
||||
|
||||
\var{tz} must be an instance of a \class{tzinfo} subclass, and its
|
||||
\method{utcoffset()} and \method{dst()} methods must not return
|
||||
\code{None}. \var{self} must be aware (\code{\var{self}.tzinfo} must
|
||||
not be \code{None}, and \code{\var{self}.utcoffset()} must not return
|
||||
\code{None}).
|
||||
|
||||
If code{\var{self}.tzinfo} is \var{tz},
|
||||
\code{\var{self}.astimezone(\var{tz})} is equal to \var{self}: no
|
||||
adjustment of date or time members is performed.
|
||||
Else the result is local time in time zone \var{tz}, representing the
|
||||
same UTC time as \var{self}: after \code{\var{astz} =
|
||||
\var{dt}.astimezone(\var{tz})},
|
||||
\code{\var{astz} - \var{astz}.utcoffset()} will usually have the same
|
||||
date and time members as \code{\var{dt} - \var{dt}.utcoffset()}.
|
||||
The discussion of class \class{tzinfo} explains the cases at Daylight
|
||||
Saving Time transition boundaries where this cannot be achieved (an issue
|
||||
only if \var{tz} models both standard and daylight time).
|
||||
|
||||
If you merely want to attach a time zone object \var{tz} to a
|
||||
datetime \var{dt} without adjustment of date and time members,
|
||||
use \code{\var{dt}.replace(tzinfo=\var{tz})}. If
|
||||
you merely want to remove the time zone object from an aware datetime
|
||||
\var{dt} without conversion of date and time members, use
|
||||
\code{\var{dt}.replace(tzinfo=None)}.
|
||||
|
||||
Note that the default \method{tzinfo.fromutc()} method can be overridden
|
||||
in a \class{tzinfo} subclass to effect the result returned by
|
||||
\method{astimezone()}. Ignoring error cases, \method{astimezone()}
|
||||
acts like:
|
||||
|
||||
\begin{verbatim}
|
||||
def astimezone(self, tz):
|
||||
if self.tzinfo is tz:
|
||||
return self
|
||||
# Convert self to UTC, and attach the new time zone object.
|
||||
utc = (self - self.utcoffset()).replace(tzinfo=tz)
|
||||
# Convert from UTC to tz's local time.
|
||||
return tz.fromutc(utc)
|
||||
\end{verbatim}
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{utcoffset}{}
|
||||
If \member{tzinfo} is \code{None}, returns \code{None}, else
|
||||
returns \code{tzinfo.utcoffset(self)}.
|
||||
returns \code{\var{self}.tzinfo.utcoffset(\var{self})}, and
|
||||
raises an exception if the latter doesn't return \code{None}, or
|
||||
a \class{timedelta} object representing a whole number of minutes
|
||||
with magnitude less than one day.
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{dst}{}
|
||||
If \member{tzinfo} is \code{None}, returns \code{None}, else
|
||||
returns \code{\var{self}.tzinfo.dst(\var{self})}, and
|
||||
raises an exception if the latter doesn't return \code{None}, or
|
||||
a \class{timedelta} object representing a whole number of minutes
|
||||
with magnitude less than one day.
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{tzname}{}
|
||||
If \member{tzinfo} is \code{None}, returns \code{None}, else
|
||||
returns \code{tzinfo.tzname(self)}.
|
||||
returns \code{\var{self}.tzinfo.tzname(\var{self})},
|
||||
raises an exception if the latter doesn't return \code{None} or
|
||||
a string object,
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{timetuple}{}
|
||||
|
@ -989,17 +1028,25 @@ Instance methods:
|
|||
|
||||
\begin{methoddesc}{utcoffset}{}
|
||||
If \member{tzinfo} is \code{None}, returns \code{None}, else
|
||||
returns \code{tzinfo.utcoffset(self)}.
|
||||
returns \code{\var{self}.tzinfo.utcoffset(None)}, and
|
||||
raises an exception if the latter doesn't return \code{None} or
|
||||
a \class{timedelta} object representing a whole number of minutes
|
||||
with magnitude less than one day.
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{dst}{}
|
||||
If \member{tzinfo} is \code{None}, returns \code{None}, else
|
||||
returns \code{tzinfo.dst(self)}.
|
||||
returns \code{\var{self}.tzinfo.dst(None)}, and
|
||||
raises an exception if the latter doesn't return \code{None}, or
|
||||
a \class{timedelta} object representing a whole number of minutes
|
||||
with magnitude less than one day.
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{tzname}{}
|
||||
If \member{tzinfo} is \code{None}, returns \code{None}, else
|
||||
returns \code{tzinfo.tzname(self)}.
|
||||
returns \code{\var{self}.tzinfo.tzname(None)}, or
|
||||
raises an exception if the latter doesn't return \code{None} or
|
||||
a string object.
|
||||
\end{methoddesc}
|
||||
|
||||
|
||||
|
@ -1066,37 +1113,58 @@ implement all of them.
|
|||
example, \method{datetime.timetuple()} calls its \member{tzinfo}
|
||||
member's \method{dst()} method to determine how the
|
||||
\member{tm_isdst} flag should be set, and
|
||||
\method{datetime.astimezone()} calls \method{dst()} to account for
|
||||
\method{tzinfo.fromutc()} calls \method{dst()} to account for
|
||||
DST changes when crossing time zones.
|
||||
|
||||
An instance \var{tz} of a \class{tzinfo} subclass that models both
|
||||
standard and daylight times must be consistent in this sense:
|
||||
|
||||
\code{tz.utcoffset(dt) - tz.dst(dt)}
|
||||
\code{\var{tz}.utcoffset(\var{dt}) - \var{tz}.dst(\var{dt})}
|
||||
|
||||
must return the same result for every \class{datetime} \var{dt}
|
||||
with \code{dt.tzinfo==tz} For sane \class{tzinfo} subclasses, this
|
||||
expression yields the time zone's "standard offset", which should not
|
||||
depend on the date or the time, but only on geographic location. The
|
||||
implementation of \method{datetime.astimezone()} relies on this, but
|
||||
cannot detect violations; it's the programmer's responsibility to
|
||||
ensure it.
|
||||
with \code{\var{dt}.tzinfo==\var{tz}} For sane \class{tzinfo}
|
||||
subclasses, this expression yields the time zone's "standard offset",
|
||||
which should not depend on the date or the time, but only on geographic
|
||||
location. The implementation of \method{datetime.astimezone()} relies
|
||||
on this, but cannot detect violations; it's the programmer's
|
||||
responsibility to ensure it. If a \class{tzinfo} subclass cannot
|
||||
guarantee this, it may be able to override the default implementation
|
||||
of \method{tzinfo.fromutc()} to work correctly with \method{astimezone()}
|
||||
regardless.
|
||||
|
||||
Most implementations of \method{dst()} will probably look like one
|
||||
of these two:
|
||||
|
||||
\begin{verbatim}
|
||||
return timedelta(0) # a fixed-offset class: doesn't account for DST
|
||||
|
||||
or
|
||||
|
||||
# Code to set dston and dstoff to the time zone's DST transition
|
||||
# times based on the input dt.year, and expressed in standard local
|
||||
# time. Then
|
||||
|
||||
if dston <= dt.replace(tzinfo=None) < dstoff:
|
||||
return timedelta(hours=1)
|
||||
else:
|
||||
return timedelta(0)
|
||||
\end{verbatim}
|
||||
|
||||
The default implementation of \method{dst()} raises
|
||||
\exception{NotImplementedError}.
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{tzname}{self, dt}
|
||||
Return the timezone name corresponding to the \class{datetime}
|
||||
object represented
|
||||
by \var{dt}, as a string. Nothing about string names is defined by the
|
||||
\module{datetime} module, and there's no requirement that it mean anything
|
||||
in particular. For example, "GMT", "UTC", "-500", "-5:00", "EDT",
|
||||
"US/Eastern", "America/New York" are all valid replies. Return
|
||||
Return the time zone name corresponding to the \class{datetime}
|
||||
object \var{dt}, as a string.
|
||||
Nothing about string names is defined by the
|
||||
\module{datetime} module, and there's no requirement that it mean
|
||||
anything in particular. For example, "GMT", "UTC", "-500", "-5:00",
|
||||
"EDT", "US/Eastern", "America/New York" are all valid replies. Return
|
||||
\code{None} if a string name isn't known. Note that this is a method
|
||||
rather than a fixed string primarily because some \class{tzinfo} objects
|
||||
will wish to return different names depending on the specific value
|
||||
of \var{dt} passed, especially if the \class{tzinfo} class is
|
||||
rather than a fixed string primarily because some \class{tzinfo}
|
||||
subclasses will wish to return different names depending on the specific
|
||||
value of \var{dt} passed, especially if the \class{tzinfo} class is
|
||||
accounting for daylight time.
|
||||
|
||||
The default implementation of \method{tzname()} raises
|
||||
|
@ -1113,7 +1181,7 @@ class \class{datetime}.
|
|||
When \code{None} is passed, it's up to the class designer to decide the
|
||||
best response. For example, returning \code{None} is appropriate if the
|
||||
class wishes to say that time objects don't participate in the
|
||||
\class{tzinfo} protocol. It may be more useful for \code{utcoffset(None)}
|
||||
\class{tzinfo} protocols. It may be more useful for \code{utcoffset(None)}
|
||||
to return the standard UTC offset, as there is no other convention for
|
||||
discovering the standard offset.
|
||||
|
||||
|
@ -1124,6 +1192,50 @@ user code calls \class{tzinfo} methods directly. The intent is that
|
|||
the \class{tzinfo} methods interpret \var{dt} as being in local time,
|
||||
and not need worry about objects in other timezones.
|
||||
|
||||
There is one more \class{tzinfo} method that a subclass may wish to
|
||||
override:
|
||||
|
||||
\begin{methoddesc}{fromutc}{self, dt}
|
||||
This is called from the default \class{datetime.astimezone()}
|
||||
implementation. When called from that, \code{\var{dt}.tzinfo} is
|
||||
\var{self}, and \var{dt}'s date and time members are to be viewed as
|
||||
expressing a UTC time. The purpose of \method{fromutc()} is to
|
||||
adjust the date and time members, returning an equivalent datetime in
|
||||
\var{self}'s local time.
|
||||
|
||||
Most \class{tzinfo} subclasses should be able to inherit the default
|
||||
\method{fromutc()} implementation without problems. It's strong enough
|
||||
to handle fixed-offset time zones, and time zones accounting for both
|
||||
standard and daylight time, and the latter even if the DST transition
|
||||
times differ in different years. An example of a time zone the default
|
||||
\method{fromutc()} implementation may not handle correctly in all cases
|
||||
is one where the standard offset (from UTC) depends on the specific date
|
||||
and time passed, which can happen for political reasons.
|
||||
The default implementations of \method{astimezone()} and
|
||||
\method{fromutc()} may not produce the result you want if the result is
|
||||
one of the hours straddling the moment the standard offset changes.
|
||||
|
||||
Skipping code for error cases, the default \method{fromutc()}
|
||||
implementation acts like:
|
||||
|
||||
\begin{verbatim}
|
||||
def fromutc(self, dt):
|
||||
# raise ValueError error if dt.tzinfo is not self
|
||||
dtoff = dt.utcoffset()
|
||||
dtdst = dt.dst()
|
||||
# raise ValueError if dtoff is None or dtdst is None
|
||||
delta = dtoff - dtdst # this is self's standard offset
|
||||
if delta:
|
||||
dt += delta # convert to standard local time
|
||||
dtdst = dt.dst()
|
||||
# raise ValueError if dtdst is None
|
||||
if dtdst:
|
||||
return dt + dtdst
|
||||
else:
|
||||
return dt
|
||||
\end{verbatim}
|
||||
\end{methoddesc}
|
||||
|
||||
Example \class{tzinfo} classes:
|
||||
|
||||
\verbatiminput{tzinfo-examples.py}
|
||||
|
@ -1150,7 +1262,7 @@ to 3:00. A wall time of the form 2:MM doesn't really make sense on that
|
|||
day, so \code{astimezone(Eastern)} won't deliver a result with
|
||||
\code{hour==2} on the
|
||||
day DST begins. In order for \method{astimezone()} to make this
|
||||
guarantee, the \class{tzinfo} \method{dst()} method must consider times
|
||||
guarantee, the \method{rzinfo.dst()} method must consider times
|
||||
in the "missing hour" (2:MM for Eastern) to be in daylight time.
|
||||
|
||||
When DST ends (the "end" line), there's a potentially worse problem:
|
||||
|
@ -1162,8 +1274,8 @@ Local times of the form 1:MM are ambiguous. \method{astimezone()} mimics
|
|||
the local clock's behavior by mapping two adjacent UTC hours into the
|
||||
same local hour then. In the Eastern example, UTC times of the form
|
||||
5:MM and 6:MM both map to 1:MM when converted to Eastern. In order for
|
||||
\method{astimezone()} to make this guarantee, the \class{tzinfo}
|
||||
\method{dst()} method must consider times in the "repeated hour" to be in
|
||||
\method{astimezone()} to make this guarantee, the \method{tzinfo.dst()}
|
||||
method must consider times in the "repeated hour" to be in
|
||||
standard time. This is easily arranged, as in the example, by expressing
|
||||
DST switch times in the time zone's standard local time.
|
||||
|
||||
|
@ -1235,9 +1347,7 @@ Struct typedefs:
|
|||
|
||||
PyDateTime_Date
|
||||
PyDateTime_DateTime
|
||||
PyDateTime_DateTimeTZ
|
||||
PyDateTime_Time
|
||||
PyDateTime_TimeTZ
|
||||
PyDateTime_Delta
|
||||
PyDateTime_TZInfo
|
||||
|
||||
|
@ -1249,15 +1359,9 @@ Type-check macros:
|
|||
PyDateTime_Check(op)
|
||||
PyDateTime_CheckExact(op)
|
||||
|
||||
PyDateTimeTZ_Check(op)
|
||||
PyDateTimeTZ_CheckExact(op)
|
||||
|
||||
PyTime_Check(op)
|
||||
PyTime_CheckExact(op)
|
||||
|
||||
PyTimeTZ_Check(op)
|
||||
PyTimeTZ_CheckExact(op)
|
||||
|
||||
PyDelta_Check(op)
|
||||
PyDelta_CheckExact(op)
|
||||
|
||||
|
@ -1269,18 +1373,18 @@ Accessor macros:
|
|||
All objects are immutable, so accessors are read-only. All macros
|
||||
return ints:
|
||||
|
||||
For \class{date}, \class{datetime}, and \class{datetimetz} instances:
|
||||
For \class{date} and \class{datetime} instances:
|
||||
PyDateTime_GET_YEAR(o)
|
||||
PyDateTime_GET_MONTH(o)
|
||||
PyDateTime_GET_DAY(o)
|
||||
|
||||
For \class{datetime} and \class{datetimetz} instances:
|
||||
For \class{datetime} instances:
|
||||
PyDateTime_DATE_GET_HOUR(o)
|
||||
PyDateTime_DATE_GET_MINUTE(o)
|
||||
PyDateTime_DATE_GET_SECOND(o)
|
||||
PyDateTime_DATE_GET_MICROSECOND(o)
|
||||
|
||||
For \class{time} and \class{timetz} instances:
|
||||
For \class{time} instances:
|
||||
PyDateTime_TIME_GET_HOUR(o)
|
||||
PyDateTime_TIME_GET_MINUTE(o)
|
||||
PyDateTime_TIME_GET_SECOND(o)
|
||||
|
|
|
@ -27,7 +27,7 @@ class FixedOffset(tzinfo):
|
|||
"""Fixed offset in minutes east from UTC."""
|
||||
|
||||
def __init__(self, offset, name):
|
||||
self.__offset = timdelta(minutes = offset)
|
||||
self.__offset = timedelta(minutes = offset)
|
||||
self.__name = name
|
||||
|
||||
def utcoffset(self, dt):
|
||||
|
@ -116,9 +116,9 @@ class USTimeZone(tzinfo):
|
|||
def dst(self, dt):
|
||||
if dt is None or dt.tzinfo is None:
|
||||
# An exception may be sensible here, in one or both cases.
|
||||
# It depends on how you want to treat them. The astimezone()
|
||||
# implementation always passes a datetime with
|
||||
# dt.tzinfo == self.
|
||||
# It depends on how you want to treat them. The default
|
||||
# fromutc() implementation (called by the default astimezone()
|
||||
# implementation) passes a datetime with dt.tzinfo is self.
|
||||
return ZERO
|
||||
assert dt.tzinfo is self
|
||||
|
||||
|
|
22
Misc/NEWS
22
Misc/NEWS
|
@ -45,7 +45,7 @@ Extension modules
|
|||
microsecond <http://www.python.org/sf/661086>. This repairs an
|
||||
irritation most likely seen on Windows systems.
|
||||
|
||||
In dt.asdatetime(tz), if tz.utcoffset(dt) returns a duration,
|
||||
In dt.astimezone(tz), if tz.utcoffset(dt) returns a duration,
|
||||
ValueError is raised if tz.dst(dt) returns None (2.3a1 treated it
|
||||
as 0 instead, but a tzinfo subclass wishing to participate in
|
||||
time zone conversion has to take a stand on whether it supports
|
||||
|
@ -60,11 +60,27 @@ Extension modules
|
|||
The example tzinfo class for local time had a bug. It was replaced
|
||||
by a later example coded by Guido.
|
||||
|
||||
datetimetz.astimezone(tz) no longer raises an exception when the
|
||||
datetime.astimezone(tz) no longer raises an exception when the
|
||||
input datetime has no UTC equivalent in tz. For typical "hybrid" time
|
||||
zones (a single tzinfo subclass modeling both standard and daylight
|
||||
time), this case can arise one hour per year, at the hour daylight time
|
||||
ends. See new docs for details.
|
||||
ends. See new docs for details. In short, the new behavior mimics
|
||||
the local wall clock's behavior of repeating an hour in local time.
|
||||
|
||||
dt.astimezone() can no longer be used to convert between naive and aware
|
||||
datetime objects. If you merely want to attach, or remove, a tzinfo
|
||||
object, without any conversion of date and time members, use
|
||||
dt.replace(tzinfo=whatever) instead, where "whatever" is None or a
|
||||
tzinfo subclass instance.
|
||||
|
||||
A new method tzinfo.fromutc(dt) can be overridden in tzinfo subclasses
|
||||
to give complete control over how a UTC time is to be converted to
|
||||
a local time. The default astimezone() implementation calls fromutc()
|
||||
as its last step, so a tzinfo subclass can affect that too by overriding
|
||||
fromutc(). It's expected that the default fromutc() implementation will
|
||||
be suitable as-is for "almost all" time zone subclasses, but the
|
||||
creativity of political time zone fiddling appears unbounded -- fromutc()
|
||||
allows the highly motivated to emulate any scheme expressible in Python.
|
||||
|
||||
The constructors building a datetime from a timestamp could raise
|
||||
ValueError if the platform C localtime()/gmtime() inserted "leap
|
||||
|
|
Loading…
Reference in New Issue