Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0b7fd8f

Browse files
authored
GH-103857: Deprecate utcnow and utcfromtimestamp (#103858)
Using `datetime.datetime.utcnow()` and `datetime.datetime.utcfromtimestamp()` will now raise a `DeprecationWarning`. We also have removed our internal uses of these functions and documented the change.
1 parent a5308e1 commit 0b7fd8f

File tree

10 files changed

+101
-34
lines changed

10 files changed

+101
-34
lines changed

Doc/library/datetime.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,10 @@ Other constructors, all class methods:
896896
in UTC. As such, the recommended way to create an object representing the
897897
current time in UTC is by calling ``datetime.now(timezone.utc)``.
898898

899+
.. deprecated:: 3.12
900+
901+
Use :meth:`datetime.now` with :attr:`UTC` instead.
902+
899903

900904
.. classmethod:: datetime.fromtimestamp(timestamp, tz=None)
901905

@@ -964,6 +968,10 @@ Other constructors, all class methods:
964968
:c:func:`gmtime` function. Raise :exc:`OSError` instead of
965969
:exc:`ValueError` on :c:func:`gmtime` failure.
966970

971+
.. deprecated:: 3.12
972+
973+
Use :meth:`datetime.fromtimestamp` with :attr:`UTC` instead.
974+
967975

968976
.. classmethod:: datetime.fromordinal(ordinal)
969977

Lib/datetime.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,6 +1801,13 @@ def fromtimestamp(cls, timestamp, tz=None):
18011801
@classmethod
18021802
def utcfromtimestamp(cls, t):
18031803
"""Construct a naive UTC datetime from a POSIX timestamp."""
1804+
import warnings
1805+
warnings.warn("datetime.utcfromtimestamp() is deprecated and scheduled "
1806+
"for removal in a future version. Use timezone-aware "
1807+
"objects to represent datetimes in UTC: "
1808+
"datetime.fromtimestamp(t, datetime.UTC).",
1809+
DeprecationWarning,
1810+
stacklevel=2)
18041811
return cls._fromtimestamp(t, True, None)
18051812

18061813
@classmethod
@@ -1812,8 +1819,15 @@ def now(cls, tz=None):
18121819
@classmethod
18131820
def utcnow(cls):
18141821
"Construct a UTC datetime from time.time()."
1822+
import warnings
1823+
warnings.warn("datetime.utcnow() is deprecated and scheduled for "
1824+
"removal in a future version. Instead, Use timezone-aware "
1825+
"objects to represent datetimes in UTC: "
1826+
"datetime.now(datetime.UTC).",
1827+
DeprecationWarning,
1828+
stacklevel=2)
18151829
t = _time.time()
1816-
return cls.utcfromtimestamp(t)
1830+
return cls._fromtimestamp(t, True, None)
18171831

18181832
@classmethod
18191833
def combine(cls, date, time, tzinfo=True):

Lib/email/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,13 @@ def formatdate(timeval=None, localtime=False, usegmt=False):
143143
# 2822 requires that day and month names be the English abbreviations.
144144
if timeval is None:
145145
timeval = time.time()
146-
if localtime or usegmt:
147-
dt = datetime.datetime.fromtimestamp(timeval, datetime.timezone.utc)
148-
else:
149-
dt = datetime.datetime.utcfromtimestamp(timeval)
146+
dt = datetime.datetime.fromtimestamp(timeval, datetime.timezone.utc)
147+
150148
if localtime:
151149
dt = dt.astimezone()
152150
usegmt = False
151+
elif not usegmt:
152+
dt = dt.replace(tzinfo=None)
153153
return format_datetime(dt, usegmt)
154154

155155
def format_datetime(dt, usegmt=False):

Lib/http/cookiejar.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ def time2isoz(t=None):
104104
105105
"""
106106
if t is None:
107-
dt = datetime.datetime.utcnow()
107+
dt = datetime.datetime.now(tz=datetime.UTC)
108108
else:
109-
dt = datetime.datetime.utcfromtimestamp(t)
109+
dt = datetime.datetime.fromtimestamp(t, tz=datetime.UTC)
110110
return "%04d-%02d-%02d %02d:%02d:%02dZ" % (
111111
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
112112

@@ -122,9 +122,9 @@ def time2netscape(t=None):
122122
123123
"""
124124
if t is None:
125-
dt = datetime.datetime.utcnow()
125+
dt = datetime.datetime.now(tz=datetime.UTC)
126126
else:
127-
dt = datetime.datetime.utcfromtimestamp(t)
127+
dt = datetime.datetime.fromtimestamp(t, tz=datetime.UTC)
128128
return "%s, %02d-%s-%04d %02d:%02d:%02d GMT" % (
129129
DAYS[dt.weekday()], dt.day, MONTHS[dt.month-1],
130130
dt.year, dt.hour, dt.minute, dt.second)

Lib/test/datetimetester.py

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,7 +2437,8 @@ def test_utcfromtimestamp(self):
24372437

24382438
ts = time.time()
24392439
expected = time.gmtime(ts)
2440-
got = self.theclass.utcfromtimestamp(ts)
2440+
with self.assertWarns(DeprecationWarning):
2441+
got = self.theclass.utcfromtimestamp(ts)
24412442
self.verify_field_equality(expected, got)
24422443

24432444
# Run with US-style DST rules: DST begins 2 a.m. on second Sunday in
@@ -2483,8 +2484,12 @@ def test_timestamp_aware(self):
24832484

24842485
@support.run_with_tz('MSK-03') # Something east of Greenwich
24852486
def test_microsecond_rounding(self):
2487+
def utcfromtimestamp(*args, **kwargs):
2488+
with self.assertWarns(DeprecationWarning):
2489+
return self.theclass.utcfromtimestamp(*args, **kwargs)
2490+
24862491
for fts in [self.theclass.fromtimestamp,
2487-
self.theclass.utcfromtimestamp]:
2492+
utcfromtimestamp]:
24882493
zero = fts(0)
24892494
self.assertEqual(zero.second, 0)
24902495
self.assertEqual(zero.microsecond, 0)
@@ -2581,10 +2586,11 @@ def test_fromtimestamp_limits(self):
25812586
self.theclass.fromtimestamp(ts)
25822587

