Ticket #1443: datetime_pre_1900.2.patch

File datetime_pre_1900.2.patch, 17.1 KB (added by Chris Beaven, 18 years ago)

updated for recent change to date validator

  • django/core/validators.py

     
    132132    # Could use time.strptime here and catch errors, but datetime.date below
    133133    # produces much friendlier error messages.
    134134    year, month, day = map(int, date_string.split('-'))
    135     # This check is needed because strftime is used when saving the date
    136     # value to the database, and strftime requires that the year be >=1900.
    137     if year < 1900:
    138         raise ValidationError, gettext('Year must be 1900 or later.')
    139135    try:
    140136        date(year, month, day)
    141137    except ValueError, e:
  • django/db/backends/util.py

     
    11import datetime
     2from django.utils import datetime_pg
    23from time import time
    34
    45class CursorDebugWrapper(object):
     
    4344###############################################
    4445
    4546def typecast_date(s):
    46     return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null
     47    return s and datetime_pg.date(*map(int, s.split('-'))) or None # returns None if s is null
    4748
    4849def typecast_time(s): # does NOT store time zone information
    4950    if not s: return None
     
    7778        seconds, microseconds = seconds.split('.')
    7879    else:
    7980        microseconds = '0'
    80     return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]),
     81    return datetime_pg.datetime(int(dates[0]), int(dates[1]), int(dates[2]),
    8182        int(times[0]), int(times[1]), int(seconds), int(float('.'+microseconds) * 1000000))
    8283
    8384def typecast_boolean(s):
  • django/db/models/fields/__init__.py

     
    88from django.utils.text import capfirst
    99from django.utils.translation import gettext, gettext_lazy
    1010import datetime, os, time
     11from django.utils import datetime_pg
    1112
    1213class NOT_PROVIDED:
    1314    pass
     
    404405        Field.__init__(self, verbose_name, name, **kwargs)
    405406
    406407    def to_python(self, value):
    407         if isinstance(value, datetime.datetime):
    408             return value.date()
    409         if isinstance(value, datetime.date):
     408        if isinstance(value, datetime_pg.date):
    410409            return value
     410        if isinstance(value, (datetime.date, datetime.datetime)):
     411            return datetime_pg.new_date_pg(value)
    411412        validators.isValidANSIDate(value, None)
    412413        try:
    413             return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
     414            return datetime_pg.date(*time.strptime(value, '%Y-%m-%d')[:3])
    414415        except ValueError:
    415416            raise validators.ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
    416417
     
    461462
    462463class DateTimeField(DateField):
    463464    def to_python(self, value):
    464         if isinstance(value, datetime.datetime):
     465        if isinstance(value, datetime_pg.datetime):
    465466            return value
    466         if isinstance(value, datetime.date):
    467             return datetime.datetime(value.year, value.month, value.day)
     467        if isinstance(value, (datetime.date, datetime.datetime)):
     468            return datetime_pg.new_datetime_pg(value)
    468469        try: # Seconds are optional, so try converting seconds first.
    469             return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6])
     470            return datetime_pg.datetime(*time.strptime(value, '%Y-%m-%d %H:%M:%S')[:6])
    470471        except ValueError:
    471472            try: # Try without seconds.
    472                 return datetime.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5])
     473                return datetime_pg.datetime(*time.strptime(value, '%Y-%m-%d %H:%M')[:5])
    473474            except ValueError: # Try without hour/minutes/seconds.
    474475                try:
    475                     return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
     476                    return datetime_pg.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
    476477                except ValueError:
    477478                    raise validators.ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
    478479
     
    508509            d = new_data.get(date_field, None)
    509510            t = new_data.get(time_field, None)
    510511        if d is not None and t is not None:
    511             return datetime.datetime.combine(d, t)
     512            return datetime_pg.datetime.combine(d, t)
    512513        return self.get_default()
    513514
    514515    def flatten_data(self,follow, obj = None):
  • django/forms/__init__.py

     
    33from django.utils.html import escape
    44from django.conf import settings
    55from django.utils.translation import gettext, ngettext
     6from django.utils import datetime_pg
    67
    78FORM_FIELD_ID_PREFIX = 'id_'
    89
     
    809810        import time, datetime
    810811        try:
    811812            time_tuple = time.strptime(data, '%Y-%m-%d')
    812             return datetime.date(*time_tuple[0:3])
     813            return datetime_pg.date(*time_tuple[0:3])
    813814        except (ValueError, TypeError):
    814815            return None
    815816    html2python = staticmethod(html2python)
  • django/utils/datetime_pg.py

     
     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# >>> date_pg(1850, 8, 2).strftime("%Y/%M/%d was a %A")
     8# '1850/08/02 was a Friday'
     9# >>>
     10
     11from datetime import date as real_date, datetime as real_datetime
     12import time
     13import re
     14
     15
     16class date_pg(real_date):
     17    def strftime(self, fmt):
     18        return strftime(self, fmt)
     19date = date_pg
     20
     21
     22class datetime_pg(real_datetime):
     23    def strftime(self, fmt):
     24        return strftime(self, fmt)
     25    def combine(self, date, time):
     26        return datetime_pg(date.year, date.month, date.day, time.hour, time.minute, time.microsecond, time.tzinfo)
     27datetime = datetime_pg
     28
     29
     30def new_date_pg(d):
     31    """ Generate a date_pg from a datetime.date object """
     32    return date_pg(d.year, d.month, d.day)
     33
     34def new_datetime_pg(d):
     35    """ Generate a datetime_pg from a datetime.date or datetime.datetime object """
     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_pg(*kw)
     40
     41
     42# No support for strftime's "%s" or "%y".
     43# Allowed if there's an even number of "%"s because they are escaped.
     44_illegal_formatting = re.compile(r"((^|[^%])(%%)*%[sy])")
     45
     46def _findall(text, substr):
     47     # Also finds overlaps
     48     sites = []
     49     i = 0
     50     while 1:
     51         j = text.find(substr, i)
     52         if j == -1:
     53             break
     54         sites.append(j)
     55         i=j+1
     56     return sites
     57
     58def strftime(dt, fmt):
     59    if dt.year >= 1900:
     60        return super(type(dt), dt).strftime(fmt)
     61    illegal_formatting = _illegal_formatting.search(fmt)
     62    if illegal_formatting:
     63        raise TypeError("strftime of dates before 1900 does not handle" + illegal_formatting.group(0))
     64
     65    year = dt.year
     66    # For every non-leap year century, advance by
     67    # 6 years to get into the 28-year repeat cycle
     68    delta = 2000 - year
     69    off = 6*(delta // 100 + delta // 400)
     70    year = year + off
     71
     72    # Move to around the year 2000
     73    year = year + ((2000 - year)//28)*28
     74    timetuple = dt.timetuple()
     75    s1 = time.strftime(fmt, (year,) + timetuple[1:])
     76    sites1 = _findall(s1, str(year))
     77   
     78    s2 = time.strftime(fmt, (year+28,) + timetuple[1:])
     79    sites2 = _findall(s2, str(year+28))
     80
     81    sites = []
     82    for site in sites1:
     83        if site in sites2:
     84            sites.append(site)
     85           
     86    s = s1
     87    syear = "%4d" % (dt.year,)
     88    for site in sites:
     89        s = s[:site] + syear + s[site+4:]
     90    return s
  • tests/modeltests/basic/models.py

     
    1919[]
    2020
    2121# Create an Article.
    22 >>> from datetime import datetime
     22>>> from django.utils.datetime_pg import datetime
    2323>>> a = Article(id=None, headline='Area man programs in Python', pub_date=datetime(2005, 7, 28))
    2424
    2525# Save it into the database. You have to call save() explicitly.
     
    3333>>> a.headline
    3434'Area man programs in Python'
    3535>>> a.pub_date
    36 datetime.datetime(2005, 7, 28, 0, 0)
     36datetime_pg(2005, 7, 28, 0, 0)
    3737
    3838# Change values by changing the attributes, then calling save().
    3939>>> a.headline = 'Area woman programs in Python'
     
    101101>>> a2.headline
    102102'Second article'
    103103>>> a2.pub_date
    104 datetime.datetime(2005, 7, 29, 0, 0)
     104datetime_pg(2005, 7, 29, 0, 0)
    105105
    106106# ...or, you can use keyword arguments.
    107107>>> a3 = Article(id=None, headline='Third article', pub_date=datetime(2005, 7, 30))
     
    111111>>> a3.headline
    112112'Third article'
    113113>>> a3.pub_date
    114 datetime.datetime(2005, 7, 30, 0, 0)
     114datetime_pg(2005, 7, 30, 0, 0)
    115115
    116116# You can also mix and match position and keyword arguments, but be sure not to
    117117# duplicate field information.
     
    146146>>> a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 31, 12, 30))
    147147>>> a7.save()
    148148>>> Article.objects.get(id__exact=7).pub_date
    149 datetime.datetime(2005, 7, 31, 12, 30)
     149datetime_pg(2005, 7, 31, 12, 30)
    150150
    151151>>> a8 = Article(headline='Article 8', pub_date=datetime(2005, 7, 31, 12, 30, 45))
    152152>>> a8.save()
    153153>>> Article.objects.get(id__exact=8).pub_date
    154 datetime.datetime(2005, 7, 31, 12, 30, 45)
     154datetime_pg(2005, 7, 31, 12, 30, 45)
    155155>>> a8.id
    1561568L
    157157
     
    177177
    178178# dates() returns a list of available dates of the given scope for the given field.
    179179>>> Article.objects.dates('pub_date', 'year')
    180 [datetime.datetime(2005, 1, 1, 0, 0)]
     180[datetime_pg(2005, 1, 1, 0, 0)]
    181181>>> Article.objects.dates('pub_date', 'month')
    182 [datetime.datetime(2005, 7, 1, 0, 0)]
     182[datetime_pg(2005, 7, 1, 0, 0)]
    183183>>> Article.objects.dates('pub_date', 'day')
    184 [datetime.datetime(2005, 7, 28, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 31, 0, 0)]
     184[datetime_pg(2005, 7, 28, 0, 0), datetime_pg(2005, 7, 29, 0, 0), datetime_pg(2005, 7, 30, 0, 0), datetime_pg(2005, 7, 31, 0, 0)]
    185185>>> Article.objects.dates('pub_date', 'day', order='ASC')
    186 [datetime.datetime(2005, 7, 28, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 31, 0, 0)]
     186[datetime_pg(2005, 7, 28, 0, 0), datetime_pg(2005, 7, 29, 0, 0), datetime_pg(2005, 7, 30, 0, 0), datetime_pg(2005, 7, 31, 0, 0)]
    187187>>> Article.objects.dates('pub_date', 'day', order='DESC')
    188 [datetime.datetime(2005, 7, 31, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 28, 0, 0)]
     188[datetime_pg(2005, 7, 31, 0, 0), datetime_pg(2005, 7, 30, 0, 0), datetime_pg(2005, 7, 29, 0, 0), datetime_pg(2005, 7, 28, 0, 0)]
    189189
    190190# dates() requires valid arguments.
    191191
     
    213213# result one at a time, to save memory.
    214214>>> for a in Article.objects.dates('pub_date', 'day', order='DESC').iterator():
    215215...     print repr(a)
    216 datetime.datetime(2005, 7, 31, 0, 0)
    217 datetime.datetime(2005, 7, 30, 0, 0)
    218 datetime.datetime(2005, 7, 29, 0, 0)
    219 datetime.datetime(2005, 7, 28, 0, 0)
     216datetime_pg(2005, 7, 31, 0, 0)
     217datetime_pg(2005, 7, 30, 0, 0)
     218datetime_pg(2005, 7, 29, 0, 0)
     219datetime_pg(2005, 7, 28, 0, 0)
    220220
    221221# You can combine queries with & and |.
    222222>>> s1 = Article.objects.filter(id__exact=1)
     
    325325>>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180))
    326326>>> a9.save()
    327327>>> Article.objects.get(id__exact=9).pub_date
    328 datetime.datetime(2005, 7, 31, 12, 30, 45, 180)
     328datetime_pg(2005, 7, 31, 12, 30, 45, 180)
    329329"""
    330330
    331331if building_docs or settings.DATABASE_ENGINE == 'mysql':
     
    335335>>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180))
    336336>>> a9.save()
    337337>>> Article.objects.get(id__exact=9).pub_date
    338 datetime.datetime(2005, 7, 31, 12, 30, 45)
     338datetime_pg(2005, 7, 31, 12, 30, 45)
    339339"""
    340340
    341341__test__['API_TESTS'] += """
  • tests/modeltests/manipulators/models.py

     
    8787>>> a2
    8888<Album: Ultimate Ella>
    8989>>> a2.release_date
    90 datetime.date(2005, 2, 13)
     90date_pg(2005, 2, 13)
    9191"""}
  • tests/modeltests/or_lookups/models.py

     
    85853
    8686
    8787>>> list(Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')).values())
    88 [{'headline': 'Hello and goodbye', 'pub_date': datetime.datetime(2005, 11, 29, 0, 0), 'id': 3}]
     88[{'headline': 'Hello and goodbye', 'pub_date': datetime_pg(2005, 11, 29, 0, 0), 'id': 3}]
    8989
    9090>>> Article.objects.filter(Q(headline__startswith='Hello')).in_bulk([1,2])
    9191{1: <Article: Hello>}
  • tests/modeltests/reserved_names/models.py

     
    4949[<Thing: a>, <Thing: h>]
    5050
    5151>>> Thing.objects.dates('where', 'year')
    52 [datetime.datetime(2005, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)]
     52[datetime_pg(2005, 1, 1, 0, 0), datetime_pg(2006, 1, 1, 0, 0)]
    5353
    5454>>> Thing.objects.filter(where__month=1)
    5555[<Thing: a>]
  • tests/modeltests/validation/models.py

     
    9494>>> p.validate()
    9595{}
    9696>>> p.birthdate
    97 datetime.date(2000, 5, 3)
     97date_pg(2000, 5, 3)
    9898
    9999>>> p = Person(**dict(valid_params, birthdate=datetime.datetime(2000, 5, 3)))
    100100>>> p.validate()
    101101{}
    102102>>> p.birthdate
    103 datetime.date(2000, 5, 3)
     103date_pg(2000, 5, 3)
    104104
    105105>>> p = Person(**dict(valid_params, birthdate='2000-05-03'))
    106106>>> p.validate()
    107107{}
    108108>>> p.birthdate
    109 datetime.date(2000, 5, 3)
     109date_pg(2000, 5, 3)
    110110
    111111>>> p = Person(**dict(valid_params, birthdate='2000-5-3'))
    112112>>> p.validate()
    113113{}
    114114>>> p.birthdate
    115 datetime.date(2000, 5, 3)
     115date_pg(2000, 5, 3)
    116116
    117117>>> p = Person(**dict(valid_params, birthdate='foo'))
    118118>>> p.validate()
     
    122122>>> p.validate()
    123123{}
    124124>>> p.favorite_moment
    125 datetime.datetime(2002, 4, 3, 13, 23)
     125datetime_pg(2002, 4, 3, 13, 23)
    126126
    127127>>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3)))
    128128>>> p.validate()
    129129{}
    130130>>> p.favorite_moment
    131 datetime.datetime(2002, 4, 3, 0, 0)
     131datetime_pg(2002, 4, 3, 0, 0)
    132132
    133133>>> p = Person(**dict(valid_params, email='john@example.com'))
    134134>>> p.validate()
  • tests/regressiontests/datetime_pg/tests.py

     
     1r"""
     2>>> original_datetime(*more_recent) == datetime(*more_recent)
     3True
     4>>> original_datetime(*really_old) == datetime(*really_old)
     5True
     6>>> original_date(*more_recent) == date(*more_recent)
     7True
     8>>> original_date(*really_old) == date(*really_old)
     9True
     10
     11>>> original_date(*just_safe).strftime('%Y-%m-%d') == date(*just_safe).strftime('%Y-%m-%d')
     12True
     13>>> original_datetime(*just_safe).strftime('%Y-%m-%d') == datetime(*just_safe).strftime('%Y-%m-%d')
     14True
     15
     16>>> date(*just_unsafe[:3]).strftime('%Y-%m-%d (weekday %w)')
     17'1899-12-31 (weekday 0)'
     18>>> date(*just_safe).strftime('%Y-%m-%d (weekday %w)')
     19'1900-01-01 (weekday 1)'
     20
     21>>> datetime(*just_unsafe).strftime('%Y-%m-%d %H:%M:%S (weekday %w)')
     22'1899-12-31 23:59:59 (weekday 0)'
     23>>> datetime(*just_safe).strftime('%Y-%m-%d %H:%M:%S (weekday %w)')
     24'1900-01-01 00:00:00 (weekday 1)'
     25
     26>>> date(*just_safe).strftime('%y')   # %y will error before this date
     27'00'
     28>>> datetime(*just_safe).strftime('%y')
     29'00'
     30"""
     31
     32from datetime import date as original_date, datetime as original_datetime
     33from django.utils.datetime_pg import date, datetime
     34
     35just_safe = (1900, 1, 1)
     36just_unsafe = (1899, 12, 31, 23, 59, 59)
     37really_old = (20, 1, 1)
     38more_recent = (2006, 1, 1)
Back to Top