Skip to content

Commit 0ba2eb0

Browse files
authored
Add missing DataArray.dt.total_seconds() method (#8435)
1 parent 15328b6 commit 0ba2eb0

File tree

4 files changed

+31
-0
lines changed

4 files changed

+31
-0
lines changed

doc/api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ Datetimelike properties
557557
DataArray.dt.seconds
558558
DataArray.dt.microseconds
559559
DataArray.dt.nanoseconds
560+
DataArray.dt.total_seconds
560561

561562
**Timedelta methods**:
562563

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ New Features
2424

2525
- Use `opt_einsum <https://optimized-einsum.readthedocs.io/en/stable/>`_ for :py:func:`xarray.dot` by default if installed.
2626
By `Deepak Cherian <https://github.com/dcherian>`_. (:issue:`7764`, :pull:`8373`).
27+
- Add ``DataArray.dt.total_seconds()`` method to match the Pandas API. (:pull:`8435`).
28+
By `Ben Mares <https://github.com/maresb>`_.
2729

2830
Breaking changes
2931
~~~~~~~~~~~~~~~~

xarray/core/accessor_dt.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ def _access_through_series(values, name):
7474
if name == "season":
7575
months = values_as_series.dt.month.values
7676
field_values = _season_from_months(months)
77+
elif name == "total_seconds":
78+
field_values = values_as_series.dt.total_seconds().values
7779
elif name == "isocalendar":
7880
# special NaT-handling can be removed when
7981
# https://github.com/pandas-dev/pandas/issues/54657 is resolved
@@ -574,6 +576,13 @@ class TimedeltaAccessor(TimeAccessor[T_DataArray]):
574576
43200, 64800])
575577
Coordinates:
576578
* time (time) timedelta64[ns] 1 days 00:00:00 ... 5 days 18:00:00
579+
>>> ts.dt.total_seconds()
580+
<xarray.DataArray 'total_seconds' (time: 20)>
581+
array([ 86400., 108000., 129600., 151200., 172800., 194400., 216000.,
582+
237600., 259200., 280800., 302400., 324000., 345600., 367200.,
583+
388800., 410400., 432000., 453600., 475200., 496800.])
584+
Coordinates:
585+
* time (time) timedelta64[ns] 1 days 00:00:00 ... 5 days 18:00:00
577586
"""
578587

579588
@property
@@ -596,6 +605,11 @@ def nanoseconds(self) -> T_DataArray:
596605
"""Number of nanoseconds (>= 0 and less than 1 microsecond) for each element"""
597606
return self._date_field("nanoseconds", np.int64)
598607

608+
# Not defined as a property in order to match the Pandas API
609+
def total_seconds(self) -> T_DataArray:
610+
"""Total duration of each element expressed in seconds."""
611+
return self._date_field("total_seconds", np.float64)
612+
599613

600614
class CombinedDatetimelikeAccessor(
601615
DatetimeAccessor[T_DataArray], TimedeltaAccessor[T_DataArray]

xarray/tests/test_accessor_dt.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import xarray as xr
88
from xarray.tests import (
9+
assert_allclose,
910
assert_array_equal,
1011
assert_chunks_equal,
1112
assert_equal,
@@ -100,6 +101,19 @@ def test_field_access(self, field) -> None:
100101
assert expected.dtype == actual.dtype
101102
assert_identical(expected, actual)
102103

104+
def test_total_seconds(self) -> None:
105+
# Subtract a value in the middle of the range to ensure that some values
106+
# are negative
107+
delta = self.data.time - np.datetime64("2000-01-03")
108+
actual = delta.dt.total_seconds()
109+
expected = xr.DataArray(
110+
np.arange(-48, 52, dtype=np.float64) * 3600,
111+
name="total_seconds",
112+
coords=[self.data.time],
113+
)
114+
# This works with assert_identical when pandas is >=1.5.0.
115+
assert_allclose(expected, actual)
116+
103117
@pytest.mark.parametrize(
104118
"field, pandas_field",
105119
[

0 commit comments

Comments
 (0)