diff --git a/doc/source/whatsnew/v0.16.0.txt b/doc/source/whatsnew/v0.16.0.txt index 2db455272363b..f12e5f1f9970e 100644 --- a/doc/source/whatsnew/v0.16.0.txt +++ b/doc/source/whatsnew/v0.16.0.txt @@ -99,6 +99,7 @@ Enhancements - Added time interval selection in get_data_yahoo (:issue:`9071`) - Added ``Series.str.slice_replace()``, which previously raised NotImplementedError (:issue:`8888`) - Added ``Timestamp.to_datetime64()`` to complement ``Timedelta.to_timedelta64()`` (:issue:`9255`) +- ``tseries.frequencies.to_offset()`` now accepts ``Timedelta`` as input (:issue:`9064`) Performance diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py index 54b29b1641309..0ec225d77f5e2 100644 --- a/pandas/tseries/frequencies.py +++ b/pandas/tseries/frequencies.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime,timedelta from pandas.compat import range, long, zip from pandas import compat import re @@ -12,6 +12,7 @@ import pandas.core.common as com import pandas.lib as lib import pandas.tslib as tslib +from pandas.tslib import Timedelta class FreqGroup(object): FR_ANN = 1000 @@ -276,9 +277,18 @@ def get_period_alias(offset_str): _legacy_reverse_map = dict((v, k) for k, v in reversed(sorted(compat.iteritems(_rule_aliases)))) +_name_to_offset_map = {'days': Day(1), + 'hours': Hour(1), + 'minutes': Minute(1), + 'seconds': Second(1), + 'milliseconds': Milli(1), + 'microseconds': Micro(1), + 'nanoseconds': Nano(1)} + def to_offset(freqstr): """ - Return DateOffset object from string representation + Return DateOffset object from string representation or + Timedelta object Examples -------- @@ -298,6 +308,23 @@ def to_offset(freqstr): name, stride = stride, name name, _ = _base_and_stride(name) delta = get_offset(name) * stride + + elif isinstance(freqstr, timedelta): + delta = None + freqstr = Timedelta(freqstr) + try: + for name in freqstr.components._fields: + offset = _name_to_offset_map[name] + stride = getattr(freqstr.components, name) + if stride != 0: + offset = stride * offset + if delta is None: + delta = offset + else: + delta = delta + offset + except Exception: + raise ValueError("Could not evaluate %s" % freqstr) + else: delta = None stride_sign = None diff --git a/pandas/tseries/tests/test_frequencies.py b/pandas/tseries/tests/test_frequencies.py index b84cdefe7009f..965c198eb7c95 100644 --- a/pandas/tseries/tests/test_frequencies.py +++ b/pandas/tseries/tests/test_frequencies.py @@ -17,6 +17,7 @@ import pandas.compat as compat import pandas.util.testing as tm +from pandas import Timedelta def test_to_offset_multiple(): freqstr = '2h30min' @@ -81,6 +82,47 @@ def test_to_offset_leading_zero(): assert(result.n == -194) +def test_to_offset_pd_timedelta(): + # Tests for #9064 + td = Timedelta(days=1, seconds=1) + result = frequencies.to_offset(td) + expected = offsets.Second(86401) + assert(expected==result) + + td = Timedelta(days=-1, seconds=1) + result = frequencies.to_offset(td) + expected = offsets.Second(-86399) + assert(expected==result) + + td = Timedelta(hours=1, minutes=10) + result = frequencies.to_offset(td) + expected = offsets.Minute(70) + assert(expected==result) + + td = Timedelta(hours=1, minutes=-10) + result = frequencies.to_offset(td) + expected = offsets.Minute(50) + assert(expected==result) + + td = Timedelta(weeks=1) + result = frequencies.to_offset(td) + expected = offsets.Day(7) + assert(expected==result) + + td1 = Timedelta(hours=1) + result1 = frequencies.to_offset(td1) + result2 = frequencies.to_offset('60min') + assert(result1 == result2) + + td = Timedelta(microseconds=1) + result = frequencies.to_offset(td) + expected = offsets.Micro(1) + assert(expected == result) + + td = Timedelta(microseconds=0) + tm.assertRaises(ValueError, lambda: frequencies.to_offset(td)) + + def test_anchored_shortcuts(): result = frequencies.to_offset('W') expected = frequencies.to_offset('W-SUN')