datetime_from_timet_and_us(): ignore leap seconds if the platform

localtime()/gmtime() insists on delivering them, + associated doc
changes.

Redid the docs for datetimtez.astimezone().
This commit is contained in:
Tim Peters 2003-01-04 18:17:36 +00:00
parent 85e4c6757f
commit 75a6e3bd1a
3 changed files with 50 additions and 21 deletions

View File

@ -314,8 +314,9 @@ Other constructors, all class methods:
\exception{ValueError}, if the timestamp is out of the range of \exception{ValueError}, if the timestamp is out of the range of
values supported by the platform C \cfunction{localtime()} values supported by the platform C \cfunction{localtime()}
function. It's common for this to be restricted to years from 1970 function. It's common for this to be restricted to years from 1970
through 2038. through 2038. Note that on non-POSIX systems that include leap
\end{methoddesc} seconds in their notion of a timestamp, leap seconds are ignored by
\method{fromtimestamp()}.
\begin{methoddesc}{fromordinal}{ordinal} \begin{methoddesc}{fromordinal}{ordinal}
Return the date corresponding to the proleptic Gregorian ordinal, Return the date corresponding to the proleptic Gregorian ordinal,
@ -546,6 +547,11 @@ Other constructors, all class methods:
range of values supported by the platform C range of values supported by the platform C
\cfunction{localtime()} function. It's common for this to be \cfunction{localtime()} function. It's common for this to be
restricted to years in 1970 through 2038. restricted to years in 1970 through 2038.
Note that on non-POSIX systems that include leap seconds in their
notion of a timestamp, leap seconds are ignored by
\method{fromtimestamp()}, and then it's possible to have two timestamps
differing by a second that yield identical \class{datetime} objects.
\end{methoddesc}
See also \method{utcfromtimestamp()}. See also \method{utcfromtimestamp()}.
\end{methoddesc} \end{methoddesc}
@ -988,16 +994,18 @@ April, and ends the minute after 1:59 (EDT) on the last Sunday in October:
When DST starts (the "start" line), the local wall clock leaps from 1:59 When DST starts (the "start" line), the local wall clock leaps from 1:59
to 3:00. A wall time of the form 2:MM doesn't really make sense on that to 3:00. A wall time of the form 2:MM doesn't really make sense on that
day, so astimezone(Eastern) won't deliver a result with hour=2 on the day, so \code{astimezone(Eastern)} won't deliver a result with
day DST begins. How an Eastern class chooses to interpret 2:MM on \code{hour==2} on the
that day is its business. The example Eastern class above chose to day DST begins. How an Eastern instance chooses to interpret 2:MM on
that day is its business. The example Eastern implementation above
chose to
consider it as a time in EDT, simply because it "looks like it's consider it as a time in EDT, simply because it "looks like it's
after 2:00", and so synonymous with the EST 1:MM times on that day. after 2:00", and so synonymous with the EST 1:MM times on that day.
Your Eastern class may wish, for example, to raise an exception instead Your Eastern class may wish, for example, to raise an exception instead
when it sees a 2:MM time on the day Eastern begins. when it sees a 2:MM time on the day EDT begins.
When DST ends (the "end" line), there's a potentially worse problem: When DST ends (the "end" line), there's a potentially worse problem:
there's an hour that can't be spelled at all in local wall time, the there's an hour that can't be spelled unambiguously in local wall time, the
hour beginning at the moment DST ends. In this example, that's times of hour beginning at the moment DST ends. In this example, that's times of
the form 6:MM UTC on the day daylight time ends. The local wall clock the form 6:MM UTC on the day daylight time ends. The local wall clock
leaps from 1:59 (daylight time) back to 1:00 (standard time) again. leaps from 1:59 (daylight time) back to 1:00 (standard time) again.
@ -1005,11 +1013,12 @@ leaps from 1:59 (daylight time) back to 1:00 (standard time) again.
2:MM is taken as standard time (it's "after 2:00"), so maps to 7:MM UTC. 2:MM is taken as standard time (it's "after 2:00"), so maps to 7:MM UTC.
There is no local time that maps to 6:MM UTC on this day. There is no local time that maps to 6:MM UTC on this day.
Just as the wall clock does, astimezone(Eastern) maps both UTC hours 5:MM Just as the wall clock does, \code{astimezone(Eastern)} maps both UTC
hours 5:MM
and 6:MM to Eastern hour 1:MM on this day. However, this result is and 6:MM to Eastern hour 1:MM on this day. However, this result is
ambiguous (there's no way for Eastern to know which repetition of 1:MM ambiguous (there's no way for Eastern to know which repetition of 1:MM
is intended). Applications that can't bear such ambiguity even one hour is intended). Applications that can't bear such ambiguity
per year should avoid using hybrid tzinfo classes; there are no should avoid using hybrid tzinfo classes; there are no
ambiguities when using UTC, or any other fixed-offset tzinfo subclass ambiguities when using UTC, or any other fixed-offset tzinfo subclass
(such as a class representing only EST (fixed offset -5 hours), or only (such as a class representing only EST (fixed offset -5 hours), or only
EDT (fixed offset -4 hours)). EDT (fixed offset -4 hours)).
@ -1354,19 +1363,24 @@ Instance methods:
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}{astimezone}{tz} \begin{methoddesc}{astimezone}{tz}
Return a \class{datetimetz} with new tzinfo member \var{tz}. \var{tz} Return a \class{datetimetz} object with new \membar{tzinfo} member
must be \code{None}, or an instance of a \class{tzinfo} subclass. If \var{tz}.
\var{tz} is \code{None}, self is naive, or \var{tz} must be \code{None}, or an instance of a \class{tzinfo} subclass.
If \var{tz} is \code{None}, \var{self} is naive,
\code{tz.utcoffset(self)} returns \code{None}, \code{tz.utcoffset(self)} returns \code{None},
or \code{self.tzinfo}\ is \var{tz},
\code{self.astimezone(tz)} is equivalent to \code{self.astimezone(tz)} is equivalent to
\code{self.replace(tzinfo=tz)}: a new timezone object is attached \code{self.replace(tzinfo=tz)}: a new timezone object is attached
without any conversion of date or time fields. If self is aware and without any conversion of date or time fields. Else \code{self.tzinfo}
\code{tz.utcoffset(self)} does not return \code{None}, the date and and \var{tz} must implement the \method{utcoffset()} and \method{dst()}
time fields are adjusted so that the result is local time in timezone \class{tzinfo} methods, and the date and time fields are adjusted so
tz, representing the same UTC time as self. that the result is local time in time zone \var{tz}, representing the
XXX [The treatment of endcases remains unclear: for DST-aware same UTC time as \var{self}: after \code{astz = dt.astimezone(tz)},
classes, one hour per year has two spellings in local time, and \code{astz - astz.utcoffset()} will usually have the same date and time
another hour has no spelling in local time.] XXX 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).
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}{utcoffset}{} \begin{methoddesc}{utcoffset}{}

