diff -r 6641e941ef1e -r ff1a9aa48cfd app/django/utils/datetime_safe.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/django/utils/datetime_safe.py Tue Oct 14 16:00:59 2008 +0000 @@ -0,0 +1,89 @@ +# Python's datetime strftime doesn't handle dates before 1900. +# These classes override date and datetime to support the formatting of a date +# through its full "proleptic Gregorian" date range. +# +# Based on code submitted to comp.lang.python by Andrew Dalke +# +# >>> datetime_safe.date(1850, 8, 2).strftime("%Y/%M/%d was a %A") +# '1850/08/02 was a Friday' + +from datetime import date as real_date, datetime as real_datetime +import re +import time + +class date(real_date): + def strftime(self, fmt): + return strftime(self, fmt) + +class datetime(real_datetime): + def strftime(self, fmt): + return strftime(self, fmt) + + def combine(self, date, time): + return datetime(date.year, date.month, date.day, time.hour, time.minute, time.microsecond, time.tzinfo) + + def date(self): + return date(self.year, self.month, self.day) + +def new_date(d): + "Generate a safe date from a datetime.date object." + return date(d.year, d.month, d.day) + +def new_datetime(d): + """ + Generate a safe datetime from a datetime.date or datetime.datetime object. + """ + kw = [d.year, d.month, d.day] + if isinstance(d, real_datetime): + kw.extend([d.hour, d.minute, d.second, d.microsecond, d.tzinfo]) + return datetime(*kw) + +# This library does not support strftime's "%s" or "%y" format strings. +# Allowed if there's an even number of "%"s because they are escaped. +_illegal_formatting = re.compile(r"((^|[^%])(%%)*%[sy])") + +def _findall(text, substr): + # Also finds overlaps + sites = [] + i = 0 + while 1: + j = text.find(substr, i) + if j == -1: + break + sites.append(j) + i=j+1 + return sites + +def strftime(dt, fmt): + if dt.year >= 1900: + return super(type(dt), dt).strftime(fmt) + illegal_formatting = _illegal_formatting.search(fmt) + if illegal_formatting: + raise TypeError("strftime of dates before 1900 does not handle" + illegal_formatting.group(0)) + + year = dt.year + # For every non-leap year century, advance by + # 6 years to get into the 28-year repeat cycle + delta = 2000 - year + off = 6 * (delta // 100 + delta // 400) + year = year + off + + # Move to around the year 2000 + year = year + ((2000 - year) // 28) * 28 + timetuple = dt.timetuple() + s1 = time.strftime(fmt, (year,) + timetuple[1:]) + sites1 = _findall(s1, str(year)) + + s2 = time.strftime(fmt, (year+28,) + timetuple[1:]) + sites2 = _findall(s2, str(year+28)) + + sites = [] + for site in sites1: + if site in sites2: + sites.append(site) + + s = s1 + syear = "%4d" % (dt.year,) + for site in sites: + s = s[:site] + syear + s[site+4:] + return s