diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/email/utils.py | 53 | ||||
-rw-r--r-- | Lib/test/test_email/test_utils.py | 73 |
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() |