app/django/utils/datetime_safe.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 # Python's datetime strftime doesn't handle dates before 1900.
       
     2 # These classes override date and datetime to support the formatting of a date
       
     3 # through its full "proleptic Gregorian" date range.
       
     4 #
       
     5 # Based on code submitted to comp.lang.python by Andrew Dalke
       
     6 #
       
     7 # >>> datetime_safe.date(1850, 8, 2).strftime("%Y/%M/%d was a %A")
       
     8 # '1850/08/02 was a Friday'
       
     9 
       
    10 from datetime import date as real_date, datetime as real_datetime
       
    11 import re
       
    12 import time
       
    13 
       
    14 class date(real_date):
       
    15     def strftime(self, fmt):
       
    16         return strftime(self, fmt)
       
    17 
       
    18 class datetime(real_datetime):
       
    19     def strftime(self, fmt):
       
    20         return strftime(self, fmt)
       
    21 
       
    22     def combine(self, date, time):
       
    23         return datetime(date.year, date.month, date.day, time.hour, time.minute, time.microsecond, time.tzinfo)
       
    24 
       
    25     def date(self):
       
    26         return date(self.year, self.month, self.day)
       
    27 
       
    28 def new_date(d):
       
    29     "Generate a safe date from a datetime.date object."
       
    30     return date(d.year, d.month, d.day)
       
    31 
       
    32 def new_datetime(d):
       
    33     """
       
    34     Generate a safe datetime from a datetime.date or datetime.datetime object.
       
    35     """
       
    36     kw = [d.year, d.month, d.day]
       
    37     if isinstance(d, real_datetime):
       
    38         kw.extend([d.hour, d.minute, d.second, d.microsecond, d.tzinfo])
       
    39     return datetime(*kw)
       
    40 
       
    41 # This library does not support strftime's "%s" or "%y" format strings.
       
    42 # Allowed if there's an even number of "%"s because they are escaped.
       
    43 _illegal_formatting = re.compile(r"((^|[^%])(%%)*%[sy])")
       
    44 
       
    45 def _findall(text, substr):
       
    46     # Also finds overlaps
       
    47     sites = []
       
    48     i = 0
       
    49     while 1:
       
    50         j = text.find(substr, i)
       
    51         if j == -1:
       
    52             break
       
    53         sites.append(j)
       
    54         i=j+1
       
    55     return sites
       
    56 
       
    57 def strftime(dt, fmt):
       
    58     if dt.year >= 1900:
       
    59         return super(type(dt), dt).strftime(fmt)
       
    60     illegal_formatting = _illegal_formatting.search(fmt)
       
    61     if illegal_formatting:
       
    62         raise TypeError("strftime of dates before 1900 does not handle" + illegal_formatting.group(0))
       
    63 
       
    64     year = dt.year
       
    65     # For every non-leap year century, advance by
       
    66     # 6 years to get into the 28-year repeat cycle
       
    67     delta = 2000 - year
       
    68     off = 6 * (delta // 100 + delta // 400)
       
    69     year = year + off
       
    70 
       
    71     # Move to around the year 2000
       
    72     year = year + ((2000 - year) // 28) * 28
       
    73     timetuple = dt.timetuple()
       
    74     s1 = time.strftime(fmt, (year,) + timetuple[1:])
       
    75     sites1 = _findall(s1, str(year))
       
    76 
       
    77     s2 = time.strftime(fmt, (year+28,) + timetuple[1:])
       
    78     sites2 = _findall(s2, str(year+28))
       
    79 
       
    80     sites = []
       
    81     for site in sites1:
       
    82         if site in sites2:
       
    83             sites.append(site)
       
    84 
       
    85     s = s1
       
    86     syear = "%4d" % (dt.year,)
       
    87     for site in sites:
       
    88         s = s[:site] + syear + s[site+4:]
       
    89     return s