From ead620521e9157f68c7da64ecb8ab7478e1cab8c Mon Sep 17 00:00:00 2001 From: cabbagenom Date: Sat, 26 Mar 2016 18:10:02 +0000 Subject: [PATCH 1/3] DateTimeField to_representation can handle strings. Fixes #4013. --- rest_framework/fields.py | 14 ++++++++++++++ tests/test_fields.py | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 2a08e09ff..16074b76a 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1072,10 +1072,24 @@ class DateTimeField(Field): return value if output_format.lower() == ISO_8601: + if isinstance(value, str): + format_strings = (format_prefix + timezone_extension + for format_prefix in ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M:%S.%f') + for timezone_extension in ('', '%Z', '%z')) + for format_string in format_strings: + try: + value = datetime.datetime.strptime(value, format_string) + break + except ValueError: + pass + else: + raise ValueError('DateTime String %s did not match any valid format string.' % value) + value = value.isoformat() if value.endswith('+00:00'): value = value[:-6] + 'Z' return value + return value.strftime(output_format) diff --git a/tests/test_fields.py b/tests/test_fields.py index cefb45605..cce0181fa 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -978,6 +978,15 @@ class TestDateTimeField(FieldValues): outputs = { datetime.datetime(2001, 1, 1, 13, 00): '2001-01-01T13:00:00', datetime.datetime(2001, 1, 1, 13, 00, tzinfo=timezone.UTC()): '2001-01-01T13:00:00Z', + '2001-01-01T01:01': '2001-01-01T01:01:00', + '2001-01-01T01:01:01': '2001-01-01T01:01:01', + '2001-01-01T01:01:01.01': '2001-01-01T01:01:01.010000', + '2001-01-01T01:01+0100': '2001-01-01T01:01:00+01:00', + '2001-01-01T01:01:01+0100': '2001-01-01T01:01:01+01:00', + '2001-01-01T01:01:01.01+0100': '2001-01-01T01:01:01.010000+01:00', + '2001-01-01T01:01UTC': '2001-01-01T01:01:00', + '2001-01-01T01:01:01UTC': '2001-01-01T01:01:01', + '2001-01-01T01:01:01.01UTC': '2001-01-01T01:01:01.010000', None: None, '': None, } From e61a4f19cf5f89c2506a5f6a3e61b0d2d864efc2 Mon Sep 17 00:00:00 2001 From: cabbagenom Date: Sun, 27 Mar 2016 12:08:52 +0100 Subject: [PATCH 2/3] DateTimeField to_representation string check str -> six.string_types --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 16074b76a..d4496a2e8 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1072,7 +1072,7 @@ class DateTimeField(Field): return value if output_format.lower() == ISO_8601: - if isinstance(value, str): + if isinstance(value, six.string_types): format_strings = (format_prefix + timezone_extension for format_prefix in ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M:%S.%f') for timezone_extension in ('', '%Z', '%z')) From 8966d8e4586ca240ef8a89a0734c6049a43172f8 Mon Sep 17 00:00:00 2001 From: cabbagenom Date: Sun, 27 Mar 2016 12:17:51 +0100 Subject: [PATCH 3/3] DateTimeField tests reflect Python 2's strptime limitations. Given that Python 2's datetime.datetime.strptime function does not accept '+HHMM' strings with the format directive '%z', the tests for accepting such strings have been ommitted for python 2. --- tests/test_fields.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_fields.py b/tests/test_fields.py index cce0181fa..b31f59c7f 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -981,9 +981,10 @@ class TestDateTimeField(FieldValues): '2001-01-01T01:01': '2001-01-01T01:01:00', '2001-01-01T01:01:01': '2001-01-01T01:01:01', '2001-01-01T01:01:01.01': '2001-01-01T01:01:01.010000', - '2001-01-01T01:01+0100': '2001-01-01T01:01:00+01:00', - '2001-01-01T01:01:01+0100': '2001-01-01T01:01:01+01:00', - '2001-01-01T01:01:01.01+0100': '2001-01-01T01:01:01.010000+01:00', + # Caveat of Python 2's datetime module does not allow '+HHMM' ISO-8601 strings to be parsed in Python 2's strptime + '2001-01-01T01:01+0100' if six.PY3 else None: '2001-01-01T01:01:00+01:00' if six.PY3 else None, + '2001-01-01T01:01:01+0100' if six.PY3 else None: '2001-01-01T01:01:01+01:00' if six.PY3 else None, + '2001-01-01T01:01:01.01+0100' if six.PY3 else None: '2001-01-01T01:01:01.010000+01:00' if six.PY3 else None, '2001-01-01T01:01UTC': '2001-01-01T01:01:00', '2001-01-01T01:01:01UTC': '2001-01-01T01:01:01', '2001-01-01T01:01:01.01UTC': '2001-01-01T01:01:01.010000',