25832588
def test_utcfromtimestamp_limits(self):
2584-
try:
2585-
self.theclass.utcfromtimestamp(-2**32 - 1)
2586-
except (OSError, OverflowError):
2587-
self.skipTest("Test not valid on this platform")
2589+
with self.assertWarns(DeprecationWarning):
2590+
try:
2591+
self.theclass.utcfromtimestamp(-2**32 - 1)
2592+
except (OSError, OverflowError):
2593+
self.skipTest("Test not valid on this platform")
25882594

25892595
min_dt = self.theclass.min.replace(tzinfo=timezone.utc)
25902596
min_ts = min_dt.timestamp()
@@ -2597,10 +2603,11 @@ def test_utcfromtimestamp_limits(self):
25972603
("maximum", max_ts, max_dt.replace(tzinfo=None)),
25982604
]:
25992605
with self.subTest(test_name, ts=ts, expected=expected):
2600-
try:
2601-
actual = self.theclass.utcfromtimestamp(ts)
2602-
except (OSError, OverflowError) as exc:
2603-
self.skipTest(str(exc))
2606+
with self.assertWarns(DeprecationWarning):
2607+
try:
2608+
actual = self.theclass.utcfromtimestamp(ts)
2609+
except (OSError, OverflowError) as exc:
2610+
self.skipTest(str(exc))
26042611

26052612
self.assertEqual(actual, expected)
26062613

@@ -2645,7 +2652,8 @@ def test_negative_float_fromtimestamp(self):
26452652

26462653
@unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps")
26472654
def test_negative_float_utcfromtimestamp(self):
2648-
d = self.theclass.utcfromtimestamp(-1.05)
2655+
with self.assertWarns(DeprecationWarning):
2656+
d = self.theclass.utcfromtimestamp(-1.05)
26492657
self.assertEqual(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000))
26502658

