gh-72346: Added isdst deprecation warning to email.utils.localtime (GH-91450)

This commit is contained in:
Alan Williams 2023-03-19 19:20:20 -05:00 committed by GitHub
parent 40d4f15793
commit 5e6661bce9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 44 deletions

View file

@ -13,19 +13,17 @@ module:
.. function:: localtime(dt=None) .. function:: localtime(dt=None)
Return local time as an aware datetime object. If called without Return local time as an aware datetime object. If called without
arguments, return current time. Otherwise *dt* argument should be a arguments, return current time. Otherwise *dt* argument should be a
:class:`~datetime.datetime` instance, and it is converted to the local time :class:`~datetime.datetime` instance, and it is converted to the local time
zone according to the system time zone database. If *dt* is naive (that 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 is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. The
case, a positive or zero value for *isdst* causes ``localtime`` to presume *isdst* parameter is ignored.
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`` to attempt to divine whether summer time
is in effect for the specified time.
.. versionadded:: 3.3 .. versionadded:: 3.3
.. deprecated-removed:: 3.12 3.14
The *isdst* parameter.
.. function:: make_msgid(idstring=None, domain=None) .. function:: make_msgid(idstring=None, domain=None)

View file

@ -565,6 +565,9 @@ Pending Removal in Python 3.14
* Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` with mutable * Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` with mutable
bases using the C API. bases using the C API.
* Deprecated the *isdst* parameter in :func:`email.utils.localtime`.
(Contributed by Alan Williams in :gh:`72346`.)
* ``__package__`` and ``__cached__`` will cease to be set or taken * ``__package__`` and ``__cached__`` will cease to be set or taken
into consideration by the import system (:gh:`97879`). into consideration by the import system (:gh:`97879`).

View file

@ -331,41 +331,23 @@ def collapse_rfc2231_value(value, errors='replace',
# better than not having it. # better than not having it.
# #
def localtime(dt=None, isdst=-1): def localtime(dt=None, isdst=None):
"""Return local time as an aware datetime object. """Return local time as an aware datetime object.
If called without arguments, return current time. Otherwise *dt* If called without arguments, return current time. Otherwise *dt*
argument should be a datetime instance, and it is converted to the 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 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. 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 The isdst parameter is ignored.
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 isdst is not None:
import warnings
warnings._deprecated(
"The 'isdst' parameter to 'localtime'",
message='{name} is deprecated and slated for removal in Python {remove}',
remove=(3, 14),
)
if dt is None: if dt is None:
return datetime.datetime.now(datetime.timezone.utc).astimezone() dt = datetime.datetime.now()
if dt.tzinfo is not None: return dt.astimezone()
return dt.astimezone()
# We have a naive datetime. Convert to a (localtime) timetuple and pass to
# system mktime together with the isdst hint. System mktime will return
# seconds since epoch.
tm = dt.timetuple()[:-1] + (isdst,)
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(seconds)[: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:
tz = datetime.timezone(delta)
return dt.replace(tzinfo=tz)

View file

@ -83,14 +83,14 @@ class LocaltimeTests(unittest.TestCase):
def test_localtime_daylight_true_dst_false(self): def test_localtime_daylight_true_dst_false(self):
test.support.patch(self, time, 'daylight', True) test.support.patch(self, time, 'daylight', True)
t0 = datetime.datetime(2012, 3, 12, 1, 1) t0 = datetime.datetime(2012, 3, 12, 1, 1)
t1 = utils.localtime(t0, isdst=-1) t1 = utils.localtime(t0)
t2 = utils.localtime(t1) t2 = utils.localtime(t1)
self.assertEqual(t1, t2) self.assertEqual(t1, t2)
def test_localtime_daylight_false_dst_false(self): def test_localtime_daylight_false_dst_false(self):
test.support.patch(self, time, 'daylight', False) test.support.patch(self, time, 'daylight', False)
t0 = datetime.datetime(2012, 3, 12, 1, 1) t0 = datetime.datetime(2012, 3, 12, 1, 1)
t1 = utils.localtime(t0, isdst=-1) t1 = utils.localtime(t0)
t2 = utils.localtime(t1) t2 = utils.localtime(t1)
self.assertEqual(t1, t2) self.assertEqual(t1, t2)
@ -98,7 +98,7 @@ class LocaltimeTests(unittest.TestCase):
def test_localtime_daylight_true_dst_true(self): def test_localtime_daylight_true_dst_true(self):
test.support.patch(self, time, 'daylight', True) test.support.patch(self, time, 'daylight', True)
t0 = datetime.datetime(2012, 3, 12, 1, 1) t0 = datetime.datetime(2012, 3, 12, 1, 1)
t1 = utils.localtime(t0, isdst=1) t1 = utils.localtime(t0)
t2 = utils.localtime(t1) t2 = utils.localtime(t1)
self.assertEqual(t1, t2) self.assertEqual(t1, t2)
@ -106,7 +106,7 @@ class LocaltimeTests(unittest.TestCase):
def test_localtime_daylight_false_dst_true(self): def test_localtime_daylight_false_dst_true(self):
test.support.patch(self, time, 'daylight', False) test.support.patch(self, time, 'daylight', False)
t0 = datetime.datetime(2012, 3, 12, 1, 1) t0 = datetime.datetime(2012, 3, 12, 1, 1)
t1 = utils.localtime(t0, isdst=1) t1 = utils.localtime(t0)
t2 = utils.localtime(t1) t2 = utils.localtime(t1)
self.assertEqual(t1, t2) self.assertEqual(t1, t2)
@ -157,6 +157,11 @@ class LocaltimeTests(unittest.TestCase):
t1 = utils.localtime(t0) t1 = utils.localtime(t0)
self.assertEqual(t1.tzname(), 'EET') self.assertEqual(t1.tzname(), 'EET')
def test_isdst_deprecation(self):
with self.assertWarns(DeprecationWarning):
t0 = datetime.datetime(1990, 1, 1)
t1 = utils.localtime(t0, isdst=True)
# Issue #24836: The timezone files are out of date (pre 2011k) # Issue #24836: The timezone files are out of date (pre 2011k)
# on Mac OS X Snow Leopard. # on Mac OS X Snow Leopard.
@test.support.requires_mac_ver(10, 7) @test.support.requires_mac_ver(10, 7)

View file

@ -0,0 +1 @@
Added deprecation warning to *isdst* parameter of :func:`email.utils.localtime`.