Django

Code

Ticket #2633 (closed: fixed)

Opened 2 years ago

Last modified 1 year ago

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

Reported by: mukappa Assigned to: nobody
Milestone: Component: Core framework
Version: SVN Keywords: datetime Date Filter
Cc: wbyoung@fadingred.org Triage Stage: Design decision needed
Has patch: 1 Needs documentation: 0
Needs tests: 1 Patch needs improvement: 1

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

tzinfo.patch (0.6 kB) - added by anonymous on 02/12/07 14:53:07.
Patch for django/utils/tzinfo.py
tmp_fix.diff (1.5 kB) - added by wbyoung@fadingred.org on 04/19/07 12:57:40.

Change History

09/10/06 12:39:40 changed by bahamut@macstorm.org

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"

01/18/07 04:03:19 changed by Simon G. <dev@simon.net.nz>

  • keywords set to datetime.
  • has_patch set to 1.
  • version deleted.
  • needs_tests set to 1.
  • stage changed from Unreviewed to Accepted.

Can we get some tests for this please?

02/12/07 13:58:43 changed by marcdm@phronein.com

  • keywords changed from datetime to datetime Date Filter.
  • needs_better_patch set to 1.
  • stage changed from Accepted to 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.

02/12/07 14:47:57 changed by marcdm@phronein.com

  • version set to 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
>         

02/12/07 14:53:07 changed by anonymous

  • attachment tzinfo.patch added.

Patch for django/utils/tzinfo.py

04/19/07 12:57:09 changed by wbyoung@fadingred.org

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.

04/19/07 12:57:40 changed by wbyoung@fadingred.org

  • attachment tmp_fix.diff added.

04/19/07 13:06:14 changed by wbyoung@fadingred.org

  • cc set to wbyoung@fadingred.org.

09/16/07 06:59:57 changed by mtredinnick

  • status changed from new to closed.
  • resolution set to fixed.

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


Add/Change #2633 (django.utils.dateformat.DateFormat.O() returns wrong value)




Change Properties
Action