26512659
def test_utcnow(self):
@@ -2655,8 +2663,11 @@ def test_utcnow(self):
26552663
# a second of each other.
26562664
tolerance = timedelta(seconds=1)
26572665
for dummy in range(3):
2658-
from_now = self.theclass.utcnow()
2659-
from_timestamp = self.theclass.utcfromtimestamp(time.time())
2666+
with self.assertWarns(DeprecationWarning):
2667+
from_now = self.theclass.utcnow()
2668+
2669+
with self.assertWarns(DeprecationWarning):
2670+
from_timestamp = self.theclass.utcfromtimestamp(time.time())
26602671
if abs(from_timestamp - from_now) <= tolerance:
26612672
break
26622673
# Else try again a few times.
@@ -2956,7 +2967,11 @@ def __new__(cls, *args, **kwargs):
29562967
constr_name=constr_name):
29572968
constructor = getattr(base_obj, constr_name)
29582969

2959-
dt = constructor(*constr_args)
2970+
if constr_name == "utcfromtimestamp":
2971+
with self.assertWarns(DeprecationWarning):
2972+
dt = constructor(*constr_args)
2973+
else:
2974+
dt = constructor(*constr_args)
29602975

29612976
# Test that it creates the right subclass
29622977
self.assertIsInstance(dt, DateTimeSubclass)
@@ -2986,7 +3001,11 @@ def __new__(cls, *args, **kwargs):
29863001
for name, meth_name, kwargs in test_cases:
29873002
with self.subTest(name):
29883003
constr = getattr(DateTimeSubclass, meth_name)
2989-
dt = constr(**kwargs)
3004+
if constr == "utcnow":
3005+
with self.assertWarns(DeprecationWarning):
3006+
dt = constr(**kwargs)
3007+
else:
3008+
dt = constr(**kwargs)
29903009

29913010
self.assertIsInstance(dt, DateTimeSubclass)
29923011
self.assertEqual(dt.extra, 7)
@@ -4642,7 +4661,8 @@ def test_tzinfo_now(self):
46424661
for dummy in range(3):
46434662
now = datetime.now(weirdtz)
46444663
self.assertIs(now.tzinfo, weirdtz)
4645-
utcnow = datetime.utcnow().replace(tzinfo=utc)
4664+
with self.assertWarns(DeprecationWarning):
4665+
utcnow = datetime.utcnow().replace(tzinfo=utc)
46464666
now2 = utcnow.astimezone(weirdtz)
46474667
if abs(now - now2) < timedelta(seconds=30):
46484668
break
@@ -4676,7 +4696,8 @@ def test_tzinfo_fromtimestamp(self):
46764696

46774697
# Try to make sure tz= actually does some conversion.
46784698
timestamp = 1000000000
4679-
utcdatetime = datetime.utcfromtimestamp(timestamp)
4699+
with self.assertWarns(DeprecationWarning):
4700+
utcdatetime = datetime.utcfromtimestamp(timestamp)
46804701
# In POSIX (epoch 1970), that's 2001-09-09 01:46:40 UTC, give or take.
46814702
# But on some flavor of Mac, it's nowhere near that. So we can't have
46824703
# any idea here what time that actually is, we can only test that
@@ -4690,7 +4711,8 @@ def test_tzinfo_fromtimestamp(self):
46904711
def test_tzinfo_utcnow(self):
46914712
meth = self.theclass.utcnow
46924713
# Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
4693-
base = meth()
4714+
with self.assertWarns(DeprecationWarning):
4715+
base = meth()
46944716
# Try with and without naming the keyword; for whatever reason,
46954717
# utcnow() doesn't accept a tzinfo argument.
46964718
off42 = FixedOffset(42, "42")
@@ -4702,7 +4724,8 @@ def test_tzinfo_utcfromtimestamp(self):
47024724
meth = self.theclass.utcfromtimestamp
47034725
ts = time.time()
47044726
# Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
4705-
base = meth(ts)
4727+
with self.assertWarns(DeprecationWarning):
4728+
base = meth(ts)
47064729
# Try with and without naming the keyword; for whatever reason,
47074730
# utcfromtimestamp() doesn't accept a tzinfo argument.
47084731
off42 = FixedOffset(42, "42")
@@ -5309,7 +5332,7 @@ def dst(self, dt):
53095332

