GH-103944: Remove last use of utcfromtimestamp (#103995)

* Remove last use of `utcfromtimestamp`

This was a weirdly valid use of `utcfromtimestamp` in the sense that the "timestamps" in TZif files are not epoch times, but actually something more properly thought of as "number of seconds since 1970 in the local time zone", so even though we didn't want UTC time, `utcfromtimestamp` was still a good way to get the thing we wanted. Since we're deprecating `utcfromtimestamp`, it's just as valid to use `timedelta` arithmetic here.

We may be able to avoid the question entirely by switching these tests over to using `ZoneInfo` in the future.

* Fix a few missing DeprecationWarnings in tests

In one test, we simply turn off DeprecationWarning rather than asserting about it, because whether the error condition happens before or after the warning seems to differ between the Python and C versions.
This commit is contained in:
Paul Ganssle 2023-05-03 11:17:27 -04:00 committed by GitHub
parent 0fc58c66ba
commit 38dc3f28dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -2,18 +2,19 @@
See https://www.zope.dev/Members/fdrake/DateTimeWiki/TestCases See https://www.zope.dev/Members/fdrake/DateTimeWiki/TestCases
""" """
import io
import itertools
import bisect import bisect
import copy import copy
import decimal import decimal
import sys import io
import itertools
import os import os
import pickle import pickle
import random import random
import re import re
import struct import struct
import sys
import unittest import unittest
import warnings
from array import array from array import array
@ -51,11 +52,12 @@ pickle_choices = [(pickle, pickle, proto)
for proto in range(pickle.HIGHEST_PROTOCOL + 1)] for proto in range(pickle.HIGHEST_PROTOCOL + 1)]
assert len(pickle_choices) == pickle.HIGHEST_PROTOCOL + 1 assert len(pickle_choices) == pickle.HIGHEST_PROTOCOL + 1
EPOCH_NAIVE = datetime(1970, 1, 1, 0, 0) # For calculating transitions
# An arbitrary collection of objects of non-datetime types, for testing # An arbitrary collection of objects of non-datetime types, for testing
# mixed-type comparisons. # mixed-type comparisons.
OTHERSTUFF = (10, 34.5, "abc", {}, [], ()) OTHERSTUFF = (10, 34.5, "abc", {}, [], ())
# XXX Copied from test_float. # XXX Copied from test_float.
INF = float("inf") INF = float("inf")
NAN = float("nan") NAN = float("nan")
@ -2626,6 +2628,7 @@ class TestDateTime(TestDate):
for test_name, ts in test_cases: for test_name, ts in test_cases:
with self.subTest(test_name, ts=ts): with self.subTest(test_name, ts=ts):
with self.assertRaises((ValueError, OverflowError)): with self.assertRaises((ValueError, OverflowError)):
with self.assertWarns(DeprecationWarning):
# converting a Python int to C time_t can raise a # converting a Python int to C time_t can raise a
# OverflowError, especially on 32-bit platforms. # OverflowError, especially on 32-bit platforms.
self.theclass.utcfromtimestamp(ts) self.theclass.utcfromtimestamp(ts)
@ -2645,6 +2648,7 @@ class TestDateTime(TestDate):
# exempt such platforms (provided they return reasonable # exempt such platforms (provided they return reasonable
# results!). # results!).
for insane in -1e200, 1e200: for insane in -1e200, 1e200:
with self.assertWarns(DeprecationWarning):
self.assertRaises(OverflowError, self.theclass.utcfromtimestamp, self.assertRaises(OverflowError, self.theclass.utcfromtimestamp,
insane) insane)
@ -3005,7 +3009,7 @@ class TestDateTime(TestDate):
for name, meth_name, kwargs in test_cases: for name, meth_name, kwargs in test_cases:
with self.subTest(name): with self.subTest(name):
constr = getattr(DateTimeSubclass, meth_name) constr = getattr(DateTimeSubclass, meth_name)
if constr == "utcnow": if meth_name == "utcnow":
with self.assertWarns(DeprecationWarning): with self.assertWarns(DeprecationWarning):
dt = constr(**kwargs) dt = constr(**kwargs)
else: else:
@ -4733,6 +4737,8 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
# Try with and without naming the keyword; for whatever reason, # Try with and without naming the keyword; for whatever reason,
# utcfromtimestamp() doesn't accept a tzinfo argument. # utcfromtimestamp() doesn't accept a tzinfo argument.
off42 = FixedOffset(42, "42") off42 = FixedOffset(42, "42")
with warnings.catch_warnings(category=DeprecationWarning):
warnings.simplefilter("ignore", category=DeprecationWarning)
self.assertRaises(TypeError, meth, ts, off42) self.assertRaises(TypeError, meth, ts, off42)
self.assertRaises(TypeError, meth, ts, tzinfo=off42) self.assertRaises(TypeError, meth, ts, tzinfo=off42)
@ -6102,15 +6108,14 @@ class ZoneInfo(tzinfo):
def transitions(self): def transitions(self):
for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)): for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)):
shift = ti[0] - prev_ti[0] shift = ti[0] - prev_ti[0]
# TODO: Remove this use of utcfromtimestamp yield (EPOCH_NAIVE + timedelta(seconds=t)), shift
yield datetime.utcfromtimestamp(t), shift
def nondst_folds(self): def nondst_folds(self):
"""Find all folds with the same value of isdst on both sides of the transition.""" """Find all folds with the same value of isdst on both sides of the transition."""
for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)): for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)):
shift = ti[0] - prev_ti[0] shift = ti[0] - prev_ti[0]
if shift < ZERO and ti[1] == prev_ti[1]: if shift < ZERO and ti[1] == prev_ti[1]:
yield datetime.utcfromtimestamp(t), -shift, prev_ti[2], ti[2] yield _utcfromtimestamp(datetime, t,), -shift, prev_ti[2], ti[2]
@classmethod @classmethod
def print_all_nondst_folds(cls, same_abbr=False, start_year=1): def print_all_nondst_folds(cls, same_abbr=False, start_year=1):