mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
#665194: Update email.utils.localtime to use astimezone, and fix bug.
The new code correctly handles historic changes in UTC offsets. A test for this should follow. Original patch by Alexander Belopolsky.
This commit is contained in:
parent
17183a2972
commit
b8687df653
3 changed files with 33 additions and 31 deletions
|
@ -386,33 +386,26 @@ def localtime(dt=None, isdst=-1):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if dt is None:
|
if dt is None:
|
||||||
seconds = time.time()
|
dt = datetime.datetime.now(datetime.timezone.utc)
|
||||||
else:
|
if dt.tzinfo is not None:
|
||||||
if dt.tzinfo is None:
|
return dt.astimezone()
|
||||||
# A naive datetime is given. Convert to a (localtime)
|
# We have a naive datetime. Convert to a (localtime) timetuple and pass to
|
||||||
# timetuple and pass to system mktime together with
|
# system mktime together with the isdst hint. System mktime will return
|
||||||
# the isdst hint. System mktime will return seconds
|
# seconds since epoch.
|
||||||
# sysce epoch.
|
tm = dt.timetuple()[:-1] + (isdst,)
|
||||||
tm = dt.timetuple()[:-1] + (isdst,)
|
seconds = time.mktime(tm)
|
||||||
seconds = time.mktime(tm)
|
localtm = time.localtime(seconds)
|
||||||
|
try:
|
||||||
|
delta = datetime.timedelta(seconds=localtm.tm_gmtoff)
|
||||||
|
tz = datetime.timezone(delta, localtm.tm_zone)
|
||||||
|
except AttributeError:
|
||||||
|
# Compute UTC offset and compare with the value implied by tm_isdst.
|
||||||
|
# If the values match, use the zone name implied by tm_isdst.
|
||||||
|
delta = dt - datetime.datetime(*time.gmtime(ts)[:6])
|
||||||
|
dst = time.daylight and localtm.tm_isdst > 0
|
||||||
|
gmtoff = -(time.altzone if dst else time.timezone)
|
||||||
|
if delta == datetime.timedelta(seconds=gmtoff):
|
||||||
|
tz = datetime.timezone(delta, time.tzname[dst])
|
||||||
else:
|
else:
|
||||||
# An aware datetime is given. Use aware datetime
|
tz = datetime.timezone(delta)
|
||||||
# arithmetics to find seconds since epoch.
|
return dt.replace(tzinfo=tz)
|
||||||
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)
|
|
||||||
|
|
|
@ -87,17 +87,23 @@ class LocaltimeTests(unittest.TestCase):
|
||||||
t2 = utils.localtime(t1)
|
t2 = utils.localtime(t1)
|
||||||
self.assertEqual(t1, t2)
|
self.assertEqual(t1, t2)
|
||||||
|
|
||||||
|
@test.support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
|
||||||
def test_localtime_epoch_utc_daylight_true(self):
|
def test_localtime_epoch_utc_daylight_true(self):
|
||||||
test.support.patch(self, time, 'daylight', True)
|
test.support.patch(self, time, 'daylight', True)
|
||||||
t0 = datetime.datetime(1970, 1, 1, tzinfo = datetime.timezone.utc)
|
t0 = datetime.datetime(1970, 1, 1, tzinfo = datetime.timezone.utc)
|
||||||
t1 = utils.localtime(t0)
|
t1 = utils.localtime(t0)
|
||||||
self.assertEqual(t0, t1)
|
t2 = t0 - datetime.timedelta(hours=5)
|
||||||
|
t2 = t2.replace(tzinfo = datetime.timezone(datetime.timedelta(hours=-5)))
|
||||||
|
self.assertEqual(t1, t2)
|
||||||
|
|
||||||
|
@test.support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
|
||||||
def test_localtime_epoch_utc_daylight_false(self):
|
def test_localtime_epoch_utc_daylight_false(self):
|
||||||
test.support.patch(self, time, 'daylight', False)
|
test.support.patch(self, time, 'daylight', False)
|
||||||
t0 = datetime.datetime(1970, 1, 1, tzinfo = datetime.timezone.utc)
|
t0 = datetime.datetime(1970, 1, 1, tzinfo = datetime.timezone.utc)
|
||||||
t1 = utils.localtime(t0)
|
t1 = utils.localtime(t0)
|
||||||
self.assertEqual(t0, t1)
|
t2 = t0 - datetime.timedelta(hours=5)
|
||||||
|
t2 = t2.replace(tzinfo = datetime.timezone(datetime.timedelta(hours=-5)))
|
||||||
|
self.assertEqual(t1, t2)
|
||||||
|
|
||||||
def test_localtime_epoch_notz_daylight_true(self):
|
def test_localtime_epoch_notz_daylight_true(self):
|
||||||
test.support.patch(self, time, 'daylight', True)
|
test.support.patch(self, time, 'daylight', True)
|
||||||
|
|
|
@ -24,6 +24,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue ##665194: Update email.utils.localtime to use datetime.astimezone and
|
||||||
|
correctly handle historic changes in UTC offsets.
|
||||||
|
|
||||||
- Issue #15199: Fix JavaScript's default MIME type to application/javascript.
|
- Issue #15199: Fix JavaScript's default MIME type to application/javascript.
|
||||||
Patch by Bohuslav Kabrda.
|
Patch by Bohuslav Kabrda.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue