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