Opened 18 years ago
Closed 17 years ago
#2633 closed defect (fixed)
django.utils.dateformat.DateFormat.O() returns wrong value
Reported by: | mukappa | Owned by: | nobody |
---|---|---|---|
Component: | Core (Other) | Version: | dev |
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: | no | UI/UX: | no |
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 by , 18 years ago
comment:2 by , 18 years ago
Has patch: | set |
---|---|
Keywords: | datetime added |
Needs tests: | set |
Triage Stage: | Unreviewed → Accepted |
Version: | 0.95 |
Can we get some tests for this please?
comment:3 by , 18 years ago
Keywords: | Date Filter added |
---|---|
Patch needs improvement: | set |
Triage Stage: | Accepted → Design 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/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 http://docs.python.org/lib/datetime-timedelta.html, 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 by , 18 years ago
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/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 >
comment:5 by , 18 years ago
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.
by , 18 years ago
Attachment: | tmp_fix.diff added |
---|
comment:6 by , 18 years ago
Cc: | added |
---|
comment:7 by , 17 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
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: