Commits

Anonymous committed d25ef9c

newforms-admin: Merged from trunk up to [7947].

Comments (0)

Files changed (15)

django/contrib/databrowse/plugins/calendars.py

 from django.utils.encoding import force_unicode
 from django.utils.safestring import mark_safe
 from django.views.generic import date_based
+from django.utils import datetime_safe
 
 class CalendarPlugin(DatabrowsePlugin):
     def __init__(self, field_names=None):
 
     def urls(self, plugin_name, easy_instance_field):
         if isinstance(easy_instance_field.field, models.DateField):
+            d = easy_instance_field.raw_value
             return [mark_safe(u'%s%s/%s/%s/%s/%s/' % (
                 easy_instance_field.model.url(),
                 plugin_name, easy_instance_field.field.name,
-                easy_instance_field.raw_value.year,
-                easy_instance_field.raw_value.strftime('%b').lower(),
-                easy_instance_field.raw_value.day))]
+                d.year,
+                datetime_safe.new_date(d).strftime('%b').lower(),
+                d.day))]
 
     def model_view(self, request, model_databrowse, url):
         self.model, self.site = model_databrowse.model, model_databrowse.site

django/core/serializers/base.py

     from StringIO import StringIO
 from django.db import models
 from django.utils.encoding import smart_str, smart_unicode
+from django.utils import datetime_safe
 
 class SerializationError(Exception):
     """Something bad happened during serialization."""
         Convert a field's value to a string.
         """
         if isinstance(field, models.DateTimeField):
-            value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
+            d = datetime_safe.new_datetime(getattr(obj, field.name))
+            value = d.strftime("%Y-%m-%d %H:%M:%S")
         else:
             value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
         return smart_unicode(value)

django/core/serializers/json.py

 from django.utils import simplejson
 from django.core.serializers.python import Serializer as PythonSerializer
 from django.core.serializers.python import Deserializer as PythonDeserializer
+from django.utils import datetime_safe
 try:
     from cStringIO import StringIO
 except ImportError:
     Convert a queryset to JSON.
     """
     internal_use_only = False
-    
+
     def end_serialization(self):
         self.options.pop('stream', None)
         self.options.pop('fields', None)
 
     def default(self, o):
         if isinstance(o, datetime.datetime):
-            return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
+            d = datetime_safe.new_datetime(o)
+            return d.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
         elif isinstance(o, datetime.date):
-            return o.strftime(self.DATE_FORMAT)
+            d = datetime_safe.new_date(o)
+            return d.strftime(self.DATE_FORMAT)
         elif isinstance(o, datetime.time):
             return o.strftime(self.TIME_FORMAT)
         elif isinstance(o, decimal.Decimal):

django/core/validators.py

     # Could use time.strptime here and catch errors, but datetime.date below
     # produces much friendlier error messages.
     year, month, day = map(int, date_string.split('-'))
