Opened 12 years ago
Closed 11 years ago
#2633 closed defect (fixed)
django.utils.dateformat.DateFormat.O() returns wrong value
Description
from django.utils.dateformat
def O(self): "Difference to Greenwich time in hours; e.g. '+0200'" tz = self.timezone.utcoffset(self.data) 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(self.data) 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]$ ./manage.py 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. (InteractiveConsole) >>> from datetime import datetime >>> from django.utils.dateformat import DateFormat >>> dt = datetime.now() >>> dt datetime.datetime(2006, 8, 30, 20, 48, 14, 86518) >>> df = DateFormat(dt) >>> df.O() '+1900' >>> 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)
Change History (9)
comment:1 Changed 12 years ago by
comment:2 Changed 11 years ago by
Can we get some tests for this please?
comment:3 Changed 11 years ago by
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/tzinfo.py line 33:
def utcoffset(self, dt): if self._isdst(dt): return timedelta(0,seconds=-time.altzone) else: 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/dateformat.py from :
lines 160 - 163
def O(self): "Difference to Greenwich time in hours; e.g. '+0200'" tz = self.timezone.utcoffset(self.data) 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(self.data) 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 tzinfo.py 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
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/tzinfo.py
4c4,21 < 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
Patch for django/utils/tzinfo.py
comment:5 Changed 11 years ago by
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.
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: