Skip to content

ENH: Add Series.dt.total_seconds GH #10817 #10939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/source/whatsnew/v0.17.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ Other enhancements

- ``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.

- ``pd.Series`` of type ``timedelta64`` has new method ``.dt.total_seconds()`` returning the duration of the timedelta in seconds (:issue: `10817`)

- ``pd.Timedelta.total_seconds()`` now returns Timedelta duration to ns precision (previously microsecond precision) (:issue: `10939`)

- ``.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`)

- ``regex`` argument to ``DataFrame.filter`` now handles numeric column names instead of raising ``ValueError`` (:issue:`10384`).
Expand Down
6 changes: 5 additions & 1 deletion pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def test_dt_namespace_accessor(self):
'is_quarter_end', 'is_year_start', 'is_year_end', 'tz']
ok_for_dt_methods = ['to_period','to_pydatetime','tz_localize','tz_convert', 'normalize', 'strftime']
ok_for_td = ['days','seconds','microseconds','nanoseconds']
ok_for_td_methods = ['components','to_pytimedelta']
ok_for_td_methods = ['components','to_pytimedelta','total_seconds']

def get_expected(s, name):
result = getattr(Index(s.values),prop)
Expand Down Expand Up @@ -157,6 +157,10 @@ def compare(s, name):
result = s.dt.to_pytimedelta()
self.assertIsInstance(result,np.ndarray)
self.assertTrue(result.dtype == object)

result = s.dt.total_seconds()
self.assertIsInstance(result,pd.Series)
self.assertTrue(result.dtype == 'float64')

freq_result = s.dt.freq
self.assertEqual(freq_result, TimedeltaIndex(s.values, freq='infer').freq)
Expand Down
2 changes: 1 addition & 1 deletion pandas/tseries/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def components(self):
accessors=TimedeltaIndex._datetimelike_ops,
typ='property')
TimedeltaProperties._add_delegate_accessors(delegate=TimedeltaIndex,
accessors=["to_pytimedelta"],
accessors=["to_pytimedelta", "total_seconds"],
typ='method')

class PeriodProperties(Properties):
Expand Down
4 changes: 4 additions & 0 deletions pandas/tseries/tdi.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@ def f(x):
result = result.astype('int64')
return result

def total_seconds(self):
""" Total duration of each element expressed in seconds. """
return self._maybe_mask_results(1e-9*self.asi8)

def to_pytimedelta(self):
"""
Return TimedeltaIndex as object ndarray of datetime.timedelta objects
Expand Down
31 changes: 31 additions & 0 deletions pandas/tseries/tests/test_timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
assert_almost_equal,
assert_index_equal,
ensure_clean)
from numpy.testing import assert_allclose
from pandas.tseries.offsets import Day, Second, Hour
import pandas.util.testing as tm
from numpy.random import rand, randn
Expand Down Expand Up @@ -945,6 +946,36 @@ def test_fields(self):
tm.assert_series_equal(s.dt.days,Series([1,np.nan],index=[0,1]))
tm.assert_series_equal(s.dt.seconds,Series([10*3600+11*60+12,np.nan],index=[0,1]))

def test_total_seconds(self):
# GH 10939
# test index
rng = timedelta_range('1 days, 10:11:12.100123456', periods=2, freq='s')
expt = [1*86400+10*3600+11*60+12+100123456./1e9,1*86400+10*3600+11*60+13+100123456./1e9]
assert_allclose(rng.total_seconds(), expt, atol=1e-10, rtol=0)

# test Series
s = Series(rng)
s_expt = Series(expt,index=[0,1])
tm.assert_series_equal(s.dt.total_seconds(),s_expt)

# with nat
s[1] = np.nan
s_expt = Series([1*86400+10*3600+11*60+12+100123456./1e9,np.nan],index=[0,1])
tm.assert_series_equal(s.dt.total_seconds(),s_expt)

# with both nat
s = Series([np.nan,np.nan], dtype='timedelta64[ns]')
tm.assert_series_equal(s.dt.total_seconds(),Series([np.nan,np.nan],index=[0,1]))

def test_total_seconds_scalar(self):
# GH 10939
rng = Timedelta('1 days, 10:11:12.100123456')
expt = 1*86400+10*3600+11*60+12+100123456./1e9
assert_allclose(rng.total_seconds(), expt, atol=1e-10, rtol=0)

rng = Timedelta(np.nan)
self.assertTrue(np.isnan(rng.total_seconds()))

def test_components(self):
rng = timedelta_range('1 days, 10:11:12', periods=2, freq='s')
rng.components
Expand Down
12 changes: 11 additions & 1 deletion pandas/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ class NaTType(_NaT):

def __reduce__(self):
return (__nat_unpickle, (None, ))

def total_seconds(self):
# GH 10939
return np.nan


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

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

_nan_methods = ['weekday', 'isoweekday']
_nan_methods = ['weekday', 'isoweekday', 'total_seconds']

_implemented_methods = ['to_datetime64']
_implemented_methods.extend(_nat_methods)
Expand Down Expand Up @@ -2412,6 +2416,12 @@ class Timedelta(_Timedelta):
"""
self._ensure_components()
return self._ns

def total_seconds(self):
"""
Total duration of timedelta in seconds (to ns precision)
"""
return 1e-9*self.value

def __setstate__(self, state):
(value) = state
Expand Down