Skip to content

Commit 8be4f70

Browse files
authored
Make RFC parsing not dependent of locale (#201)
* Make RFC parsing not dependent of locale * Add more tests * Return as UTC always * Keep timezone if any * Python 2.7 compat
1 parent 9e2e652 commit 8be4f70

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

msrest/serialization.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import calendar
2929
import datetime
3030
import decimal
31+
import email
3132
from enum import Enum
3233
import json
3334
import logging
@@ -78,6 +79,26 @@ def dst(self, dt):
7879
"""No daylight saving for UTC."""
7980
return datetime.timedelta(hours=1)
8081

82+
class _FixedOffset(datetime.tzinfo):
83+
"""Fixed offset in minutes east from UTC.
84+
Copy/pasted from Python doc
85+
:param int offset: offset in minutes
86+
"""
87+
88+
def __init__(self, offset):
89+
self.__offset = datetime.timedelta(minutes=offset)
90+
91+
def utcoffset(self, dt):
92+
return self.__offset
93+
94+
def tzname(self, dt):
95+
return str(self.__offset.total_seconds()/3600)
96+
97+
def __repr__(self):
98+
return "<FixedOffset {}>".format(self.tzname(None))
99+
100+
def dst(self, dt):
101+
return datetime.timedelta(0)
81102

82103
try:
83104
from datetime import timezone
@@ -1814,10 +1835,13 @@ def deserialize_rfc(attr):
18141835
if isinstance(attr, ET.Element):
18151836
attr = attr.text
18161837
try:
1817-
date_obj = datetime.datetime.strptime(
1818-
attr, "%a, %d %b %Y %H:%M:%S %Z")
1838+
parsed_date = email.utils.parsedate_tz(attr)
1839+
date_obj = datetime.datetime(
1840+
*parsed_date[:6],
1841+
tzinfo=_FixedOffset((parsed_date[9] or 0)/60)
1842+
)
18191843
if not date_obj.tzinfo:
1820-
date_obj = date_obj.replace(tzinfo=TZ_UTC)
1844+
date_obj = date_obj.astimezone(tz=TZ_UTC)
18211845
except ValueError as err:
18221846
msg = "Cannot deserialize to rfc datetime object."
18231847
raise_with_traceback(DeserializationError, msg, err)

tests/test_serialization.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,6 +1974,55 @@ def test_deserialize_datetime(self):
19741974
self.assertEqual(utc.tm_sec, 52)
19751975
self.assertEqual(a.microsecond, 780000)
19761976

1977+
def test_deserialize_datetime_rfc(self):
1978+
1979+
a = Deserializer.deserialize_rfc("Mon, 20 Nov 1995 19:12:08 -0500")
1980+
utc = a.utctimetuple()
1981+
1982+
# UTC: 21 Nov, 00:12:08
1983+
self.assertEqual(utc.tm_year, 1995)
1984+
self.assertEqual(utc.tm_mon, 11)
1985+
self.assertEqual(utc.tm_mday, 21)
1986+
self.assertEqual(utc.tm_hour, 0)
1987+
self.assertEqual(utc.tm_min, 12)
1988+
self.assertEqual(utc.tm_sec, 8)
1989+
self.assertEqual(a.microsecond, 0)
1990+
1991+
a = Deserializer.deserialize_rfc("Mon, 20 Nov 1995 19:12:08 CDT")
1992+
utc = a.utctimetuple()
1993+
1994+
# UTC: 21 Nov, 00:12:08
1995+
self.assertEqual(utc.tm_year, 1995)
1996+
self.assertEqual(utc.tm_mon, 11)
1997+
self.assertEqual(utc.tm_mday, 21)
1998+
self.assertEqual(utc.tm_hour, 0)
1999+
self.assertEqual(utc.tm_min, 12)
2000+
self.assertEqual(utc.tm_sec, 8)
2001+
self.assertEqual(a.microsecond, 0)
2002+
2003+
a = Deserializer.deserialize_rfc("Mon, 20 Nov 1995 19:12:08")
2004+
utc = a.utctimetuple()
2005+
2006+
# UTC: No info is considered UTC
2007+
self.assertEqual(utc.tm_year, 1995)
2008+
self.assertEqual(utc.tm_mon, 11)
2009+
self.assertEqual(utc.tm_mday, 20)
2010+
self.assertEqual(utc.tm_hour, 19)
2011+
self.assertEqual(utc.tm_min, 12)
2012+
self.assertEqual(utc.tm_sec, 8)
2013+
self.assertEqual(a.microsecond, 0)
2014+
2015+
a = Deserializer.deserialize_rfc("Mon, 20 Nov 1995 19:12:08 GMT")
2016+
utc = a.utctimetuple()
2017+
2018+
self.assertEqual(utc.tm_year, 1995)
2019+
self.assertEqual(utc.tm_mon, 11)
2020+
self.assertEqual(utc.tm_mday, 20)
2021+
self.assertEqual(utc.tm_hour, 19)
2022+
self.assertEqual(utc.tm_min, 12)
2023+
self.assertEqual(utc.tm_sec, 8)
2024+
self.assertEqual(a.microsecond, 0)
2025+
19772026
def test_polymorphic_deserialization(self):
19782027

19792028
class Zoo(Model):

0 commit comments

Comments
 (0)