diff --git a/AUTHORS.rst b/AUTHORS.rst index 1dee23ddc..77a2e984e 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -161,3 +161,4 @@ Contributors (chronological) - Stephen Eaton `@madeinoz67 `_ - Antonio Lassandro `@lassandroan `_ - Javier Fernández `@jfernandz `_ +- Felix Claessen `@flix6x `_ diff --git a/src/marshmallow/utils.py b/src/marshmallow/utils.py index cb5e5002d..b231bf0c6 100644 --- a/src/marshmallow/utils.py +++ b/src/marshmallow/utils.py @@ -117,7 +117,7 @@ def rfcformat(datetime: dt.datetime) -> str: r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" r"[T ](?P\d{1,2}):(?P\d{1,2})" r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" - r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" + r"(?PZ|[ +-]\d{2}(?::?\d{2})?)?$" ) _iso8601_date_re = re.compile(r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})$") diff --git a/tests/base.py b/tests/base.py index 707708cf8..4dd5a67e8 100644 --- a/tests/base.py +++ b/tests/base.py @@ -10,6 +10,7 @@ from marshmallow.exceptions import ValidationError central = pytz.timezone("US/Central") +adam = pytz.timezone("Europe/Amsterdam") ALL_FIELDS = [ diff --git a/tests/test_deserialization.py b/tests/test_deserialization.py index 911cb1743..095364bcb 100644 --- a/tests/test_deserialization.py +++ b/tests/test_deserialization.py @@ -3,6 +3,7 @@ import ipaddress import decimal import math +from urllib import parse import pytest @@ -10,7 +11,7 @@ from marshmallow.exceptions import ValidationError from marshmallow.validate import Equal -from tests.base import assert_date_equal, assert_time_equal, central, ALL_FIELDS +from tests.base import assert_date_equal, assert_time_equal, adam, central, ALL_FIELDS class TestDeserializingNone: @@ -456,6 +457,11 @@ def test_custom_date_format_datetime_field_deserialization(self): central.localize(dt.datetime(2013, 11, 10, 1, 23, 45), is_dst=False), True, ), + ( + "Sun, 10 Nov 2013 01:23:45 +0100", + adam.localize(dt.datetime(2013, 11, 10, 1, 23, 45), is_dst=False), + True, + ), ], ) def test_rfc_datetime_field_deserialization(self, fmt, value, expected, aware): @@ -500,6 +506,21 @@ def test_rfc_datetime_field_deserialization(self, fmt, value, expected, aware): central.localize(dt.datetime(2013, 11, 10, 1, 23, 45), is_dst=False), True, ), + ( + parse.unquote_plus("2013-11-10T01:23:45-06:00"), + central.localize(dt.datetime(2013, 11, 10, 1, 23, 45), is_dst=False), + True, + ), + ( + "2013-11-10T01:23:45+01:00", + adam.localize(dt.datetime(2013, 11, 10, 1, 23, 45), is_dst=False), + True, + ), + ( + parse.unquote_plus("2013-11-10T01:23:45+01:00"), + adam.localize(dt.datetime(2013, 11, 10, 1, 23, 45), is_dst=False), + True, + ), ], ) def test_iso_datetime_field_deserialization(self, fmt, value, expected, aware): @@ -558,7 +579,7 @@ def test_naive_datetime_with_timezone(self, fmt, timezone, value, expected): field = fields.NaiveDateTime(format=fmt, timezone=timezone) assert field.deserialize(value) == expected - @pytest.mark.parametrize("timezone", (dt.timezone.utc, central)) + @pytest.mark.parametrize("timezone", (dt.timezone.utc, central, adam)) @pytest.mark.parametrize( ("fmt", "value"), [("iso", "2013-11-10T01:23:45"), ("rfc", "Sun, 10 Nov 2013 01:23:45")],