diff --git a/pandas/tests/tseries/offsets/test_business_day.py b/pandas/tests/tseries/offsets/test_business_day.py index 26df051ef928f..92daafaf469cd 100644 --- a/pandas/tests/tseries/offsets/test_business_day.py +++ b/pandas/tests/tseries/offsets/test_business_day.py @@ -7,21 +7,17 @@ timedelta, ) -import numpy as np import pytest from pandas._libs.tslibs.offsets import ( ApplyTypeError, BDay, BMonthEnd, - CDay, ) -from pandas.compat import np_datetime64_compat from pandas import ( DatetimeIndex, _testing as tm, - read_pickle, ) from pandas.tests.tseries.offsets.common import ( Base, @@ -31,7 +27,6 @@ from pandas.tests.tseries.offsets.test_offsets import _ApplyCases from pandas.tseries import offsets as offsets -from pandas.tseries.holiday import USFederalHolidayCalendar class TestBusinessDay(Base): @@ -212,243 +207,3 @@ def test_apply_corner(self): msg = "Only know how to combine business day with datetime or timedelta" with pytest.raises(ApplyTypeError, match=msg): BDay().apply(BMonthEnd()) - - -class TestCustomBusinessDay(Base): - _offset = CDay - - def setup_method(self, method): - self.d = datetime(2008, 1, 1) - self.nd = np_datetime64_compat("2008-01-01 00:00:00Z") - - self.offset = CDay() - self.offset1 = self.offset - self.offset2 = CDay(2) - - def test_different_normalize_equals(self): - # GH#21404 changed __eq__ to return False when `normalize` does not match - offset = self._offset() - offset2 = self._offset(normalize=True) - assert offset != offset2 - - def test_repr(self): - assert repr(self.offset) == "" - assert repr(self.offset2) == "<2 * CustomBusinessDays>" - - expected = "" - assert repr(self.offset + timedelta(1)) == expected - - def test_with_offset(self): - offset = self.offset + timedelta(hours=2) - - assert (self.d + offset) == datetime(2008, 1, 2, 2) - - def test_with_offset_index(self): - dti = DatetimeIndex([self.d]) - result = dti + (self.offset + timedelta(hours=2)) - - expected = DatetimeIndex([datetime(2008, 1, 2, 2)]) - tm.assert_index_equal(result, expected) - - def test_eq(self): - assert self.offset2 == self.offset2 - - def test_mul(self): - pass - - def test_hash(self): - assert hash(self.offset2) == hash(self.offset2) - - def test_call(self): - with tm.assert_produces_warning(FutureWarning): - # GH#34171 DateOffset.__call__ is deprecated - assert self.offset2(self.d) == datetime(2008, 1, 3) - assert self.offset2(self.nd) == datetime(2008, 1, 3) - - def testRollback1(self): - assert CDay(10).rollback(self.d) == self.d - - def testRollback2(self): - assert CDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) - - def testRollforward1(self): - assert CDay(10).rollforward(self.d) == self.d - - def testRollforward2(self): - assert CDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) - - def test_roll_date_object(self): - offset = CDay() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 9, 14) - - result = offset.rollforward(dt) - assert result == datetime(2012, 9, 17) - - offset = offsets.Day() - result = offset.rollback(dt) - assert result == datetime(2012, 9, 15) - - result = offset.rollforward(dt) - assert result == datetime(2012, 9, 15) - - on_offset_cases = [ - (CDay(), datetime(2008, 1, 1), True), - (CDay(), datetime(2008, 1, 5), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_is_on_offset(self, case): - offset, d, expected = case - assert_is_on_offset(offset, d, expected) - - apply_cases: _ApplyCases = [ - ( - CDay(), - { - datetime(2008, 1, 1): datetime(2008, 1, 2), - datetime(2008, 1, 4): datetime(2008, 1, 7), - datetime(2008, 1, 5): datetime(2008, 1, 7), - datetime(2008, 1, 6): datetime(2008, 1, 7), - datetime(2008, 1, 7): datetime(2008, 1, 8), - }, - ), - ( - 2 * CDay(), - { - datetime(2008, 1, 1): datetime(2008, 1, 3), - datetime(2008, 1, 4): datetime(2008, 1, 8), - datetime(2008, 1, 5): datetime(2008, 1, 8), - datetime(2008, 1, 6): datetime(2008, 1, 8), - datetime(2008, 1, 7): datetime(2008, 1, 9), - }, - ), - ( - -CDay(), - { - datetime(2008, 1, 1): datetime(2007, 12, 31), - datetime(2008, 1, 4): datetime(2008, 1, 3), - datetime(2008, 1, 5): datetime(2008, 1, 4), - datetime(2008, 1, 6): datetime(2008, 1, 4), - datetime(2008, 1, 7): datetime(2008, 1, 4), - datetime(2008, 1, 8): datetime(2008, 1, 7), - }, - ), - ( - -2 * CDay(), - { - datetime(2008, 1, 1): datetime(2007, 12, 28), - datetime(2008, 1, 4): datetime(2008, 1, 2), - datetime(2008, 1, 5): datetime(2008, 1, 3), - datetime(2008, 1, 6): datetime(2008, 1, 3), - datetime(2008, 1, 7): datetime(2008, 1, 3), - datetime(2008, 1, 8): datetime(2008, 1, 4), - datetime(2008, 1, 9): datetime(2008, 1, 7), - }, - ), - ( - CDay(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 4): datetime(2008, 1, 4), - datetime(2008, 1, 5): datetime(2008, 1, 7), - datetime(2008, 1, 6): datetime(2008, 1, 7), - datetime(2008, 1, 7): datetime(2008, 1, 7), - }, - ), - ] - - @pytest.mark.parametrize("case", apply_cases) - def test_apply(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_apply_large_n(self): - dt = datetime(2012, 10, 23) - - result = dt + CDay(10) - assert result == datetime(2012, 11, 6) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CDay() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 12, 23) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - xp = datetime(2011, 12, 26) - assert rs == xp - - def test_apply_corner(self): - msg = ( - "Only know how to combine trading day " - "with datetime, datetime64 or timedelta" - ) - with pytest.raises(ApplyTypeError, match=msg): - CDay().apply(BMonthEnd()) - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")] - tday = CDay(holidays=holidays) - for year in range(2012, 2015): - dt = datetime(year, 4, 30) - xp = datetime(year, 5, 2) - rs = dt + tday - assert rs == xp - - def test_weekmask(self): - weekmask_saudi = "Sat Sun Mon Tue Wed" # Thu-Fri Weekend - weekmask_uae = "1111001" # Fri-Sat Weekend - weekmask_egypt = [1, 1, 1, 1, 0, 0, 1] # Fri-Sat Weekend - bday_saudi = CDay(weekmask=weekmask_saudi) - bday_uae = CDay(weekmask=weekmask_uae) - bday_egypt = CDay(weekmask=weekmask_egypt) - dt = datetime(2013, 5, 1) - xp_saudi = datetime(2013, 5, 4) - xp_uae = datetime(2013, 5, 2) - xp_egypt = datetime(2013, 5, 2) - assert xp_saudi == dt + bday_saudi - assert xp_uae == dt + bday_uae - assert xp_egypt == dt + bday_egypt - xp2 = datetime(2013, 5, 5) - assert xp2 == dt + 2 * bday_saudi - assert xp2 == dt + 2 * bday_uae - assert xp2 == dt + 2 * bday_egypt - - def test_weekmask_and_holidays(self): - weekmask_egypt = "Sun Mon Tue Wed Thu" # Fri-Sat Weekend - holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")] - bday_egypt = CDay(holidays=holidays, weekmask=weekmask_egypt) - dt = datetime(2013, 4, 30) - xp_egypt = datetime(2013, 5, 5) - assert xp_egypt == dt + 2 * bday_egypt - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_calendar(self): - calendar = USFederalHolidayCalendar() - dt = datetime(2014, 1, 17) - assert_offset_equal(CDay(calendar=calendar), dt, datetime(2014, 1, 21)) - - def test_roundtrip_pickle(self): - def _check_roundtrip(obj): - unpickled = tm.round_trip_pickle(obj) - assert unpickled == obj - - _check_roundtrip(self.offset) - _check_roundtrip(self.offset2) - _check_roundtrip(self.offset * 2) - - def test_pickle_compat_0_14_1(self, datapath): - hdays = [datetime(2013, 1, 1) for ele in range(4)] - pth = datapath("tseries", "offsets", "data", "cday-0.14.1.pickle") - cday0_14_1 = read_pickle(pth) - cday = CDay(holidays=hdays) - assert cday == cday0_14_1 diff --git a/pandas/tests/tseries/offsets/test_custom_business_day.py b/pandas/tests/tseries/offsets/test_custom_business_day.py new file mode 100644 index 0000000000000..b8014f7112435 --- /dev/null +++ b/pandas/tests/tseries/offsets/test_custom_business_day.py @@ -0,0 +1,273 @@ +""" +Tests for offsets.CustomBusinessDay / CDay +""" +from datetime import ( + date, + datetime, + timedelta, +) + +import numpy as np +import pytest + +from pandas._libs.tslibs.offsets import ( + ApplyTypeError, + BMonthEnd, + CDay, +) +from pandas.compat import np_datetime64_compat + +from pandas import ( + DatetimeIndex, + _testing as tm, + read_pickle, +) +from pandas.tests.tseries.offsets.common import ( + Base, + assert_is_on_offset, + assert_offset_equal, +) +from pandas.tests.tseries.offsets.test_offsets import _ApplyCases + +from pandas.tseries import offsets as offsets +from pandas.tseries.holiday import USFederalHolidayCalendar + + +class TestCustomBusinessDay(Base): + _offset = CDay + + def setup_method(self, method): + self.d = datetime(2008, 1, 1) + self.nd = np_datetime64_compat("2008-01-01 00:00:00Z") + + self.offset = CDay() + self.offset1 = self.offset + self.offset2 = CDay(2) + + def test_different_normalize_equals(self): + # GH#21404 changed __eq__ to return False when `normalize` does not match + offset = self._offset() + offset2 = self._offset(normalize=True) + assert offset != offset2 + + def test_repr(self): + assert repr(self.offset) == "" + assert repr(self.offset2) == "<2 * CustomBusinessDays>" + + expected = "" + assert repr(self.offset + timedelta(1)) == expected + + def test_with_offset(self): + offset = self.offset + timedelta(hours=2) + + assert (self.d + offset) == datetime(2008, 1, 2, 2) + + def test_with_offset_index(self): + dti = DatetimeIndex([self.d]) + result = dti + (self.offset + timedelta(hours=2)) + + expected = DatetimeIndex([datetime(2008, 1, 2, 2)]) + tm.assert_index_equal(result, expected) + + def test_eq(self): + assert self.offset2 == self.offset2 + + def test_mul(self): + pass + + def test_hash(self): + assert hash(self.offset2) == hash(self.offset2) + + def test_call(self): + with tm.assert_produces_warning(FutureWarning): + # GH#34171 DateOffset.__call__ is deprecated + assert self.offset2(self.d) == datetime(2008, 1, 3) + assert self.offset2(self.nd) == datetime(2008, 1, 3) + + def testRollback1(self): + assert CDay(10).rollback(self.d) == self.d + + def testRollback2(self): + assert CDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) + + def testRollforward1(self): + assert CDay(10).rollforward(self.d) == self.d + + def testRollforward2(self): + assert CDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) + + def test_roll_date_object(self): + offset = CDay() + + dt = date(2012, 9, 15) + + result = offset.rollback(dt) + assert result == datetime(2012, 9, 14) + + result = offset.rollforward(dt) + assert result == datetime(2012, 9, 17) + + offset = offsets.Day() + result = offset.rollback(dt) + assert result == datetime(2012, 9, 15) + + result = offset.rollforward(dt) + assert result == datetime(2012, 9, 15) + + on_offset_cases = [ + (CDay(), datetime(2008, 1, 1), True), + (CDay(), datetime(2008, 1, 5), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_is_on_offset(self, case): + offset, day, expected = case + assert_is_on_offset(offset, day, expected) + + apply_cases: _ApplyCases = [ + ( + CDay(), + { + datetime(2008, 1, 1): datetime(2008, 1, 2), + datetime(2008, 1, 4): datetime(2008, 1, 7), + datetime(2008, 1, 5): datetime(2008, 1, 7), + datetime(2008, 1, 6): datetime(2008, 1, 7), + datetime(2008, 1, 7): datetime(2008, 1, 8), + }, + ), + ( + 2 * CDay(), + { + datetime(2008, 1, 1): datetime(2008, 1, 3), + datetime(2008, 1, 4): datetime(2008, 1, 8), + datetime(2008, 1, 5): datetime(2008, 1, 8), + datetime(2008, 1, 6): datetime(2008, 1, 8), + datetime(2008, 1, 7): datetime(2008, 1, 9), + }, + ), + ( + -CDay(), + { + datetime(2008, 1, 1): datetime(2007, 12, 31), + datetime(2008, 1, 4): datetime(2008, 1, 3), + datetime(2008, 1, 5): datetime(2008, 1, 4), + datetime(2008, 1, 6): datetime(2008, 1, 4), + datetime(2008, 1, 7): datetime(2008, 1, 4), + datetime(2008, 1, 8): datetime(2008, 1, 7), + }, + ), + ( + -2 * CDay(), + { + datetime(2008, 1, 1): datetime(2007, 12, 28), + datetime(2008, 1, 4): datetime(2008, 1, 2), + datetime(2008, 1, 5): datetime(2008, 1, 3), + datetime(2008, 1, 6): datetime(2008, 1, 3), + datetime(2008, 1, 7): datetime(2008, 1, 3), + datetime(2008, 1, 8): datetime(2008, 1, 4), + datetime(2008, 1, 9): datetime(2008, 1, 7), + }, + ), + ( + CDay(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 4): datetime(2008, 1, 4), + datetime(2008, 1, 5): datetime(2008, 1, 7), + datetime(2008, 1, 6): datetime(2008, 1, 7), + datetime(2008, 1, 7): datetime(2008, 1, 7), + }, + ), + ] + + @pytest.mark.parametrize("case", apply_cases) + def test_apply(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_apply_large_n(self): + dt = datetime(2012, 10, 23) + + result = dt + CDay(10) + assert result == datetime(2012, 11, 6) + + result = dt + CDay(100) - CDay(100) + assert result == dt + + off = CDay() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 12, 23) + assert rs == xp + + st = datetime(2011, 12, 18) + rs = st + off + xp = datetime(2011, 12, 26) + assert rs == xp + + def test_apply_corner(self): + msg = ( + "Only know how to combine trading day " + "with datetime, datetime64 or timedelta" + ) + with pytest.raises(ApplyTypeError, match=msg): + CDay().apply(BMonthEnd()) + + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")] + tday = CDay(holidays=holidays) + for year in range(2012, 2015): + dt = datetime(year, 4, 30) + xp = datetime(year, 5, 2) + rs = dt + tday + assert rs == xp + + def test_weekmask(self): + weekmask_saudi = "Sat Sun Mon Tue Wed" # Thu-Fri Weekend + weekmask_uae = "1111001" # Fri-Sat Weekend + weekmask_egypt = [1, 1, 1, 1, 0, 0, 1] # Fri-Sat Weekend + bday_saudi = CDay(weekmask=weekmask_saudi) + bday_uae = CDay(weekmask=weekmask_uae) + bday_egypt = CDay(weekmask=weekmask_egypt) + dt = datetime(2013, 5, 1) + xp_saudi = datetime(2013, 5, 4) + xp_uae = datetime(2013, 5, 2) + xp_egypt = datetime(2013, 5, 2) + assert xp_saudi == dt + bday_saudi + assert xp_uae == dt + bday_uae + assert xp_egypt == dt + bday_egypt + xp2 = datetime(2013, 5, 5) + assert xp2 == dt + 2 * bday_saudi + assert xp2 == dt + 2 * bday_uae + assert xp2 == dt + 2 * bday_egypt + + def test_weekmask_and_holidays(self): + weekmask_egypt = "Sun Mon Tue Wed Thu" # Fri-Sat Weekend + holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")] + bday_egypt = CDay(holidays=holidays, weekmask=weekmask_egypt) + dt = datetime(2013, 4, 30) + xp_egypt = datetime(2013, 5, 5) + assert xp_egypt == dt + 2 * bday_egypt + + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_calendar(self): + calendar = USFederalHolidayCalendar() + dt = datetime(2014, 1, 17) + assert_offset_equal(CDay(calendar=calendar), dt, datetime(2014, 1, 21)) + + def test_roundtrip_pickle(self): + def _check_roundtrip(obj): + unpickled = tm.round_trip_pickle(obj) + assert unpickled == obj + + _check_roundtrip(self.offset) + _check_roundtrip(self.offset2) + _check_roundtrip(self.offset * 2) + + def test_pickle_compat_0_14_1(self, datapath): + hdays = [datetime(2013, 1, 1) for ele in range(4)] + pth = datapath("tseries", "offsets", "data", "cday-0.14.1.pickle") + cday0_14_1 = read_pickle(pth) + cday = CDay(holidays=hdays) + assert cday == cday0_14_1