View File

@ -50,6 +50,12 @@ Extension modules
time), this case can arise one hour per year, at the hour daylight time 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.
The constructors building a datetime from a timestamp could raise
ValueError if the platform C localtime()/gmtime() inserted "leap
seconds". Leap seconds are ignored now. On such platforms, it's
possible to have timestamps that differ by a second, yet where
datetimes constructed from them are equal.
Library Library
------- -------

View File

@ -2831,7 +2831,15 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us)
PyObject *result = NULL; PyObject *result = NULL;
tm = f(&timet); tm = f(&timet);
if (tm) if (tm) {
/* The platform localtime/gmtime may insert leap seconds,
* indicated by tm->tm_sec > 59. We don't care about them,
* except to the extent that passing them on to the datetime
* constructor would raise ValueError for a reason that
* made no sense to the user.
*/
if (tm->tm_sec > 59)
tm->tm_sec = 59;
result = PyObject_CallFunction(cls, "iiiiiii", result = PyObject_CallFunction(cls, "iiiiiii",
tm->tm_year + 1900, tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mon + 1,
@ -2840,6 +2848,7 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us)
tm->tm_min, tm->tm_min,
tm->tm_sec, tm->tm_sec,
us); us);
}
else else
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"timestamp out of range for " "timestamp out of range for "