Skip to content

Commit 428f33c

Browse files
authored
BUG: Series[td64].sum() wrong on empty series, closes #37151 (#37394)
1 parent c182d21 commit 428f33c

File tree

4 files changed

+33
-12
lines changed

4 files changed

+33
-12
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ Datetimelike
374374
- Bug in :class:`DatetimeIndex.shift` incorrectly raising when shifting empty indexes (:issue:`14811`)
375375
- :class:`Timestamp` and :class:`DatetimeIndex` comparisons between timezone-aware and timezone-naive objects now follow the standard library ``datetime`` behavior, returning ``True``/``False`` for ``!=``/``==`` and raising for inequality comparisons (:issue:`28507`)
376376
- Bug in :meth:`DatetimeIndex.equals` and :meth:`TimedeltaIndex.equals` incorrectly considering ``int64`` indexes as equal (:issue:`36744`)
377+
- Bug in :meth:`TimedeltaIndex.sum` and :meth:`Series.sum` with ``timedelta64`` dtype on an empty index or series returning ``NaT`` instead of ``Timedelta(0)`` (:issue:`31751`)
377378

378379
Timedelta
379380
^^^^^^^^^

pandas/core/arrays/timedeltas.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -381,14 +381,12 @@ def sum(
381381
nv.validate_sum(
382382
(), dict(dtype=dtype, out=out, keepdims=keepdims, initial=initial)
383383
)
384-
if not self.size and (self.ndim == 1 or axis is None):
385-
return NaT
386384

387385
result = nanops.nansum(
388-
self._data, axis=axis, skipna=skipna, min_count=min_count
386+
self._ndarray, axis=axis, skipna=skipna, min_count=min_count
389387
)
390-
if is_scalar(result):
391-
return Timedelta(result)
388+
if axis is None or self.ndim == 1:
389+
return self._box_func(result)
392390
return self._from_backing_data(result)
393391

394392
def std(
@@ -403,13 +401,11 @@ def std(
403401
nv.validate_stat_ddof_func(
404402
(), dict(dtype=dtype, out=out, keepdims=keepdims), fname="std"
405403
)
406-
if not len(self):
407-
return NaT
408-
if not skipna and self._hasnans:
409-
return NaT
410404

411-
result = nanops.nanstd(self._data, axis=axis, skipna=skipna, ddof=ddof)
412-
return Timedelta(result)
405+
result = nanops.nanstd(self._ndarray, axis=axis, skipna=skipna, ddof=ddof)
406+
if axis is None or self.ndim == 1:
407+
return self._box_func(result)
408+
return self._from_backing_data(result)
413409

414410
# ----------------------------------------------------------------
415411
# Rendering Methods

pandas/tests/arrays/test_timedeltas.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import pytest
33

44
import pandas as pd
5+
from pandas import Timedelta
56
import pandas._testing as tm
67
from pandas.core import nanops
78
from pandas.core.arrays import TimedeltaArray
@@ -176,7 +177,7 @@ def test_neg_freq(self):
176177

177178

178179
class TestReductions:
179-
@pytest.mark.parametrize("name", ["sum", "std", "min", "max", "median"])
180+
@pytest.mark.parametrize("name", ["std", "min", "max", "median"])
180181
@pytest.mark.parametrize("skipna", [True, False])
181182
def test_reductions_empty(self, name, skipna):
182183
tdi = pd.TimedeltaIndex([])
@@ -188,6 +189,19 @@ def test_reductions_empty(self, name, skipna):
188189
result = getattr(arr, name)(skipna=skipna)
189190
assert result is pd.NaT
190191

192+
@pytest.mark.parametrize("skipna", [True, False])
193+
def test_sum_empty(self, skipna):
194+
tdi = pd.TimedeltaIndex([])
195+
arr = tdi.array
196+
197+
result = tdi.sum(skipna=skipna)
198+
assert isinstance(result, Timedelta)
199+
assert result == Timedelta(0)
200+
201+
result = arr.sum(skipna=skipna)
202+
assert isinstance(result, Timedelta)
203+
assert result == Timedelta(0)
204+
191205
def test_min_max(self):
192206
arr = TimedeltaArray._from_sequence(["3H", "3H", "NaT", "2H", "5H", "4H"])
193207

pandas/tests/series/test_reductions.py

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ def test_reductions_td64_with_nat():
1515
assert ser.max() == exp
1616

1717

18+
@pytest.mark.parametrize("skipna", [True, False])
19+
def test_td64_sum_empty(skipna):
20+
# GH#37151
21+
ser = Series([], dtype="timedelta64[ns]")
22+
23+
result = ser.sum(skipna=skipna)
24+
assert isinstance(result, pd.Timedelta)
25+
assert result == pd.Timedelta(0)
26+
27+
1828
def test_td64_summation_overflow():
1929
# GH#9442
2030
ser = Series(pd.date_range("20130101", periods=100000, freq="H"))

0 commit comments

Comments
 (0)