[Zope3-dev] Re: [Python-Dev] Holes in time

Guido van Rossum guido@python.org
Thu, 02 Jan 2003 23:12:58 -0500


Let me present the issue differently.

On Sunday, Oct 27, 2002, both 5:30 UTC and 6:30 UTC map to 1:30 am US
Eastern time: 5:30 UTC maps to 1:30 am EDT, and 6:30 UTC maps to 1:30
am EST.  (UTC uses a 24 hour clock.)

We have a tzinfo subclass representing the US Eastern (hybrid)
timezone whose primary responsibility is to translate from local time
in that timezone to UTC: Eastern.utcoffset(dt).  It can also tell us
how much of that offset is due to DST: Eastern.dst(dt).

It is crucial to understand that with "Eastern" as tzinfo, there is
only *one* value for 1:30 am on Oct 27, 2002.  The Eastern tzinfo
object arbitrarily decides this is EDT, so it maps to 5:30 UTC.  (But
the problem would still exist if it arbitrarily decided that it was
EST.)

It is also crucial to understand that we have no direct way to
translate UTC to Eastern.  We only have a direct way to translate
Eastern to UTC (by subtracting Eastern.utcoffset(dt)).

Usually, the utcoffset() for times that differ only a few hours is the
same, so we can approximate the reverse mapping (i.e. from UTC to
Eastern) by using the utcoffset() for the input time and assuming that
it is the same as that for the output time.  Code for this is:

   # Initially dt is a datetimetz expressed in UTC whose tzinfo is None
   dt = dt.replace(tzinfo=Eastern)
   dt = dt + Eastern.utcoffset(dt)

This is not sufficient, however, close to the DST switch.  For
example, let's try this with an initial dt value of 4:30 am UTC on Oct
27, 2002.  The code applies the UTC offset corresponding to 4:30 am
Eastern, which is -5 hours (EST), so the result is 11:30 pm the
previous day.  But this is wrong!  11:30 pm Eastern that day is in
DST, so the UTC offset should be -4 hours.

We can know we must make a correction, because we can compare the UTC
offset of the result to the UTC offset of the input, and see that they
differ.  But what correction to make?  The problem is that when the
input is 6:30 UTC, the result is 1:30 am Eastern, which is still taken
to be EDT.  If we apply the same correction as we did for 4:30 UTC, we
get 2:30 am Eastern, but that's wrong, because that's in EST,
corresponding to 7:30 UTC.  But if we don't apply a correction, and
stick with 1:30 am Eastern, we've got a time that corresponds to to
5:30 UTC.  So what time corresponds to 6:30 UTC?

The problem for astimezone() is to come up with the correct result
whenever it can, and yet somehow to fudge things so that 6:30 UTC gets
translated to 1:30 Eastern.  And astimezone() must not make many
assumptions about the nature of DST.

It can assume that the DST correction is >= 0 and probably less than
10 hours or so, and that DST changes don't occur more frequently than
twice a year (once on and once off), and that the DST correction is
constant during the DST period, and that the only variation in UTC
offset is due to DST.  But Tim has already taken all of that into
account -- read his proof at the end of datetime.py:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/python/nondist/sandbox/datetime/datetime.py?rev=1.140&content-type=text/vnd.viewcvs-markup

Can you do better?

--Guido van Rossum (home page: http://www.python.org/~guido/)