[Python-checkins] cpython (merge 3.4 -> 3.5): Issue #22932: Fix timezones in email.utils.formatdate.

robert.collins python-checkins at python.org
Fri Jul 31 22:20:17 CEST 2015


https://hg.python.org/cpython/rev/94b43b36e464
changeset:   97169:94b43b36e464
branch:      3.5
parent:      97165:88c537e6d788
parent:      97168:fa8b76dfd138
user:        Robert Collins <rbtcollins at hp.com>
date:        Sat Aug 01 08:19:06 2015 +1200
summary:
  Issue #22932: Fix timezones in email.utils.formatdate.

Patch from Dmitry Shachnev.

files:
  Lib/email/utils.py                |  30 ++++--------------
  Lib/test/test_email/test_utils.py |  20 ++++++++++++
  Misc/ACKS                         |   1 +
  Misc/NEWS                         |   3 +
  4 files changed, 31 insertions(+), 23 deletions(-)


diff --git a/Lib/email/utils.py b/Lib/email/utils.py
--- a/Lib/email/utils.py
+++ b/Lib/email/utils.py
@@ -155,30 +155,14 @@
     # 2822 requires that day and month names be the English abbreviations.
     if timeval is None:
         timeval = time.time()
+    if localtime or usegmt:
+        dt = datetime.datetime.fromtimestamp(timeval, datetime.timezone.utc)
+    else:
+        dt = datetime.datetime.utcfromtimestamp(timeval)
     if localtime:
-        now = time.localtime(timeval)
-        # 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:
-        now = time.gmtime(timeval)
-        # Timezone offset is always -0000
-        if usegmt:
-            zone = 'GMT'
-        else:
-            zone = '-0000'
-    return _format_timetuple_and_zone(now, zone)
+        dt = dt.astimezone()
+        usegmt = False
+    return format_datetime(dt, usegmt)
 
 def format_datetime(dt, usegmt=False):
     """Turn a datetime into a date string as specified in RFC 2822.
diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py
--- a/Lib/test/test_email/test_utils.py
+++ b/Lib/test/test_email/test_utils.py
@@ -136,5 +136,25 @@
         t1 = utils.localtime(t0)
         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__':
     unittest.main()
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1282,6 +1282,7 @@
 Pete Sevander
 Denis Severson
 Ian Seyer
+Dmitry Shachnev
 Daniel Shahaf
 Ha Shao
 Mark Shannon
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,9 @@
 Library
 -------
 
+- Issue #22932: Fix timezones in email.utils.formatdate.
+  Patch from Dmitry Shachnev.
+
 - Issue #23779: imaplib raises TypeError if authenticator tries to abort.
   Patch from Craig Holmquist.
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list