[Patches] [ python-Patches-762963 ] timemodule.c: Python loses current timezone

SourceForge.net noreply@sourceforge.net
Mon, 30 Jun 2003 22:08:15 -0700

Patches item #762963, was opened at 2003-06-29 21:18
Message generated for change (Settings changed) made by rhettinger
You can respond by visiting: 

Category: Modules
Group: None
Status: Open
Resolution: None
Priority: 5
Submitted By: Doug Quale (quale)
>Assigned to: Brett Cannon (bcannon)
Summary: timemodule.c: Python loses current timezone

Initial Comment:
Python routines in timemodule.c sometimes force glibc
to use GMT instead of the correct timezone.

I think this is a longstanding bug, but I have only
looked at Python 2.2 and 2.33b1. This bug has been
reported before (510218) but it was misdiagnosed and
closed. It also came up recently in on the python-list
where it was also misdiagnosed.

Standard C and Python use a struct tm with 9 values. 
BSD influenced C libraries like glibc have an extra
field (tm_gmtoff) that keeps the offset from UTC. 
BSD-style struct tm values know the correct timezone
associated with the time, but Python and Standard C
struct tm values don't so they can only assume the
current timezone.

Ideally Python would always treat stuct tm-style time
tuples as being associated with the current timezone.
Unfortunately in many cases Python forces glibc to use
GMT rather than the current timezone.  You can see the
problem most graphically with the %z format in
strftime().  In the transcript Python incorrectly gives
the timezone offset as +0000 even though it gets the
timezone name (CDT) correct:

$ python2.3
Python 2.3b1+ (#2, Jun  4 2003, 03:03:32) 
[GCC 3.3 (Debian)] on linux2
Type "help", "copyright", "credits" or "license" for
more information.
>>> import time
>>> now = time.localtime()
>>> print now
(2003, 6, 29, 20, 3, 52, 6, 180, 1)
>>> RFC822 = '%a, %d %b %Y %T %z'
>>> print time.strftime(RFC822, now)
Sun, 29 Jun 2003 20:03:52 +0000
>>> print time.strftime(RFC822)
Sun, 29 Jun 2003 20:05:27 -0500
>>> print time.strftime('%Z', now)

The correct timezone is CDT and the correct offset is
-0500. Notice that when time.strftime() computes the
current time it it gets the correct timezone offset,
but when the struct tm tuple is passed in it thinks the
timezone offset is 0.  (glibc does know that the
correct timezone name is CDT even when passed a bad
struct tm value, but that's not surprising since the
timezone name is not stored in struct tm and it is not
computed from timezone offset.)

The problem is in the gettmargs() function in
timemodule.c. When getmargs() parses a Python tm tuple
it leaves the tm_gmtoff field zeroed. This specifically
tells glibc that the timezone offset is 0, which is
wrong for most people. (BSD libc may also be affected.)
This problem does not occur when time_strfrtime() gets
the current time itself since that codepath uses a
struct tm value directly from the libc localtime(),
leaving the tm_gmtoff field intact.

Fortunately the fix is almost trivial. A call to
mktime() will normalize the fields in the struct tm
value, including the tm_gmtoff field.  I
conditionalized the patch only on HAVE_MKTIME. I'm
pretty sure there's an autoconfigure test for tm_gmtoff
and it would probably be better to use that.


You can respond by visiting: