Skip to content

Commit f2c8715

Browse files
authored
BUG: round with non-nanosecond raising OverflowError (#56158)
* BUG: round with non-nanosecond raising OverflowError * GH ref * woops
1 parent 9ac1562 commit f2c8715

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ Datetimelike
453453
- Bug in :meth:`DatetimeIndex.union` returning object dtype for tz-aware indexes with the same timezone but different units (:issue:`55238`)
454454
- Bug in :meth:`Index.is_monotonic_increasing` and :meth:`Index.is_monotonic_decreasing` always caching :meth:`Index.is_unique` as ``True`` when first value in index is ``NaT`` (:issue:`55755`)
455455
- Bug in :meth:`Index.view` to a datetime64 dtype with non-supported resolution incorrectly raising (:issue:`55710`)
456+
- Bug in :meth:`Series.dt.round` with non-nanosecond resolution and ``NaT`` entries incorrectly raising ``OverflowError`` (:issue:`56158`)
456457
- Bug in :meth:`Tick.delta` with very large ticks raising ``OverflowError`` instead of ``OutOfBoundsTimedelta`` (:issue:`55503`)
457458
- Bug in ``.astype`` converting from a higher-resolution ``datetime64`` dtype to a lower-resolution ``datetime64`` dtype (e.g. ``datetime64[us]->datetim64[ms]``) silently overflowing with values near the lower implementation bound (:issue:`55979`)
458459
- Bug in adding or subtracting a :class:`Week` offset to a ``datetime64`` :class:`Series`, :class:`Index`, or :class:`DataFrame` column with non-nanosecond resolution returning incorrect results (:issue:`55583`)

pandas/_libs/tslibs/fields.pyx

+25-1
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,31 @@ cdef ndarray[int64_t] _ceil_int64(const int64_t[:] values, int64_t unit):
746746

747747

748748
cdef ndarray[int64_t] _rounddown_int64(values, int64_t unit):
749-
return _ceil_int64(values - unit // 2, unit)
749+
cdef:
750+
Py_ssize_t i, n = len(values)
751+
ndarray[int64_t] result = np.empty(n, dtype="i8")
752+
int64_t res, value, remainder, half
753+
754+
half = unit // 2
755+
756+
with cython.overflowcheck(True):
757+
for i in range(n):
758+
value = values[i]
759+
760+
if value == NPY_NAT:
761+
res = NPY_NAT
762+
else:
763+
# This adjustment is the only difference between rounddown_int64
764+
# and _ceil_int64
765+
value = value - half
766+
remainder = value % unit
767+
if remainder == 0:
768+
res = value
769+
else:
770+
res = value + (unit - remainder)
771+
772+
result[i] = res
773+
return result
750774

751775

752776
cdef ndarray[int64_t] _roundup_int64(values, int64_t unit):

pandas/tests/series/methods/test_round.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ def test_round_builtin(self, any_float_dtype):
5656

5757
@pytest.mark.parametrize("method", ["round", "floor", "ceil"])
5858
@pytest.mark.parametrize("freq", ["s", "5s", "min", "5min", "h", "5h"])
59-
def test_round_nat(self, method, freq):
60-
# GH14940
61-
ser = Series([pd.NaT])
62-
expected = Series(pd.NaT)
59+
def test_round_nat(self, method, freq, unit):
60+
# GH14940, GH#56158
61+
ser = Series([pd.NaT], dtype=f"M8[{unit}]")
62+
expected = Series(pd.NaT, dtype=f"M8[{unit}]")
6363
round_method = getattr(ser.dt, method)
64-
tm.assert_series_equal(round_method(freq), expected)
64+
result = round_method(freq)
65+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)