Skip to content

Commit 6297494

Browse files
committed
Use explicitly declared types with branching
1 parent 187b02f commit 6297494

File tree

2 files changed

+35
-22
lines changed

2 files changed

+35
-22
lines changed

pandas/_libs/tslibs/conversion.pyx

+24-17
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ cdef int64_t cast_from_unit(
185185
int64_t m
186186
int p
187187
NPY_DATETIMEUNIT in_reso
188+
int64_t frac_int64
189+
float64_t frac_float64
188190

189191
if unit in ["Y", "M"]:
190192
if is_float_object(ts) and not ts.is_integer():
@@ -220,24 +222,29 @@ cdef int64_t cast_from_unit(
220222
f"cannot convert input {ts} with the unit '{unit}'"
221223
) from err
222224

223-
# In the event that ts itself is already an integer type, cast it to a
224-
# 64-bit integer to ensure that frac will also be a 64-bit integer after
225-
# type promotion changes in NEP 50. If this is not done, for example,
226-
# np.int32 values for ts can lead to np.int32 values for frac, which can
227-
# raise unexpected overflow errors downstream (GH 56996).
225+
# To maintain consistency across changes in NEP 50, handle the integer and
226+
# float cases separately, using frac variables with explicitly declared
227+
# types. See GH 56996 and 57984 for more discussion.
228228
if isinstance(ts, np.integer):
229-
ts = <int64_t>ts
230-
231-
frac = ts - base
232-
if p:
233-
frac = round(frac, p)
234-
235-
try:
236-
return <int64_t>(base * m) + <int64_t>(frac * m)
237-
except OverflowError as err:
238-
raise OutOfBoundsDatetime(
239-
f"cannot convert input {ts} with the unit '{unit}'"
240-
) from err
229+
frac_int64 = ts - base
230+
if p:
231+
frac_int64 = round(frac_int64, p)
232+
try:
233+
return <int64_t>(base * m) + <int64_t>(frac_int64 * m)
234+
except OverflowError as err:
235+
raise OutOfBoundsDatetime(
236+
f"cannot convert input {ts} with the unit '{unit}'"
237+
) from err
238+
else:
239+
frac_float64 = ts - base
240+
if p:
241+
frac_float64 = round(frac_float64, p)
242+
try:
243+
return <int64_t>(base * m) + <int64_t>(frac_float64 * m)
244+
except OverflowError as err:
245+
raise OutOfBoundsDatetime(
246+
f"cannot convert input {ts} with the unit '{unit}'"
247+
) from err
241248

242249

243250
cdef (int64_t, int) precision_from_unit(

pandas/tests/tools/test_to_timedelta.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -284,12 +284,18 @@ def test_to_timedelta_fraction(self):
284284
expected = pd.Timedelta("0 days 00:19:59.999999998")
285285
assert result == expected
286286

287-
@pytest.mark.parametrize("dtype", [np.int32, np.uint32])
288-
def test_to_timedelta_scalar_integer(self, dtype):
287+
@pytest.mark.parametrize(
288+
("dtype", "value", "expected"),
289+
[
290+
(np.int32, 1, "1 days 00:00:00"),
291+
(np.uint32, 1, "1 days 00:00:00"),
292+
(np.float32, 1.1, "1 days 02:24:00.002059940"),
293+
],
294+
)
295+
def test_to_timedelta_following_nep_50(self, dtype, value, expected):
289296
# GH 56996
290-
result = to_timedelta(dtype(1), "D")
291-
expected = pd.Timedelta("1 days 00:00:00")
292-
assert result == expected
297+
result = to_timedelta(dtype(value), "D")
298+
assert result == pd.Timedelta(expected)
293299

294300

295301
def test_from_numeric_arrow_dtype(any_numeric_ea_dtype):

0 commit comments

Comments
 (0)