53105333
def test_fromutc(self):
53115334
self.assertRaises(TypeError, Eastern.fromutc) # not enough args
5312-
now = datetime.utcnow().replace(tzinfo=utc_real)
5335+
now = datetime.now(tz=utc_real)
53135336
self.assertRaises(ValueError, Eastern.fromutc, now) # wrong tzinfo
53145337
now = now.replace(tzinfo=Eastern) # insert correct tzinfo
53155338
enow = Eastern.fromutc(now) # doesn't blow up
@@ -5411,9 +5434,11 @@ def test_bug_1028306(self):
54115434
self.assertEqual(datetime_sc, as_datetime)
54125435

54135436
def test_extra_attributes(self):
5437+
with self.assertWarns(DeprecationWarning):
5438+
utcnow = datetime.utcnow()
54145439
for x in [date.today(),
54155440
time(),
5416-
datetime.utcnow(),
5441+
utcnow,
54175442
timedelta(),
54185443
tzinfo(),
54195444
timezone(timedelta())]:
@@ -6073,6 +6098,7 @@ def stats(cls, start_year=1):
60736098
def transitions(self):
60746099
for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)):
60756100
shift = ti[0] - prev_ti[0]
6101+
# TODO: Remove this use of utcfromtimestamp
60766102
yield datetime.utcfromtimestamp(t), shift
60776103

60786104
def nondst_folds(self):

Lib/test/support/testresult.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ def __init__(self, stream, descriptions, verbosity):
1818
self.buffer = True
1919
if self.USE_XML:
2020
from xml.etree import ElementTree as ET
21-
from datetime import datetime
21+
from datetime import datetime, UTC
2222
self.__ET = ET
2323
self.__suite = ET.Element('testsuite')
24-
self.__suite.set('start', datetime.utcnow().isoformat(' '))
24+
self.__suite.set('start',
25+
datetime.now(UTC)
26+
.replace(tzinfo=None)
27+
.isoformat(' '))
2528
self.__e = None
2629
self.__start_time = None
2730

Lib/test/test_plistlib.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ def test_large_timestamp(self):
925925
# Issue #26709: 32-bit timestamp out of range
926926
for ts in -2**31-1, 2**31:
927927
with self.subTest(ts=ts):
928-
d = (datetime.datetime.utcfromtimestamp(0) +
928+
d = (datetime.datetime(1970, 1, 1, 0, 0) +
929929
datetime.timedelta(seconds=ts))
930930
data = plistlib.dumps(d, fmt=plistlib.FMT_BINARY)
931931
self.assertEqual(plistlib.loads(data), d)

Lib/test/test_sqlite3/test_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ def test_sqlite_timestamp(self):
517517
self.assertEqual(ts, ts2)
518518

519519
def test_sql_timestamp(self):
520-
now = datetime.datetime.utcnow()
520+
now = datetime.datetime.now(tz=datetime.UTC)
521521
self.cur.execute("insert into test(ts) values (current_timestamp)")
522522
self.cur.execute("select ts from test")
523523
with self.assertWarnsRegex(DeprecationWarning, "converter"):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Deprecated :meth:`datetime.datetime.utcnow` and
2+
:meth:`datetime.datetime.utcfromtimestamp`. (Patch by Paul Ganssle)

Modules/_datetimemodule.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5144,6 +5144,13 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
51445144
static PyObject *
51455145
datetime_utcnow(PyObject *cls, PyObject *dummy)
51465146
{
5147+
PyErr_WarnEx(
5148+
PyExc_DeprecationWarning,
5149+
"datetime.utcnow() is deprecated and scheduled for removal in a future "
5150+
"version. Use timezone-aware objects to represent datetimes in UTC: "
5151+
"datetime.now(datetime.UTC).",
5152+
2
5153+
);
51475154
return datetime_best_possible(cls, _PyTime_gmtime, Py_None);
51485155
}
51495156

@@ -5180,6 +5187,13 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
51805187
static PyObject *
51815188
datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
51825189
{
5190+
PyErr_WarnEx(
5191+
PyExc_DeprecationWarning,
5192+
"datetime.utcfromtimestamp() is deprecated and scheduled for removal "
5193+
"in a future version. Use timezone-aware objects to represent "
5194+
"datetimes in UTC: datetime.now(datetime.UTC).",
5195+
2
5196+
);
51835197
PyObject *timestamp;
51845198
PyObject *result = NULL;
51855199

0 commit comments

Comments
 (0)