Opened 11 years ago

Closed 10 years ago

#2633 closed defect (fixed)

django.utils.dateformat.DateFormat.O() returns wrong value

Reported by: mukappa Owned by: nobody
Component: Core (Other) Version: master
Severity: normal Keywords: datetime Date Filter
Cc: wbyoung@… Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: yes
Easy pickings: UI/UX:


from django.utils.dateformat

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200'"
        tz = self.timezone.utcoffset(
        return "%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)

This is wrong when tz.days == -1

I think this modified method should work

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200'"
        tz = self.timezone.utcoffset(
        seconds = (tz.days * 24 * 60 * 60) + tz.seconds
        return "%+03d%02d" % (seconds // 3600, (seconds // 60) % 60)

This session demonstrates the bug. df.O() should output -0500 not +1900

mukappa@xxxx 0 /home/mukappa/src/mysite
[1005]$ ./ shell
Python 2.3.4 (#1, Feb 22 2005, 04:09:37) 
[GCC 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from datetime import datetime
>>> from django.utils.dateformat import DateFormat
>>> dt =
>>> dt
datetime.datetime(2006, 8, 30, 20, 48, 14, 86518)
>>> df = DateFormat(dt)
>>> df.O()
>>> df.r()
'Wed, 30 Aug 2006 20:48:14 +1900'

mukappa@xxxx 0 /home/mukappa/src/mysite
[1005]$ date -R
Wed, 30 Aug 2006 20:49:02 -0500

Attachments (2)

tzinfo.patch (656 bytes) - added by anonymous 11 years ago.
Patch for django/utils/
tmp_fix.diff (1.5 KB) - added by wbyoung@… 11 years ago.

Download all attachments as: .zip

Change History (9)

comment:1 Changed 11 years ago by bahamut@…

This bug should be marked as critical, it will break PostgreSQL 8.1.3 and above when the SET TIME ZONE query is ran.

From my PostgreSQL log:

ERROR:  time zone displacement out of range: "2006-09-10 13:18:09.079872+20:00"

comment:2 Changed 11 years ago by Simon G. <dev@…>

Has patch: set
Keywords: datetime added
Needs tests: set
Triage Stage: UnreviewedAccepted
Version: 0.95

Can we get some tests for this please?

comment:3 Changed 11 years ago by marcdm@…

Keywords: Date Filter added
Patch needs improvement: set
Triage Stage: AcceptedDesign decision needed

Actually, I was just looking at this one. The problem here is that django.utils.tzinfo.Localtime.utcoffset uses a negative value for seconds when creating the timedelta object.

here in file django/utils/ line 33:

    def utcoffset(self, dt):
        if self._isdst(dt):
            return timedelta(0,seconds=-time.altzone)
            return timedelta(seconds=-time.timezone)

According to, negative values for seconds/microseconds when initializing timedelta will yield a -1 day as well. This is because the object is not designed to return negative values for the seconds attribute.

The solution I believe is to do a summation of tz.days*24*3600 + tz.seconds. That should yield the correct value for the number of seconds in the UTC offset.

I modified django/utils/ from :
lines 160 - 163

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200'"
        tz = self.timezone.utcoffset(
        return "%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)

to the following :

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200'"
        tz = self.timezone.utcoffset(
        seconds = tz.days*24*3600 + tz.seconds
        return "%+03d%02d" % (seconds // 3600, (seconds // 60) % 60)

But this is just a temporary fix. A more permanent fix I feel, would be to replace the use of the timedelta object in and use a generic object that has a seconds attribute that gives the proper value in positive or negative.

comment:4 Changed 11 years ago by marcdm@…

Version: SVN

a more permanent fix. I not sure if it's flawed because the new timedelta object doesn't entirely represent the old one. So maybe it needs to use the getattribute method instead of getattr

Patch below :

for the file trunk/django/utils/

< from datetime import timedelta, tzinfo
> from datetime import timedelta as real_timedelta, tzinfo
> class timedelta(object) :
>     def __init__(self,*args,**kwargs) :
>         self.__td = real_timedelta(*args,**kwargs)
>         self.days = 0
>     def __total_seconds(self) :
>         return self.__td.days*24*3600 + self.__td.seconds
>     seconds = property(fget=__total_seconds, doc= 'total seconds for time difference')
>     def __getattr__(self, key) :
>         if key in ['days','seconds'] :
>             ret = getattr(self,key)
>         else :
>             ret = getattr(self.__td,key)
>         return ret

Changed 11 years ago by anonymous

Attachment: tzinfo.patch added

Patch for django/utils/

comment:5 Changed 11 years ago by wbyoung@…

I just ran across this bug myself. It'd be nice to see it fixed even if it's just marked as a HACK for now. It should at least work properly. I'm going to attach a patch that just fixes the problem rather than creating a new timedelta object.

Changed 11 years ago by wbyoung@…

Attachment: tmp_fix.diff added

comment:6 Changed 11 years ago by wbyoung@…

Cc: wbyoung@… added

comment:7 Changed 10 years ago by Malcolm Tredinnick

Resolution: fixed
Status: newclosed

(In [6358]) Fixed #2633 -- Fixed timezone computation in O() format function, using fix from [6300].

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