Django

Code

root/django/trunk/django/utils/datetime_safe.py

Revision 7946, 2.6 kB (checked in by adrian, 6 months ago)

Fixed #1443 -- Django's various bits now support dates before 1900. Thanks to SmileyChris?, Chris Green, Fredrik Lundh and others for patches and design help

Line 
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
Note: See TracBrowser for help on using the browser.