summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/email/utils.py53
-rw-r--r--Lib/test/test_email/test_utils.py73
2 files changed, 126 insertions, 0 deletions
diff --git a/Lib/email/utils.py b/Lib/email/utils.py
index b7e1bb9..39f7903 100644
--- a/Lib/email/utils.py
+++ b/Lib/email/utils.py
@@ -363,3 +363,56 @@ def collapse_rfc2231_value(value, errors='replace',
except LookupError:
# charset is not a known codec.
return unquote(text)
+
+
+#
+# datetime doesn't provide a localtime function yet, so provide one. Code
+# adapted from the patch in issue 9527. This may not be perfect, but it is
+# better than not having it.
+#
+
+def localtime(dt=None, isdst=-1):
+ """Return local time as an aware datetime object.
+
+ If called without arguments, return current time. Otherwise *dt*
+ argument should be a datetime instance, and it is converted to the
+ local time zone according to the system time zone database. If *dt* is
+ naive (that is, dt.tzinfo is None), it is assumed to be in local time.
+ In this case, a positive or zero value for *isdst* causes localtime to
+ presume initially that summer time (for example, Daylight Saving Time)
+ is or is not (respectively) in effect for the specified time. A
+ negative value for *isdst* causes the localtime() function to attempt
+ to divine whether summer time is in effect for the specified time.
+
+ """
+ if dt is None:
+ seconds = time.time()
+ else:
+ if dt.tzinfo is None:
+ # A naive datetime is given. Convert to a (localtime)
+ # timetuple and pass to system mktime together with
+ # the isdst hint. System mktime will return seconds
+ # sysce epoch.
+ tm = dt.timetuple()[:-1] + (isdst,)
+ seconds = time.mktime(tm)
+ else:
+ # An aware datetime is given. Use aware datetime
+ # arithmetics to find seconds since epoch.
+ delta = dt - datetime.datetime(1970, 1, 1,
+ tzinfo=datetime.timezone.utc)
+ seconds = delta.total_seconds()
+ tm = time.localtime(seconds)
+
+ # XXX: The following logic may not work correctly if UTC
+ # offset has changed since time provided in dt. This will be
+ # corrected in C implementation for platforms that support
+ # tm_gmtoff.
+ if time.daylight and tm.tm_isdst:
+ offset = time.altzone
+ tzname = time.tzname[1]
+ else:
+ offset = time.timezone
+ tzname = time.tzname[0]
+
+ tz = datetime.timezone(datetime.timedelta(seconds=-offset), tzname)
+ return datetime.datetime.fromtimestamp(seconds, tz)
diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py
index e003a64..d9c4d70 100644
--- a/Lib/test/test_email/test_utils.py
+++ b/Lib/test/test_email/test_utils.py
@@ -1,5 +1,7 @@
import datetime
from email import utils
+import test.support
+import time
import unittest
class DateTimeTests(unittest.TestCase):
@@ -43,3 +45,74 @@ class DateTimeTests(unittest.TestCase):
self.assertEqual(
utils.parsedate_to_datetime(self.datestring + ' -0000'),
self.naive_dt)
+
+
+class LocaltimeTests(unittest.TestCase):
+
+ def test_localtime_is_tz_aware_daylight_true(self):
+ test.support.patch(self, time, 'daylight', True)
+ t = utils.localtime()
+ self.assertIsNot(t.tzinfo, None)
+
+ def test_localtime_is_tz_aware_daylight_false(self):
+ test.support.patch(self, time, 'daylight', False)
+ t = utils.localtime()
+ self.assertIsNot(t.tzinfo, None)
+
+ def test_localtime_daylight_true_dst_false(self):
+ test.support.patch(self, time, 'daylight', True)
+ t0 = datetime.datetime(2012, 3, 12, 1, 1)
+ t1 = utils.localtime(t0, isdst=-1)
+ t2 = utils.localtime(t1)
+ self.assertEqual(t1, t2)
+
+ def test_localtime_daylight_false_dst_false(self):
+ test.support.patch(self, time, 'daylight', False)
+ t0 = datetime.datetime(2012, 3, 12, 1, 1)
+ t1 = utils.localtime(t0, isdst=-1)
+ t2 = utils.localtime(t1)
+ self.assertEqual(t1, t2)
+
+ def test_localtime_daylight_true_dst_true(self):
+ test.support.patch(self, time, 'daylight', True)
+ t0 = datetime.datetime(2012, 3, 12, 1, 1)
+ t1 = utils.localtime(t0, isdst=1)
+ t2 = utils.localtime(t1)
+ self.assertEqual(t1, t2)
+
+ def test_localtime_daylight_false_dst_true(self):
+ test.support.patch(self, time, 'daylight', False)
+ t0 = datetime.datetime(2012, 3, 12, 1, 1)
+ t1 = utils.localtime(t0, isdst=1)
+ t2 = utils.localtime(t1)
+ self.assertEqual(t1, t2)
+
+ def test_localtime_epoch_utc_daylight_true(self):
+ test.support.patch(self, time, 'daylight', True)
+ t0 = datetime.datetime(1970, 1, 1, tzinfo = datetime.timezone.utc)
+ t1 = utils.localtime(t0)
+ self.assertEqual(t0, t1)
+
+ def test_localtime_epoch_utc_daylight_false(self):
+ test.support.patch(self, time, 'daylight', False)
+ t0 = datetime.datetime(1970, 1, 1, tzinfo = datetime.timezone.utc)
+ t1 = utils.localtime(t0)
+ self.assertEqual(t0, t1)
+
+ def test_localtime_epoch_notz_daylight_true(self):
+ test.support.patch(self, time, 'daylight', True)
+ t0 = datetime.datetime(1970, 1, 1)
+ t1 = utils.localtime(t0)
+ t2 = utils.localtime(t0.replace(tzinfo=None))
+ self.assertEqual(t1, t2)
+
+ def test_localtime_epoch_notz_daylight_false(self):
+ test.support.patch(self, time, 'daylight', False)
+ t0 = datetime.datetime(1970, 1, 1)
+ t1 = utils.localtime(t0)
+ t2 = utils.localtime(t0.replace(tzinfo=None))
+ self.assertEqual(t1, t2)
+
+
+if __name__ == '__main__':
+ unittest.main()