Commit b5b446d6 authored by Robert Collins's avatar Robert Collins

Issue #22932: Fix timezones in email.utils.formatdate.

Patch from Dmitry Shachnev.
parent 6e6c6a88
...@@ -155,30 +155,14 @@ def formatdate(timeval=None, localtime=False, usegmt=False): ...@@ -155,30 +155,14 @@ def formatdate(timeval=None, localtime=False, usegmt=False):
# 2822 requires that day and month names be the English abbreviations. # 2822 requires that day and month names be the English abbreviations.
if timeval is None: if timeval is None:
timeval = time.time() timeval = time.time()
if localtime: if localtime or usegmt:
now = time.localtime(timeval) dt = datetime.datetime.fromtimestamp(timeval, datetime.timezone.utc)
# Calculate timezone offset, based on whether the local zone has
# daylight savings time, and whether DST is in effect.
if time.daylight and now[-1]:
offset = time.altzone
else:
offset = time.timezone
hours, minutes = divmod(abs(offset), 3600)
# Remember offset is in seconds west of UTC, but the timezone is in
# minutes east of UTC, so the signs differ.
if offset > 0:
sign = '-'
else:
sign = '+'
zone = '%s%02d%02d' % (sign, hours, minutes // 60)
else: else:
now = time.gmtime(timeval) dt = datetime.datetime.utcfromtimestamp(timeval)
# Timezone offset is always -0000 if localtime:
if usegmt: dt = dt.astimezone()
zone = 'GMT' usegmt = False
else: return format_datetime(dt, usegmt)
zone = '-0000'
return _format_timetuple_and_zone(now, zone)
def format_datetime(dt, usegmt=False): def format_datetime(dt, usegmt=False):
"""Turn a datetime into a date string as specified in RFC 2822. """Turn a datetime into a date string as specified in RFC 2822.
......
...@@ -136,5 +136,25 @@ class LocaltimeTests(unittest.TestCase): ...@@ -136,5 +136,25 @@ class LocaltimeTests(unittest.TestCase):
t1 = utils.localtime(t0) t1 = utils.localtime(t0)
self.assertEqual(t1.tzname(), 'EET') self.assertEqual(t1.tzname(), 'EET')
class FormatDateTests(unittest.TestCase):
@test.support.run_with_tz('Europe/Minsk')
def test_formatdate(self):
timeval = time.mktime((2011, 12, 1, 18, 0, 0, 4, 335, 0))
string = utils.formatdate(timeval, localtime=False, usegmt=False)
self.assertEqual(string, 'Thu, 01 Dec 2011 15:00:00 -0000')
string = utils.formatdate(timeval, localtime=False, usegmt=True)
self.assertEqual(string, 'Thu, 01 Dec 2011 15:00:00 GMT')
@test.support.run_with_tz('Europe/Minsk')
def test_formatdate_with_localtime(self):
timeval = time.mktime((2011, 1, 1, 18, 0, 0, 6, 1, 0))
string = utils.formatdate(timeval, localtime=True)
self.assertEqual(string, 'Sat, 01 Jan 2011 18:00:00 +0200')
# Minsk moved from +0200 (with DST) to +0300 (without DST) in 2011
timeval = time.mktime((2011, 12, 1, 18, 0, 0, 4, 335, 0))
string = utils.formatdate(timeval, localtime=True)
self.assertEqual(string, 'Thu, 01 Dec 2011 18:00:00 +0300')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -1247,6 +1247,7 @@ Jerry Seutter ...@@ -1247,6 +1247,7 @@ Jerry Seutter
Pete Sevander Pete Sevander
Denis Severson Denis Severson
Ian Seyer Ian Seyer
Dmitry Shachnev
Daniel Shahaf Daniel Shahaf
Ha Shao Ha Shao
Mark Shannon Mark Shannon
......
...@@ -66,6 +66,9 @@ Core and Builtins ...@@ -66,6 +66,9 @@ Core and Builtins
Library Library
------- -------
- Issue #22932: Fix timezones in email.utils.formatdate.
Patch from Dmitry Shachnev.
- Issue #23779: imaplib raises TypeError if authenticator tries to abort. - Issue #23779: imaplib raises TypeError if authenticator tries to abort.
Patch from Craig Holmquist. Patch from Craig Holmquist.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment