diff --git a/django/newforms/fields.py b/django/newforms/fields.py index ce92886371..24849bdbcf 100644 --- a/django/newforms/fields.py +++ b/django/newforms/fields.py @@ -12,6 +12,7 @@ import time __all__ = ( 'Field', 'CharField', 'IntegerField', 'DEFAULT_DATE_INPUT_FORMATS', 'DateField', + 'DEFAULT_TIME_INPUT_FORMATS', 'TimeField', 'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', 'RegexField', 'EmailField', 'URLField', 'BooleanField', 'ChoiceField', 'MultipleChoiceField', @@ -134,6 +135,33 @@ class DateField(Field): continue raise ValidationError(gettext(u'Enter a valid date.')) +DEFAULT_TIME_INPUT_FORMATS = ( + '%H:%M:%S', # '14:30:59' + '%H:%M', # '14:30' +) + +class TimeField(Field): + def __init__(self, input_formats=None, required=True, widget=None, label=None): + Field.__init__(self, required, widget, label) + self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS + + def clean(self, value): + """ + Validates that the input can be converted to a time. Returns a Python + datetime.time object. + """ + Field.clean(self, value) + if value in EMPTY_VALUES: + return None + if isinstance(value, datetime.time): + return value + for format in self.input_formats: + try: + return datetime.time(*time.strptime(value, format)[3:6]) + except ValueError: + continue + raise ValidationError(gettext(u'Enter a valid time.')) + DEFAULT_DATETIME_INPUT_FORMATS = ( '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' '%Y-%m-%d %H:%M', # '2006-10-25 14:30' diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 5fe95421db..c75cedab14 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -834,6 +834,45 @@ Traceback (most recent call last): ... ValidationError: [u'Enter a valid date.'] +# TimeField ################################################################### + +>>> import datetime +>>> f = TimeField() +>>> f.clean(datetime.time(14, 25)) +datetime.time(14, 25) +>>> f.clean(datetime.time(14, 25, 59)) +datetime.time(14, 25, 59) +>>> f.clean('14:25') +datetime.time(14, 25) +>>> f.clean('14:25:59') +datetime.time(14, 25, 59) +>>> f.clean('hello') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid time.'] +>>> f.clean('1:24 p.m.') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid time.'] + +TimeField accepts an optional input_formats parameter: +>>> f = TimeField(input_formats=['%I:%M %p']) +>>> f.clean(datetime.time(14, 25)) +datetime.time(14, 25) +>>> f.clean(datetime.time(14, 25, 59)) +datetime.time(14, 25, 59) +>>> f.clean('4:25 AM') +datetime.time(4, 25) +>>> f.clean('4:25 PM') +datetime.time(16, 25) + +The input_formats parameter overrides all default input formats, +so the default formats won't work unless you specify them: +>>> f.clean('14:30:45') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid time.'] + # DateTimeField ############################################################### >>> import datetime