Opened 13 years ago

Closed 12 years ago

Last modified 12 years ago

#16899 closed Bug (fixed)

Wrong offset for Europe/Moscow

Reported by: igor@… Owned by: nobody
Component: Core (Other) Version: 1.3
Severity: Normal Keywords: timezone
Cc: iigor12 Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hello everybody!

in file source:/django/branches/releases/1.3.X/django/utils/tzinfo.py#L40 I see these code:

59	    def _isdst(self, dt):
60	        tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
61	        try:
62	            stamp = time.mktime(tt)
63	        except (OverflowError, ValueError):
64	            # 32 bit systems can't handle dates after Jan 2038, and certain
65	            # systems can't handle dates before ~1901-12-01:
66	            #
67	            # >>> time.mktime((1900, 1, 13, 0, 0, 0, 0, 0, 0))
68	            # OverflowError: mktime argument out of range
69	            # >>> time.mktime((1850, 1, 13, 0, 0, 0, 0, 0, 0))
70	            # ValueError: year out of range
71	            #
72	            # In this case, we fake the date, because we only care about the
73	            # DST flag.
74	            tt = (2037,) + tt[1:]
75	            stamp = time.mktime(tt)
76	        tt = time.localtime(stamp)
77	        return tt.tm_isdst > 0

It's using in

40	    def utcoffset(self, dt):
41	        if self._isdst(dt):
42	            return timedelta(seconds=-time.altzone)
43	        else:
44	            return timedelta(seconds=-time.timezone)

and make wrong value for Europe/Moscow. time.altzone contains proper value.

Why isn't time.daylight checked rather than _isdst?

$ export | grep TZ
TZ=Europe/Moscow
$ python
>>> import time
>>> time.tzname
('MSK', 'MSK')
>>> time.tzname, time.timezone, time.altzone
(('MSK', 'MSK'), -10800, -14400)
>>> time.localtime(time.mktime((2011, 9, 21, 14, 5, 10, 2, 0, -1))).tm_isdst
0
>>> time.daylight
1
>>>

Change History (6)

comment:1 by anonymous, 13 years ago

Proper way to get offset, as I understood

    def utcoffset(self, dt):
        from datetime import datetime
        tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
        try:
            stamp = time.mktime(tt)
        except (OverflowError, ValueError):
            # 32 bit systems can't handle dates after Jan 2038, and certain
            # systems can't handle dates before ~1901-12-01:
            #
            # >>> time.mktime((1900, 1, 13, 0, 0, 0, 0, 0, 0))
            # OverflowError: mktime argument out of range
            # >>> time.mktime((1850, 1, 13, 0, 0, 0, 0, 0, 0))
            # ValueError: year out of range
            #
            # In this case, we fake the date, because we only care about the
            # DST flag.
            tt = (2037,) + tt[1:]
            stamp = time.mktime(tt)
        return datetime.fromtimestamp(stamp) - datetime.utcfromtimestamp(stamp)

comment:2 by igor@…, 12 years ago

BTW, return datetime.fromtimestamp(stamp) - datetime.utcfromtimestamp(stamp) work only on system with /usr/share/zoneinfo/. Not on windows.
may be, using pytz as alternative.

comment:3 by iigor12, 12 years ago

Cc: iigor12 added

Same bug.

it's a strange time.zoninfo/altzone behaviour. http://blogs.gnome.org/jamesh/2006/12/31/python-timetimezone-timealtzone-edge-case/

comment:4 by Aymeric Augustin, 12 years ago

Triage Stage: UnreviewedAccepted

Why isn't time.daylight checked rather than _isdst?

The reason for not checking time.daylight is that time.daylight will always be True if the local time zone has DST — no matter if DST currently applies or not. But here, we want to check if a specific date is or isn't in the DST period. See http://bugs.python.org/issue7229 for a long discussion about improving Python's documentation of this flag.

Proper way to get offset, as I understood (...)

The first comment in http://bugs.python.org/issue1647654 backs your idea — and also handles days.


The code you're quoting was initially copy-pasted from Python's documentation — search "Example tzinfo classes" in http://docs.python.org/library/datetime. However, some bugs in these examples have been reported and fixed, in particular http://bugs.python.org/issue9063, but the patches haven't been backported to Django.

I'm accepting this ticket to:

  • backport the fixes in Python's documentation — Django's implementation has significantly diverged;
  • review our implementation of utcoffset, in the light of the discussions in Python's bug tracker; this is a complex topic, and it's easy to make mistakes...

comment:5 by Aymeric Augustin, 12 years ago

Resolution: fixed
Status: newclosed

In [16980]:

Fixed #16899 -- Backported the fix for http://bugs.python.org/issue9063 and added a test.

comment:6 by Aymeric Augustin, 12 years ago

Note that I have only fixed the issue originally described in this ticket.

I intend to review django.utils.tzinfo in the context of my work on #2626.

Note: See TracTickets for help on using tickets.
Back to Top