Skip to content

Commit 582eb17

Browse files
committed
Merge pull request pandas-dev#10939 from sjdenny/series_total_seconds
ENH: Add Series.dt.total_seconds GH pandas-dev#10817
2 parents b420e84 + a165269 commit 582eb17

File tree

6 files changed

+56
-3
lines changed

6 files changed

+56
-3
lines changed

doc/source/whatsnew/v0.17.0.txt

+4
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ Other enhancements
183183

184184
- ``pandas.tseries.offsets`` larger than the ``Day`` offset can now be used with with ``Series`` for addition/subtraction (:issue:`10699`). See the :ref:`Documentation <timeseries.offsetseries>` for more details.
185185

186+
- ``pd.Series`` of type ``timedelta64`` has new method ``.dt.total_seconds()`` returning the duration of the timedelta in seconds (:issue: `10817`)
187+
188+
- ``pd.Timedelta.total_seconds()`` now returns Timedelta duration to ns precision (previously microsecond precision) (:issue: `10939`)
189+
186190
- ``.as_blocks`` will now take a ``copy`` optional argument to return a copy of the data, default is to copy (no change in behavior from prior versions), (:issue:`9607`)
187191

188192
- ``regex`` argument to ``DataFrame.filter`` now handles numeric column names instead of raising ``ValueError`` (:issue:`10384`).

pandas/tests/test_series.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def test_dt_namespace_accessor(self):
8989
'is_quarter_end', 'is_year_start', 'is_year_end', 'tz']
9090
ok_for_dt_methods = ['to_period','to_pydatetime','tz_localize','tz_convert', 'normalize', 'strftime']
9191
ok_for_td = ['days','seconds','microseconds','nanoseconds']
92-
ok_for_td_methods = ['components','to_pytimedelta']
92+
ok_for_td_methods = ['components','to_pytimedelta','total_seconds']
9393

9494
def get_expected(s, name):
9595
result = getattr(Index(s.values),prop)
@@ -157,6 +157,10 @@ def compare(s, name):
157157
result = s.dt.to_pytimedelta()
158158
self.assertIsInstance(result,np.ndarray)
159159
self.assertTrue(result.dtype == object)
160+
161+
result = s.dt.total_seconds()
162+
self.assertIsInstance(result,pd.Series)
163+
self.assertTrue(result.dtype == 'float64')
160164

161165
freq_result = s.dt.freq
162166
self.assertEqual(freq_result, TimedeltaIndex(s.values, freq='infer').freq)

pandas/tseries/common.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def components(self):
161161
accessors=TimedeltaIndex._datetimelike_ops,
162162
typ='property')
163163
TimedeltaProperties._add_delegate_accessors(delegate=TimedeltaIndex,
164-
accessors=["to_pytimedelta"],
164+
accessors=["to_pytimedelta", "total_seconds"],
165165
typ='method')
166166

167167
class PeriodProperties(Properties):

pandas/tseries/tdi.py

+4
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,10 @@ def f(x):
391391
result = result.astype('int64')
392392
return result
393393

394+
def total_seconds(self):
395+
""" Total duration of each element expressed in seconds. """
396+
return self._maybe_mask_results(1e-9*self.asi8)
397+
394398
def to_pytimedelta(self):
395399
"""
396400
Return TimedeltaIndex as object ndarray of datetime.timedelta objects

pandas/tseries/tests/test_timedeltas.py

+31
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
assert_almost_equal,
2020
assert_index_equal,
2121
ensure_clean)
22+
from numpy.testing import assert_allclose
2223
from pandas.tseries.offsets import Day, Second, Hour
2324
import pandas.util.testing as tm
2425
from numpy.random import rand, randn
@@ -953,6 +954,36 @@ def test_fields(self):
953954
tm.assert_series_equal(s.dt.days,Series([1,np.nan],index=[0,1]))
954955
tm.assert_series_equal(s.dt.seconds,Series([10*3600+11*60+12,np.nan],index=[0,1]))
955956

957+
def test_total_seconds(self):
958+
# GH 10939
959+
# test index
960+
rng = timedelta_range('1 days, 10:11:12.100123456', periods=2, freq='s')
961+
expt = [1*86400+10*3600+11*60+12+100123456./1e9,1*86400+10*3600+11*60+13+100123456./1e9]
962+
assert_allclose(rng.total_seconds(), expt, atol=1e-10, rtol=0)
963+
964+
# test Series
965+
s = Series(rng)
966+
s_expt = Series(expt,index=[0,1])
967+
tm.assert_series_equal(s.dt.total_seconds(),s_expt)
968+
969+
# with nat
970+
s[1] = np.nan
971+
s_expt = Series([1*86400+10*3600+11*60+12+100123456./1e9,np.nan],index=[0,1])
972+
tm.assert_series_equal(s.dt.total_seconds(),s_expt)
973+
974+
# with both nat
975+
s = Series([np.nan,np.nan], dtype='timedelta64[ns]')
976+
tm.assert_series_equal(s.dt.total_seconds(),Series([np.nan,np.nan],index=[0,1]))
977+
978+
def test_total_seconds_scalar(self):
979+
# GH 10939
980+
rng = Timedelta('1 days, 10:11:12.100123456')
981+
expt = 1*86400+10*3600+11*60+12+100123456./1e9
982+
assert_allclose(rng.total_seconds(), expt, atol=1e-10, rtol=0)
983+
984+
rng = Timedelta(np.nan)
985+
self.assertTrue(np.isnan(rng.total_seconds()))
986+
956987
def test_components(self):
957988
rng = timedelta_range('1 days, 10:11:12', periods=2, freq='s')
958989
rng.components

pandas/tslib.pyx

+11-1
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ class NaTType(_NaT):
642642

643643
def __reduce__(self):
644644
return (__nat_unpickle, (None, ))
645+
646+
def total_seconds(self):
647+
# GH 10939
648+
return np.nan
645649

646650

647651
fields = ['year', 'quarter', 'month', 'day', 'hour',
@@ -673,7 +677,7 @@ def _make_nan_func(func_name):
673677

674678
_nat_methods = ['date', 'now', 'replace', 'to_datetime', 'today']
675679

676-
_nan_methods = ['weekday', 'isoweekday']
680+
_nan_methods = ['weekday', 'isoweekday', 'total_seconds']
677681

678682
_implemented_methods = ['to_datetime64']
679683
_implemented_methods.extend(_nat_methods)
@@ -2411,6 +2415,12 @@ class Timedelta(_Timedelta):
24112415
"""
24122416
self._ensure_components()
24132417
return self._ns
2418+
2419+
def total_seconds(self):
2420+
"""
2421+
Total duration of timedelta in seconds (to ns precision)
2422+
"""
2423+
return 1e-9*self.value
24142424

24152425
def __setstate__(self, state):
24162426
(value) = state

0 commit comments

Comments
 (0)