diff --git a/doc/source/release.rst b/doc/source/release.rst index 2646dd33535a1..c0d4c0c73296f 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -150,6 +150,8 @@ API Changes - ``DataFrame.sort`` now places NaNs at the beginning or end of the sort according to the ``na_position`` parameter. (:issue:`3917`) +- all offset operations now return ``Timestamp`` types (rather than datetime), Business/Week frequencies were incorrect (:issue:`4069`) + Deprecations ~~~~~~~~~~~~ diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index eb40f1f520cff..9130d0f3d8102 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -472,9 +472,9 @@ def _set_busdaycalendar(self): kwargs = {'weekmask':self.weekmask,'holidays':self.holidays} else: kwargs = {'weekmask':self.weekmask} - try: + try: self.busdaycalendar = np.busdaycalendar(**kwargs) - except: + except: # Check we have the required numpy version from distutils.version import LooseVersion @@ -484,9 +484,9 @@ def _set_busdaycalendar(self): np.__version__) else: raise - + def __getstate__(self): - """"Return a pickleable state""" + """Return a pickleable state""" state = self.__dict__.copy() del state['busdaycalendar'] return state @@ -520,7 +520,7 @@ def apply(self, other): if self.offset: result = result + self.offset - return result + return as_timestamp(result) elif isinstance(other, np.datetime64): dtype = other.dtype @@ -539,7 +539,7 @@ def apply(self, other): if self.offset: result = result + self.offset - return result + return as_timestamp(result) elif isinstance(other, (timedelta, Tick)): return BDay(self.n, offset=self.offset + other, @@ -639,7 +639,7 @@ def apply(self, other): if other.weekday() > 4: other = other - BDay() - return other + return as_timestamp(other) _prefix = 'BM' @@ -706,7 +706,7 @@ def isAnchored(self): def apply(self, other): if self.weekday is None: - return as_datetime(other) + self.n * self._inc + return as_timestamp(as_datetime(other) + self.n * self._inc) if self.n > 0: k = self.n @@ -998,7 +998,7 @@ def apply(self, other): if other.weekday() > 4: other = other - BDay() - return other + return as_timestamp(other) def onOffset(self, dt): modMonth = (dt.month - self.startingMonth) % 3 @@ -1188,7 +1188,7 @@ def apply(self, other): if result.weekday() > 4: result = result - BDay() - return result + return as_timestamp(result) class BYearBegin(YearOffset): diff --git a/pandas/tseries/tests/test_offsets.py b/pandas/tseries/tests/test_offsets.py index b303b7bb50526..07daf7f22afb7 100644 --- a/pandas/tseries/tests/test_offsets.py +++ b/pandas/tseries/tests/test_offsets.py @@ -99,7 +99,7 @@ class TestBase(tm.TestCase): def test_apply_out_of_range(self): if self._offset is None: - raise nose.SkipTest("_offset not defined") + raise nose.SkipTest("_offset not defined to test out-of-range") # try to create an out-of-bounds result timestamp; if we can't create the offset # skip @@ -113,6 +113,17 @@ def test_apply_out_of_range(self): except (ValueError, KeyError): raise nose.SkipTest("cannot create out_of_range offset") + def test_return_type(self): + + # make sure that we are returning a Timestamp + try: + offset = self._offset(1) + except: + raise nose.SkipTest("_offset not defined to test return_type") + + result = Timestamp('20080101') + offset + self.assertIsInstance(result, Timestamp) + class TestDateOffset(TestBase): _multiprocess_can_split_ = True