This commit is contained in:
Frankie Dintino 2018-03-21 18:57:02 +00:00 committed by GitHub
commit b364f36159
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 11 deletions

View File

@ -18,7 +18,7 @@ from django.core.validators import (
) )
from django.forms import FilePathField as DjangoFilePathField from django.forms import FilePathField as DjangoFilePathField
from django.forms import ImageField as DjangoImageField from django.forms import ImageField as DjangoImageField
from django.utils import six, timezone from django.utils import datetime_safe, six, timezone
from django.utils.dateparse import ( from django.utils.dateparse import (
parse_date, parse_datetime, parse_duration, parse_time parse_date, parse_datetime, parse_duration, parse_time
) )
@ -1152,6 +1152,12 @@ class DateTimeField(Field):
self.timezone = default_timezone self.timezone = default_timezone
super(DateTimeField, self).__init__(*args, **kwargs) super(DateTimeField, self).__init__(*args, **kwargs)
def ensure_pre_1900_safe(self, value):
if isinstance(value, datetime.date):
if six.PY2 and value.year < 1900:
value = datetime_safe.new_datetime(value)
return value
def enforce_timezone(self, value): def enforce_timezone(self, value):
""" """
When `self.default_timezone` is `None`, always return naive datetimes. When `self.default_timezone` is `None`, always return naive datetimes.
@ -1162,16 +1168,18 @@ class DateTimeField(Field):
if field_timezone is not None: if field_timezone is not None:
if timezone.is_aware(value): if timezone.is_aware(value):
try: try:
return value.astimezone(field_timezone) value = value.astimezone(field_timezone)
except OverflowError: except OverflowError:
self.fail('overflow') self.fail('overflow')
else:
try: try:
return timezone.make_aware(value, field_timezone) value = timezone.make_aware(value, field_timezone)
except InvalidTimeError: except InvalidTimeError:
self.fail('make_aware', timezone=field_timezone) self.fail('make_aware', timezone=field_timezone)
elif (field_timezone is None) and timezone.is_aware(value): elif (field_timezone is None) and timezone.is_aware(value):
return timezone.make_naive(value, utc) value = timezone.make_naive(value, utc)
return value
return self.ensure_pre_1900_safe(value)
def default_timezone(self): def default_timezone(self):
return timezone.get_current_timezone() if settings.USE_TZ else None return timezone.get_current_timezone() if settings.USE_TZ else None
@ -1236,6 +1244,12 @@ class DateField(Field):
self.input_formats = input_formats self.input_formats = input_formats
super(DateField, self).__init__(*args, **kwargs) super(DateField, self).__init__(*args, **kwargs)
def ensure_pre_1900_safe(self, value):
if isinstance(value, datetime.date):
if six.PY2 and value.year < 1900:
value = datetime_safe.new_date(value)
return value
def to_internal_value(self, value): def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS) input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS)
@ -1243,7 +1257,7 @@ class DateField(Field):
self.fail('datetime') self.fail('datetime')
if isinstance(value, datetime.date): if isinstance(value, datetime.date):
return value return self.ensure_pre_1900_safe(value)
for input_format in input_formats: for input_format in input_formats:
if input_format.lower() == ISO_8601: if input_format.lower() == ISO_8601:
@ -1253,14 +1267,14 @@ class DateField(Field):
pass pass
else: else:
if parsed is not None: if parsed is not None:
return parsed return self.ensure_pre_1900_safe(parsed)
else: else:
try: try:
parsed = self.datetime_parser(value, input_format) parsed = self.datetime_parser(value, input_format)
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
else: else:
return parsed.date() return self.ensure_pre_1900_safe(parsed.date())
humanized_format = humanize_datetime.date_formats(input_formats) humanized_format = humanize_datetime.date_formats(input_formats)
self.fail('invalid', format=humanized_format) self.fail('invalid', format=humanized_format)
@ -1283,6 +1297,8 @@ class DateField(Field):
'read-only field and deal with timezone issues explicitly.' 'read-only field and deal with timezone issues explicitly.'
) )
value = self.ensure_pre_1900_safe(value)
if output_format.lower() == ISO_8601: if output_format.lower() == ISO_8601:
return value.isoformat() return value.isoformat()

View File

@ -1120,6 +1120,7 @@ class TestDateField(FieldValues):
valid_inputs = { valid_inputs = {
'2001-01-01': datetime.date(2001, 1, 1), '2001-01-01': datetime.date(2001, 1, 1),
datetime.date(2001, 1, 1): datetime.date(2001, 1, 1), datetime.date(2001, 1, 1): datetime.date(2001, 1, 1),
'1800-01-01': datetime.date(1800, 1, 1),
} }
invalid_inputs = { invalid_inputs = {
'abc': ['Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].'], 'abc': ['Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].'],
@ -1129,6 +1130,8 @@ class TestDateField(FieldValues):
outputs = { outputs = {
datetime.date(2001, 1, 1): '2001-01-01', datetime.date(2001, 1, 1): '2001-01-01',
'2001-01-01': '2001-01-01', '2001-01-01': '2001-01-01',
datetime.date(1800, 1, 1): '1800-01-01',
'1800-01-01': '1800-01-01',
six.text_type('2016-01-10'): '2016-01-10', six.text_type('2016-01-10'): '2016-01-10',
None: None, None: None,
'': None, '': None,
@ -1174,6 +1177,18 @@ class TestNoOutputFormatDateField(FieldValues):
field = serializers.DateField(format=None) field = serializers.DateField(format=None)
class TestPre1900DateField(FieldValues):
"""
Values for `DateField` prior to 1900
"""
valid_inputs = {}
invalid_inputs = {}
outputs = {
datetime.date(1800, 1, 1): '01 Jan 1800',
}
field = serializers.DateField(format='%d %b %Y')
class TestDateTimeField(FieldValues): class TestDateTimeField(FieldValues):
""" """
Valid and invalid values for `DateTimeField`. Valid and invalid values for `DateTimeField`.
@ -1348,6 +1363,18 @@ class TestNaiveDayLightSavingTimeTimeZoneDateTimeField(FieldValues):
field = serializers.DateTimeField(default_timezone=MockTimezone()) field = serializers.DateTimeField(default_timezone=MockTimezone())
class TestPre1900DateTimeField(FieldValues):
"""
Values for `DateTimeField` prior to 1900.
"""
valid_inputs = {}
invalid_inputs = {}
outputs = {
datetime.datetime(1800, 1, 1, 13, 00): '01:00PM, 01 Jan 1800',
}
field = serializers.DateTimeField(format='%I:%M%p, %d %b %Y')
class TestTimeField(FieldValues): class TestTimeField(FieldValues):
""" """
Valid and invalid values for `TimeField`. Valid and invalid values for `TimeField`.