Django

Code

Ticket #479: dateformat.patch

File dateformat.patch, 13.7 kB (added by Sune Kirkeby <sune.kirkeby@gmail.com>, 3 years ago)

New, improved and working patch for timezone-formatting in dateformat

  • django/utils/tzinfo.py

    old new  
     1"""Implementation of a tzinfo-classes for use with datetime.datetime.""" 
     2 
     3import time 
     4from datetime import timedelta, tzinfo 
     5 
     6ZERO = timedelta(0) 
     7STDOFFSET = timedelta(seconds=-time.timezone) 
     8DSTOFFSET = timedelta(seconds=-time.altzone) 
     9DSTDIFF = DSTOFFSET - STDOFFSET 
     10 
     11class FixedOffset(tzinfo): 
     12    """Fixed offset in minutes east from UTC.""" 
     13 
     14    def __init__(self, offset): 
     15        self.__offset = timedelta(minutes=offset) 
     16        # FIXME -- Not really a name... 
     17        self.__name = "%+03d%02d" % (offset / 60, offset % 60) 
     18 
     19    def __repr__(self): 
     20        return self.__name 
     21 
     22    def utcoffset(self, dt): 
     23        return self.__offset 
     24 
     25    def tzname(self, dt): 
     26        return self.__name 
     27 
     28    def dst(self, dt): 
     29        return ZERO 
     30 
     31class LocalTimezone(tzinfo): 
     32    """Proxy timezone information from time module.""" 
     33    def __init__(self, dt): 
     34        tzinfo.__init__(self, dt) 
     35        self._tzname = time.tzname[self._isdst(dt)] 
     36    def __repr__(self): 
     37        return self._tzname 
     38 
     39    def utcoffset(self, dt): 
     40        if self._isdst(dt): 
     41            return DSTOFFSET 
     42        else: 
     43            return STDOFFSET 
     44    def dst(self, dt): 
     45        if self._isdst(dt): 
     46            return DSTDIFF 
     47        else: 
     48            return ZERO 
     49    def tzname(self, dt): 
     50        return time.tzname[self._isdst(dt)] 
     51    def _isdst(self, dt): 
     52        tt = (dt.year, dt.month, dt.day, 
     53              dt.hour, dt.minute, dt.second, 
     54              dt.weekday(), 0, -1) 
     55        stamp = time.mktime(tt) 
     56        tt = time.localtime(stamp) 
     57        return tt.tm_isdst > 0 
  • django/utils/timesince.py

    old new  
    11import time, math, datetime 
     2from tzinfo import LocalTimezone 
    23 
    34def timesince(d, now=None): 
    45    """ 
     
    67    as a nicely formatted string, e.g "10 minutes" 
    78    Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since 
    89    """ 
    9     original = time.mktime(d.timetuple()) 
    1010    chunks = ( 
    1111      (60 * 60 * 24 * 365, 'year'), 
    1212      (60 * 60 * 24 * 30, 'month'), 
     
    1414      (60 * 60, 'hour'), 
    1515      (60, 'minute') 
    1616    ) 
    17     if not now: 
    18         now = time.time() 
    19     since = now - original 
     17    if now: 
     18        t = time.mktime(now) 
     19    else: 
     20        t = time.localtime() 
     21    if d.tzinfo: 
     22        tz = LocalTimezone() 
     23    else: 
     24        tz = None 
     25    now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz) 
     26    delta = now - d 
     27    since = delta.days * 24 * 60 * 60 + delta.seconds 
    2028    # Crazy iteration syntax because we need i to be current index 
    2129    for i, (seconds, name) in zip(range(len(chunks)), chunks): 
    2230        count = math.floor(since / seconds) 
  • django/utils/dateformat.py

    old new  
    1313 
    1414from calendar import isleap 
    1515from dates import MONTHS, MONTHS_AP, WEEKDAYS 
     16from tzinfo import LocalTimezone 
     17import time 
     18import re 
    1619 
     20re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])') 
     21split_formatstr = re_formatchars.split 
     22re_escaped = re.compile(r'\\(.)') 
     23 
    1724class DateFormat: 
    1825    year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] 
    1926 
    2027    def __init__(self, d): 
    2128        self.date = d 
    2229 
     30        self.timezone = getattr(self.date, 'tzinfo', None) 
     31        if not self.timezone: 
     32            self.timezone = LocalTimezone(self.date) 
     33 
    2334    def a(self): 
    2435        "'a.m.' or 'p.m.'" 
    2536        if self.date.hour > 11: 
     
    8495 
    8596    def I(self): 
    8697        "'1' if Daylight Savings Time, '0' otherwise." 
    87         raise NotImplementedError 
     98        if self.timezone.dst(self.date): 
     99            return '1' 
     100        else: 
     101            return '0' 
    88102 
    89103    def j(self): 
    90104        "Day of the month without leading zeros; i.e. '1' to '31'" 
     
    116130 
    117131    def O(self): 
    118132        "Difference to Greenwich time in hours; e.g. '+0200'" 
    119         raise NotImplementedError 
     133        tz = self.timezone.utcoffset(self.date) 
     134        return "%+03d%02d" % (tz.seconds / 3600, (tz.seconds / 60) % 60) 
    120135 
    121136    def P(self): 
    122137        """ 
     
    133148 
    134149    def r(self): 
    135150        "RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'" 
    136         raise NotImplementedError 
     151        return self.format('D, j M Y H:i:s O') 
    137152 
    138153    def s(self): 
    139154        "Seconds; i.e. '00' to '59'" 
     
    158173 
    159174    def T(self): 
    160175        "Time zone of this machine; e.g. 'EST' or 'MDT'" 
    161         raise NotImplementedError 
     176        name = self.timezone.tzname(self.date) 
     177        if name is None: 
     178            name = self.format('O') 
     179        return name 
    162180 
    163181    def U(self): 
    164182        "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)" 
    165         raise NotImplementedError 
     183        off = self.timezone.utcoffset(self.date) 
     184        return int(time.mktime(self.date.timetuple())) + off.seconds * 60 
    166185 
    167186    def w(self): 
    168187        "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)" 
    169         weekday = self.date.weekday() 
    170         if weekday == 0: 
    171             return 6 
    172         return weekday - 1 
     188        return (self.date.weekday() + 1) % 7 
    173189 
    174190    def W(self): 
    175191        "ISO-8601 week number of year, weeks starting on Monday" 
     
    197213                    week_number -= 1 
    198214        return week_number 
    199215 
     216    def y(self): 
     217        "Year, 2 digits; e.g. '99'" 
     218        return str(self.date.year)[2:] 
     219 
    200220    def Y(self): 
    201221        "Year, 4 digits; e.g. '1999'" 
    202222        return self.date.year 
    203223 
    204     def y(self): 
    205         "Year, 2 digits; e.g. '99'" 
    206         return str(self.date.year)[2:] 
    207  
    208224    def z(self): 
    209225        "Day of the year; i.e. '0' to '365'" 
    210226        doy = self.year_days[self.date.month] + self.date.day 
     
    216232        """Time zone offset in seconds (i.e. '-43200' to '43200'). The offset 
    217233        for timezones west of UTC is always negative, and for those east of UTC 
    218234        is always positive.""" 
    219         raise NotImplementedError 
     235        return self.timezone.utcoffset(self.date).seconds 
    220236 
    221237    def format(self, formatstr): 
    222         result = '' 
    223         for char in formatstr
    224             try
    225                 result += str(getattr(self, char)()) 
    226             except AttributeError
    227                 result += char 
    228         return result 
     238        pieces = [] 
     239        for i, piece in enumerate(split_formatstr(formatstr))
     240            if i % 2
     241                pieces.append(str(getattr(self, piece)())) 
     242            elif piece
     243                pieces.append(re_escaped.sub(r'\1', piece)) 
     244        return ''.join(pieces) 
    229245 
    230246class TimeFormat: 
    231247    def __init__(self, t): 
  • tests/othertests/db_typecasts.py

    old new  
    11# Unit tests for django.core.db.typecasts 
    22 
    33from django.core.db import typecasts 
     4from django.utils.tzinfo import FixedOffset 
    45import datetime 
    56 
    67TEST_CASES = { 
  • tests/othertests/dateformat.py

    old new  
     1""" 
     2>>> format(my_birthday, '') 
     3'' 
     4>>> format(my_birthday, 'a') 
     5'p.m.' 
     6>>> format(my_birthday, 'A') 
     7'PM' 
     8>>> format(my_birthday, 'j') 
     9'7' 
     10>>> format(my_birthday, 'l') 
     11'Saturday' 
     12>>> format(my_birthday, 'L') 
     13'False' 
     14>>> format(my_birthday, 'm') 
     15'07' 
     16>>> format(my_birthday, 'M') 
     17'Jul' 
     18>>> format(my_birthday, 'n') 
     19'7' 
     20>>> format(my_birthday, 'N') 
     21'July' 
     22>>> format(my_birthday, 'O') 
     23'+0100' 
     24>>> format(my_birthday, 'P') 
     25'10 p.m.' 
     26>>> format(my_birthday, 'r') 
     27'Sat, 7 Jul 1979 22:00:00 +0100' 
     28>>> format(my_birthday, 's') 
     29'00' 
     30>>> format(my_birthday, 'S') 
     31'th' 
     32>>> format(my_birthday, 't') 
     33Traceback (most recent call last): 
     34    ... 
     35NotImplementedError 
     36>>> format(my_birthday, 'T') 
     37'CET' 
     38>>> format(my_birthday, 'U') 
     39'300445200' 
     40>>> format(my_birthday, 'w') 
     41'6' 
     42>>> format(my_birthday, 'W') 
     43'27' 
     44>>> format(my_birthday, 'y') 
     45'79' 
     46>>> format(my_birthday, 'Y') 
     47'1979' 
     48>>> format(my_birthday, 'z') 
     49'188' 
     50>>> format(my_birthday, 'Z') 
     51'3600' 
     52 
     53>>> format(summertime, 'I') 
     54'1' 
     55>>> format(summertime, 'O') 
     56'+0200' 
     57>>> format(wintertime, 'I') 
     58'0' 
     59>>> format(wintertime, 'O') 
     60'+0100' 
     61 
     62>>> format(my_birthday, 'Y z \\C\\E\\T') 
     63'1979 188 CET' 
     64""" 
     65from django.utils.dateformat import format 
     66import datetime 
     67 
     68import os 
     69import time 
     70 
     71os.environ['TZ'] = 'Europe/Copenhagen' 
     72time.tzset() 
     73 
     74my_birthday = datetime.datetime(1979, 7, 7, 22, 00) 
     75summertime = datetime.datetime(2005, 10, 30, 1, 00) 
     76wintertime = datetime.datetime(2005, 10, 30, 4, 00)