-    # This check is needed because strftime is used when saving the date
-    # value to the database, and strftime requires that the year be >=1900.
-    if year < 1900:
-        raise ValidationError, _('Year must be 1900 or later.')
     try:
         date(year, month, day)
     except ValueError, e:
     """
     Usage: If you create an instance of the IsPowerOf validator:
         v = IsAPowerOf(2)
-    
+
     The following calls will succeed:
-        v(4, None) 
+        v(4, None)
         v(8, None)
         v(16, None)
-    
+
     But this call:
         v(17, None)
     will raise "django.core.validators.ValidationError: ['This value must be a power of 2.']"

django/db/backends/mysql/creation.py

     'FileField':         'varchar(%(max_length)s)',
     'FilePathField':     'varchar(%(max_length)s)',
     'FloatField':        'double precision',
-    'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'integer',
     'IPAddressField':    'char(15)',
     'NullBooleanField':  'bool',

django/db/backends/mysql_old/creation.py

     'FileField':         'varchar(%(max_length)s)',
     'FilePathField':     'varchar(%(max_length)s)',
     'FloatField':        'double precision',
-    'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'integer',
     'IPAddressField':    'char(15)',
     'NullBooleanField':  'bool',

django/db/backends/oracle/creation.py

     'FileField':                    'NVARCHAR2(%(max_length)s)',
     'FilePathField':                'NVARCHAR2(%(max_length)s)',
     'FloatField':                   'DOUBLE PRECISION',
-    'ImageField':                   'NVARCHAR2(%(max_length)s)',
     'IntegerField':                 'NUMBER(11)',
     'IPAddressField':               'VARCHAR2(15)',
     'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))',

django/db/backends/postgresql/creation.py

     'FileField':         'varchar(%(max_length)s)',
     'FilePathField':     'varchar(%(max_length)s)',
     'FloatField':        'double precision',
-    'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'integer',
     'IPAddressField':    'inet',
     'NullBooleanField':  'boolean',

django/db/backends/sqlite3/creation.py

     'FileField':                    'varchar(%(max_length)s)',
     'FilePathField':                'varchar(%(max_length)s)',
     'FloatField':                   'real',
-    'ImageField':                   'varchar(%(max_length)s)',
     'IntegerField':                 'integer',
     'IPAddressField':               'char(15)',
     'NullBooleanField':             'bool',

django/db/models/fields/__init__.py

 from django.utils.translation import ugettext_lazy, ugettext as _
 from django.utils.encoding import smart_unicode, force_unicode, smart_str
 from django.utils.maxlength import LegacyMaxlength
+from django.utils import datetime_safe
 
 class NOT_PROVIDED:
     pass
         if lookup_type in ('range', 'in'):
             value = [smart_unicode(v) for v in value]
         elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
-            value = value.strftime('%Y-%m-%d')
+            value = datetime_safe.new_date(value).strftime('%Y-%m-%d')
         else:
             value = smart_unicode(value)
         return Field.get_db_prep_lookup(self, lookup_type, value)
         # Casts dates into string format for entry into database.
         if value is not None:
             try:
-                value = value.strftime('%Y-%m-%d')
+                value = datetime_safe.new_date(value).strftime('%Y-%m-%d')
             except AttributeError:
                 # If value is already a string it won't have a strftime method,
                 # so we'll just let it pass through.
 
     def flatten_data(self, follow, obj=None):
         val = self._get_val_from_obj(obj)
-        return {self.attname: (val is not None and val.strftime("%Y-%m-%d") or '')}
+        if val is None:
+            data = ''
+        else:
+            data = datetime_safe.new_date(val).strftime("%Y-%m-%d")
+        return {self.attname: data}
 
     def formfield(self, **kwargs):
         defaults = {'form_class': forms.DateField}
     def flatten_data(self,follow, obj = None):
         val = self._get_val_from_obj(obj)
         date_field, time_field = self.get_manipulator_field_names('')
-        return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''),
-                time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
+        if val is None:
+            date_data = time_data = ''
+        else:
+            d = datetime_safe.new_datetime(val)
+            date_data = d.strftime('%Y-%m-%d')
+            time_data = d.strftime('%H:%M:%S')
+        return {date_field: date_data, time_field: time_data}
 
     def formfield(self, **kwargs):
         defaults = {'form_class': forms.DateTimeField}
         if not self.height_field:
             setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
 
-    def get_internal_type(self):
-        return "ImageField"
-
     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
         FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
         # If the image has height and/or width field(s) and they haven't

django/db/models/manipulators.py

 from django.utils.text import capfirst
 from django.utils.encoding import smart_str
 from django.utils.translation import ugettext as _
+from django.utils import datetime_safe
 
 def add_manipulators(sender):
     cls = sender
             pass
         else:
             format_string = (lookup_type == 'date') and '%B %d, %Y' or '%B %Y'
+            date_val = datetime_safe.new_datetime(date_val)
             raise validators.ValidationError, "Please enter a different %s. The one you entered is already being used for %s." % \
                 (from_field.verbose_name, date_val.strftime(format_string))

django/newforms/widgets.py

 from django.utils.translation import ugettext
 from django.utils.encoding import StrAndUnicode, force_unicode
 from django.utils.safestring import mark_safe
+from django.utils import datetime_safe
 from util import flatatt
 from urlparse import urljoin
 
         if value is None:
             value = ''
         elif hasattr(value, 'strftime'):
+            value = datetime_safe.new_datetime(value)
             value = value.strftime(self.format)
         return super(DateTimeInput, self).render(name, value, attrs)
 

django/utils/datetime_safe.py

+# 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

django/utils/tzinfo.py

         tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
         try:
             stamp = time.mktime(tt)
-        except OverflowError:
-            # 32 bit systems can't handle dates after Jan 2038, so we fake it
-            # in that case (since we only care about the DST flag here).
+        except (OverflowError, ValueError):
+            # 32 bit systems can't handle dates after Jan 2038, and certain
+            # systems can't handle dates before ~1901-12-01:
+            #
+            # >>> time.mktime((1900, 1, 13, 0, 0, 0, 0, 0, 0))
+            # OverflowError: mktime argument out of range
+            # >>> time.mktime((1850, 1, 13, 0, 0, 0, 0, 0, 0))
+            # ValueError: year out of range
+            #
+            # In this case, we fake the date, because we only care about the
+            # DST flag.
             tt = (2037,) + tt[1:]
             stamp = time.mktime(tt)
         tt = time.localtime(stamp)

tests/regressiontests/datetime_safe/tests.py

+r"""
+>>> from datetime import date as original_date, datetime as original_datetime
+>>> from django.utils.datetime_safe import date, datetime
+>>> just_safe = (1900, 1, 1)
+>>> just_unsafe = (1899, 12, 31, 23, 59, 59)
+>>> really_old = (20, 1, 1)
+>>> more_recent = (2006, 1, 1)
+
+>>> original_datetime(*more_recent) == datetime(*more_recent)
+True
+>>> original_datetime(*really_old) == datetime(*really_old)
+True
+>>> original_date(*more_recent) == date(*more_recent)
+True
+>>> original_date(*really_old) == date(*really_old)
+True
+
+>>> original_date(*just_safe).strftime('%Y-%m-%d') == date(*just_safe).strftime('%Y-%m-%d')
+True
+>>> original_datetime(*just_safe).strftime('%Y-%m-%d') == datetime(*just_safe).strftime('%Y-%m-%d')
+True
+
+>>> date(*just_unsafe[:3]).strftime('%Y-%m-%d (weekday %w)')
+'1899-12-31 (weekday 0)'
+>>> date(*just_safe).strftime('%Y-%m-%d (weekday %w)')
+'1900-01-01 (weekday 1)'
+
+>>> datetime(*just_unsafe).strftime('%Y-%m-%d %H:%M:%S (weekday %w)')
+'1899-12-31 23:59:59 (weekday 0)'
+>>> datetime(*just_safe).strftime('%Y-%m-%d %H:%M:%S (weekday %w)')
+'1900-01-01 00:00:00 (weekday 1)'
+
+>>> date(*just_safe).strftime('%y')   # %y will error before this date
+'00'
+>>> datetime(*just_safe).strftime('%y')
+'00'
+"""