Skip to content

Commit bd89085

Browse files
Replace deprecated utcnow() and utcfromtimestamp() with timezone-aware equivalents (#967)
* Replace deprecated utcnow() and utcfromtimestamp() with timezone-aware equivalents Python 3.12 deprecated `datetime.utcnow()` and `datetime.utcfromtimestamp()`; both are scheduled for removal in a future Python version. This change replaces all internal uses with the non-deprecated, behavior-preserving equivalents: - `datetime.now(timezone.utc).replace(tzinfo=None)` for `datetime.utcnow()` - `datetime.fromtimestamp(t, tz=timezone.utc).replace(tzinfo=None)` for `datetime.utcfromtimestamp(t)` This eliminates 4 DeprecationWarnings from the test suite without changing any public behavior. The existing test suite continues to pass (1830 passed) with `-W error::DeprecationWarning`. * Add regression coverage for utcfromtimestamp behavior The existing test_utcfromtimestamp only exercises t=0, which incidentally gives back a value where every field happens to be zero. That makes it weak against regressions in field handling, microsecond preservation, and return-type semantics. Add three focused tests that lock those down without changing or removing any existing behavior: - test_utcfromtimestamp_known_value: asserts that a specific non-zero Unix timestamp (1577836800 = 2020-01-01T00:00:00 UTC) produces the expected year/month/day/hour/minute/second/microsecond values. - test_utcfromtimestamp_preserves_microseconds: asserts that a fractional timestamp passes its microseconds through to the resulting DateTime, protecting the precision contract of the method. - test_utcfromtimestamp_returns_naive_pendulum_datetime: asserts that the returned object is a pendulum.DateTime instance and is naive (tzinfo is None), which is the documented behavior the method has had before and after the deprecation cleanup in this PR. All three tests are additions; no existing test is modified or removed. Full suite: 1833 passed, 5 skipped (was 1830 passed) with -W error::DeprecationWarning.
1 parent 6247ff9 commit bd89085

3 files changed

Lines changed: 39 additions & 4 deletions

File tree

‎src/pendulum/datetime.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,12 @@ def fromtimestamp(cls, t: float, tz: datetime.tzinfo | None = None) -> Self:
12571257

12581258
@classmethod
12591259
def utcfromtimestamp(cls, t: float) -> Self:
1260-
return cls.instance(datetime.datetime.utcfromtimestamp(t), tz=None)
1260+
return cls.instance(
1261+
datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc).replace(
1262+
tzinfo=None
1263+
),
1264+
tz=None,
1265+
)
12611266

12621267
@classmethod
12631268
def fromordinal(cls, n: int) -> Self:

‎tests/datetime/test_behavior.py‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from datetime import date
88
from datetime import datetime
99
from datetime import time
10+
from datetime import timezone as datetime_timezone
1011

1112
import pytest
1213

@@ -102,11 +103,39 @@ def test_fromtimestamp():
102103

103104
def test_utcfromtimestamp():
104105
p = pendulum.DateTime.utcfromtimestamp(0)
105-
dt = datetime.utcfromtimestamp(0)
106+
dt = datetime.fromtimestamp(0, tz=datetime_timezone.utc).replace(tzinfo=None)
106107

107108
assert p == dt
108109

109110

111+
def test_utcfromtimestamp_known_value():
112+
p = pendulum.DateTime.utcfromtimestamp(1577836800)
113+
114+
assert p.year == 2020
115+
assert p.month == 1
116+
assert p.day == 1
117+
assert p.hour == 0
118+
assert p.minute == 0
119+
assert p.second == 0
120+
assert p.microsecond == 0
121+
122+
123+
def test_utcfromtimestamp_preserves_microseconds():
124+
p = pendulum.DateTime.utcfromtimestamp(1577836800.123456)
125+
126+
assert p.year == 2020
127+
assert p.month == 1
128+
assert p.day == 1
129+
assert p.microsecond == 123456
130+
131+
132+
def test_utcfromtimestamp_returns_naive_pendulum_datetime():
133+
p = pendulum.DateTime.utcfromtimestamp(1577836800)
134+
135+
assert isinstance(p, pendulum.DateTime)
136+
assert p.tzinfo is None
137+
138+
110139
def test_fromordinal():
111140
assert datetime.fromordinal(730120) == pendulum.DateTime.fromordinal(730120)
112141

‎tests/datetime/test_construct.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44

55
from datetime import datetime
6+
from datetime import timezone as datetime_timezone
67

78
import pytest
89

@@ -41,7 +42,7 @@ def test_creates_an_instance_default_to_utcnow():
4142
def test_setting_timezone():
4243
tz = "Australia/Brisbane"
4344
dtz = timezone(tz)
44-
dt = datetime.utcnow()
45+
dt = datetime.now(datetime_timezone.utc).replace(tzinfo=None)
4546
offset = dtz.convert(dt).utcoffset().total_seconds() / 3600
4647

4748
p = pendulum.datetime(dt.year, dt.month, dt.day, tz=dtz)
@@ -52,7 +53,7 @@ def test_setting_timezone():
5253
def test_setting_timezone_with_string():
5354
tz = "Australia/Brisbane"
5455
dtz = timezone(tz)
55-
dt = datetime.utcnow()
56+
dt = datetime.now(datetime_timezone.utc).replace(tzinfo=None)
5657
offset = dtz.convert(dt).utcoffset().total_seconds() / 3600
5758

5859
p = pendulum.datetime(dt.year, dt.month, dt.day, tz=tz)

0 commit comments

Comments
 (0)