Skip to content

Commit

Permalink
Merge pull request pandas-dev#10939 from sjdenny/series_total_seconds
Browse files Browse the repository at this point in the history
ENH: Add Series.dt.total_seconds GH pandas-dev#10817
  • Loading branch information
jreback committed Sep 2, 2015
2 parents b420e84 + a165269 commit 582eb17
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 3 deletions.
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 @@ -183,6 +183,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 @@ -953,6 +954,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 @@ -2411,6 +2415,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

0 comments on commit 582eb17

Please sign in to comment.