From 66752a1b5446ab033ad7496e1a22c2173812d637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Mon, 11 Nov 2019 14:01:31 +0100 Subject: [PATCH 01/12] Initial duplicated --- ...st_offsets.py => test_business_offsets.py} | 0 .../tseries/offsets/test_date_offsets.py | 4362 +++++++++++++++++ 2 files changed, 4362 insertions(+) rename pandas/tests/tseries/offsets/{test_offsets.py => test_business_offsets.py} (100%) create mode 100644 pandas/tests/tseries/offsets/test_date_offsets.py diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py similarity index 100% rename from pandas/tests/tseries/offsets/test_offsets.py rename to pandas/tests/tseries/offsets/test_business_offsets.py diff --git a/pandas/tests/tseries/offsets/test_date_offsets.py b/pandas/tests/tseries/offsets/test_date_offsets.py new file mode 100644 index 0000000000000..bed8d2461f65d --- /dev/null +++ b/pandas/tests/tseries/offsets/test_date_offsets.py @@ -0,0 +1,4362 @@ +from datetime import date, datetime, time as dt_time, timedelta +from typing import Dict, List, Tuple, Type + +import numpy as np +import pytest + +from pandas._libs.tslibs import ( + NaT, + OutOfBoundsDatetime, + Timestamp, + conversion, + timezones, +) +from pandas._libs.tslibs.frequencies import ( + INVALID_FREQ_ERR_MSG, + get_freq_code, + get_freq_str, +) +import pandas._libs.tslibs.offsets as liboffsets +from pandas._libs.tslibs.offsets import ApplyTypeError +import pandas.compat as compat +from pandas.compat.numpy import np_datetime64_compat + +from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range +from pandas.core.series import Series +import pandas.util.testing as tm + +from pandas.io.pickle import read_pickle +from pandas.tseries.frequencies import _offset_map, get_offset +from pandas.tseries.holiday import USFederalHolidayCalendar +import pandas.tseries.offsets as offsets +from pandas.tseries.offsets import ( + FY5253, + BaseOffset, + BDay, + BMonthBegin, + BMonthEnd, + BQuarterBegin, + BQuarterEnd, + BusinessHour, + BYearBegin, + BYearEnd, + CBMonthBegin, + CBMonthEnd, + CDay, + CustomBusinessHour, + DateOffset, + Day, + Easter, + FY5253Quarter, + LastWeekOfMonth, + MonthBegin, + MonthEnd, + Nano, + QuarterBegin, + QuarterEnd, + SemiMonthBegin, + SemiMonthEnd, + Tick, + Week, + WeekOfMonth, + YearBegin, + YearEnd, +) + +from .common import assert_offset_equal, assert_onOffset + + +class WeekDay: + # TODO: Remove: This is not used outside of tests + MON = 0 + TUE = 1 + WED = 2 + THU = 3 + FRI = 4 + SAT = 5 + SUN = 6 + + +#### +# Misc function tests +#### + + +def test_to_M8(): + valb = datetime(2007, 10, 1) + valu = _to_M8(valb) + assert isinstance(valu, np.datetime64) + + +##### +# DateOffset Tests +##### +_ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]] + + +class Base: + _offset = None # type: Type[DateOffset] + d = Timestamp(datetime(2008, 1, 2)) + + timezones = [ + None, + "UTC", + "Asia/Tokyo", + "US/Eastern", + "dateutil/Asia/Tokyo", + "dateutil/US/Pacific", + ] + + def _get_offset(self, klass, value=1, normalize=False): + # create instance from offset class + if klass is FY5253: + klass = klass( + n=value, + startingMonth=1, + weekday=1, + variation="last", + normalize=normalize, + ) + elif klass is FY5253Quarter: + klass = klass( + n=value, + startingMonth=1, + weekday=1, + qtr_with_extra_week=1, + variation="last", + normalize=normalize, + ) + elif klass is LastWeekOfMonth: + klass = klass(n=value, weekday=5, normalize=normalize) + elif klass is WeekOfMonth: + klass = klass(n=value, week=1, weekday=5, normalize=normalize) + elif klass is Week: + klass = klass(n=value, weekday=5, normalize=normalize) + elif klass is DateOffset: + klass = klass(days=value, normalize=normalize) + else: + klass = klass(value, normalize=normalize) + return klass + + def test_apply_out_of_range(self, tz_naive_fixture): + tz = tz_naive_fixture + if self._offset is None: + return + + # try to create an out-of-bounds result timestamp; if we can't create + # the offset skip + try: + if self._offset in (BusinessHour, CustomBusinessHour): + # Using 10000 in BusinessHour fails in tz check because of DST + # difference + offset = self._get_offset(self._offset, value=100000) + else: + offset = self._get_offset(self._offset, value=10000) + + result = Timestamp("20080101") + offset + assert isinstance(result, datetime) + assert result.tzinfo is None + + # Check tz is preserved + t = Timestamp("20080101", tz=tz) + result = t + offset + assert isinstance(result, datetime) + assert t.tzinfo == result.tzinfo + + except OutOfBoundsDatetime: + pass + except (ValueError, KeyError): + # we are creating an invalid offset + # so ignore + pass + + def test_offsets_compare_equal(self): + # root cause of GH#456: __ne__ was not implemented + if self._offset is None: + return + offset1 = self._offset() + offset2 = self._offset() + assert not offset1 != offset2 + assert offset1 == offset2 + + def test_rsub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert self.d - self.offset2 == (-self.offset2).apply(self.d) + + def test_radd(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert self.d + self.offset2 == self.offset2 + self.d + + def test_sub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + off = self.offset2 + msg = "Cannot subtract datetime from offset" + with pytest.raises(TypeError, match=msg): + off - self.d + + assert 2 * off - off == off + assert self.d - self.offset2 == self.d + self._offset(-2) + assert self.d - self.offset2 == self.d - (2 * off - off) + + def testMult1(self): + if self._offset is None or not hasattr(self, "offset1"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset1 attr + return + assert self.d + 10 * self.offset1 == self.d + self._offset(10) + assert self.d + 5 * self.offset1 == self.d + self._offset(5) + + def testMult2(self): + if self._offset is None: + return + assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) + assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) + + def test_compare_str(self): + # GH#23524 + # comparing to strings that cannot be cast to DateOffsets should + # not raise for __eq__ or __ne__ + if self._offset is None: + return + off = self._get_offset(self._offset) + + assert not off == "infer" + assert off != "foo" + # Note: inequalities are only implemented for Tick subclasses; + # tests for this are in test_ticks + + +class TestCommon(Base): + # exected value created by Base._get_offset + # are applied to 2011/01/01 09:00 (Saturday) + # used for .apply and .rollforward + expecteds = { + "Day": Timestamp("2011-01-02 09:00:00"), + "DateOffset": Timestamp("2011-01-02 09:00:00"), + "BusinessDay": Timestamp("2011-01-03 09:00:00"), + "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), + "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), + "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), + "MonthBegin": Timestamp("2011-02-01 09:00:00"), + "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), + "MonthEnd": Timestamp("2011-01-31 09:00:00"), + "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), + "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), + "YearBegin": Timestamp("2012-01-01 09:00:00"), + "BYearBegin": Timestamp("2011-01-03 09:00:00"), + "YearEnd": Timestamp("2011-12-31 09:00:00"), + "BYearEnd": Timestamp("2011-12-30 09:00:00"), + "QuarterBegin": Timestamp("2011-03-01 09:00:00"), + "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), + "QuarterEnd": Timestamp("2011-03-31 09:00:00"), + "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), + "BusinessHour": Timestamp("2011-01-03 10:00:00"), + "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), + "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), + "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), + "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), + "FY5253": Timestamp("2011-01-25 09:00:00"), + "Week": Timestamp("2011-01-08 09:00:00"), + "Easter": Timestamp("2011-04-24 09:00:00"), + "Hour": Timestamp("2011-01-01 10:00:00"), + "Minute": Timestamp("2011-01-01 09:01:00"), + "Second": Timestamp("2011-01-01 09:00:01"), + "Milli": Timestamp("2011-01-01 09:00:00.001000"), + "Micro": Timestamp("2011-01-01 09:00:00.000001"), + "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), + } + + def test_immutable(self, offset_types): + # GH#21341 check that __setattr__ raises + offset = self._get_offset(offset_types) + with pytest.raises(AttributeError): + offset.normalize = True + with pytest.raises(AttributeError): + offset.n = 91 + + def test_return_type(self, offset_types): + offset = self._get_offset(offset_types) + + # make sure that we are returning a Timestamp + result = Timestamp("20080101") + offset + assert isinstance(result, Timestamp) + + # make sure that we are returning NaT + assert NaT + offset is NaT + assert offset + NaT is NaT + + assert NaT - offset is NaT + assert (-offset).apply(NaT) is NaT + + def test_offset_n(self, offset_types): + offset = self._get_offset(offset_types) + assert offset.n == 1 + + neg_offset = offset * -1 + assert neg_offset.n == -1 + + mul_offset = offset * 3 + assert mul_offset.n == 3 + + def test_offset_timedelta64_arg(self, offset_types): + # check that offset._validate_n raises TypeError on a timedelt64 + # object + off = self._get_offset(offset_types) + + td64 = np.timedelta64(4567, "s") + with pytest.raises(TypeError, match="argument must be an integer"): + type(off)(n=td64, **off.kwds) + + def test_offset_mul_ndarray(self, offset_types): + off = self._get_offset(offset_types) + + expected = np.array([[off, off * 2], [off * 3, off * 4]]) + + result = np.array([[1, 2], [3, 4]]) * off + tm.assert_numpy_array_equal(result, expected) + + result = off * np.array([[1, 2], [3, 4]]) + tm.assert_numpy_array_equal(result, expected) + + def test_offset_freqstr(self, offset_types): + offset = self._get_offset(offset_types) + + freqstr = offset.freqstr + if freqstr not in ("", "", "LWOM-SAT"): + code = get_offset(freqstr) + assert offset.rule_code == code + + def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): + + if normalize and issubclass(offset, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + + offset_s = self._get_offset(offset, normalize=normalize) + func = getattr(offset_s, funcname) + + result = func(dt) + assert isinstance(result, Timestamp) + assert result == expected + + result = func(Timestamp(dt)) + assert isinstance(result, Timestamp) + assert result == expected + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected + Nano(5) + else: + assert result == expected + + if isinstance(dt, np.datetime64): + # test tz when input is datetime or Timestamp + return + + for tz in self.timezones: + expected_localize = expected.tz_localize(tz) + tz_obj = timezones.maybe_get_tz(tz) + dt_tz = conversion.localize_pydatetime(dt, tz_obj) + + result = func(dt_tz) + assert isinstance(result, Timestamp) + assert result == expected_localize + + result = func(Timestamp(dt, tz=tz)) + assert isinstance(result, Timestamp) + assert result == expected_localize + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt, tz=tz) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected_localize + Nano(5) + else: + assert result == expected_localize + + def test_apply(self, offset_types): + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = self.expecteds[offset_types.__name__] + self._check_offsetfunc_works(offset_types, "apply", dt, expected) + + expected = Timestamp(expected.date()) + self._check_offsetfunc_works( + offset_types, "apply", dt, expected, normalize=True + ) + + def test_rollforward(self, offset_types): + expecteds = self.expecteds.copy() + + # result will not be changed if the target is on the offset + no_changes = [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ] + for n in no_changes: + expecteds[n] = Timestamp("2011/01/01 09:00") + + expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") + expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2011-01-02 00:00:00"), + "DateOffset": Timestamp("2011-01-02 00:00:00"), + "MonthBegin": Timestamp("2011-02-01 00:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), + "YearBegin": Timestamp("2012-01-01 00:00:00"), + "Week": Timestamp("2011-01-08 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[offset_types.__name__] + self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) + expected = norm_expected[offset_types.__name__] + self._check_offsetfunc_works( + offset_types, "rollforward", dt, expected, normalize=True + ) + + def test_rollback(self, offset_types): + expecteds = { + "BusinessDay": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), + "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), + "MonthEnd": Timestamp("2010-12-31 09:00:00"), + "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), + "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), + "BYearBegin": Timestamp("2010-01-01 09:00:00"), + "YearEnd": Timestamp("2010-12-31 09:00:00"), + "BYearEnd": Timestamp("2010-12-31 09:00:00"), + "QuarterBegin": Timestamp("2010-12-01 09:00:00"), + "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), + "QuarterEnd": Timestamp("2010-12-31 09:00:00"), + "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), + "BusinessHour": Timestamp("2010-12-31 17:00:00"), + "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), + "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), + "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), + "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), + "FY5253": Timestamp("2010-01-26 09:00:00"), + "Easter": Timestamp("2010-04-04 09:00:00"), + } + + # result will not be changed if the target is on the offset + for n in [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ]: + expecteds[n] = Timestamp("2011/01/01 09:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2010-12-31 00:00:00"), + "DateOffset": Timestamp("2010-12-31 00:00:00"), + "MonthBegin": Timestamp("2010-12-01 00:00:00"), + "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), + "YearBegin": Timestamp("2010-01-01 00:00:00"), + "Week": Timestamp("2010-12-25 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[offset_types.__name__] + self._check_offsetfunc_works(offset_types, "rollback", dt, expected) + + expected = norm_expected[offset_types.__name__] + self._check_offsetfunc_works( + offset_types, "rollback", dt, expected, normalize=True + ) + + def test_onOffset(self, offset_types): + dt = self.expecteds[offset_types.__name__] + offset_s = self._get_offset(offset_types) + assert offset_s.onOffset(dt) + + # when normalize=True, onOffset checks time is 00:00:00 + if issubclass(offset_types, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + offset_n = self._get_offset(offset_types, normalize=True) + assert not offset_n.onOffset(dt) + + if offset_types in (BusinessHour, CustomBusinessHour): + # In default BusinessHour (9:00-17:00), normalized time + # cannot be in business hour range + return + date = datetime(dt.year, dt.month, dt.day) + assert offset_n.onOffset(date) + + def test_add(self, offset_types, tz_naive_fixture): + tz = tz_naive_fixture + dt = datetime(2011, 1, 1, 9, 0) + + offset_s = self._get_offset(offset_types) + expected = self.expecteds[offset_types.__name__] + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + # normalize=True, disallowed for Tick subclasses GH#21427 + if issubclass(offset_types, Tick): + return + offset_s = self._get_offset(offset_types, normalize=True) + expected = Timestamp(expected.date()) + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + def test_pickle_v0_15_2(self, datapath): + offsets = { + "DateOffset": DateOffset(years=1), + "MonthBegin": MonthBegin(1), + "Day": Day(1), + "YearBegin": YearBegin(1), + "Week": Week(1), + } + + pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") + # This code was executed once on v0.15.2 to generate the pickle: + # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) + # + tm.assert_dict_equal(offsets, read_pickle(pickle_path)) + + +class TestDateOffset(Base): + def setup_method(self, method): + self.d = Timestamp(datetime(2008, 1, 2)) + _offset_map.clear() + + def test_repr(self): + repr(DateOffset()) + repr(DateOffset(2)) + repr(2 * DateOffset()) + repr(2 * DateOffset(months=2)) + + def test_mul(self): + assert DateOffset(2) == 2 * DateOffset(1) + assert DateOffset(2) == DateOffset(1) * 2 + + def test_constructor(self): + + assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2) + assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2) + + assert (self.d + DateOffset(2)) == datetime(2008, 1, 4) + + assert not DateOffset(2).isAnchored() + assert DateOffset(1).isAnchored() + + d = datetime(2008, 1, 31) + assert (d + DateOffset(months=1)) == datetime(2008, 2, 29) + + def test_copy(self): + assert DateOffset(months=2).copy() == DateOffset(months=2) + + def test_eq(self): + offset1 = DateOffset(days=1) + offset2 = DateOffset(days=365) + + assert offset1 != offset2 + + +class TestBusinessDay(Base): + _offset = BDay + + def setup_method(self, method): + self.d = datetime(2008, 1, 1) + + self.offset = BDay() + self.offset1 = self.offset + self.offset2 = BDay(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 * BusinessDays>" + + if compat.PY37: + expected = "" + else: + 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_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): + assert self.offset2(self.d) == datetime(2008, 1, 3) + + def testRollback1(self): + assert BDay(10).rollback(self.d) == self.d + + def testRollback2(self): + assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) + + def testRollforward1(self): + assert BDay(10).rollforward(self.d) == self.d + + def testRollforward2(self): + assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) + + def test_roll_date_object(self): + offset = BDay() + + 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) + + def test_onOffset(self): + tests = [ + (BDay(), datetime(2008, 1, 1), True), + (BDay(), datetime(2008, 1, 5), False), + ] + + for offset, d, expected in tests: + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + 2 * BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + -BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + -2 * BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + BDay(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 + BDay(10) + assert result == datetime(2012, 11, 6) + + result = dt + BDay(100) - BDay(100) + assert result == dt + + off = BDay() * 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 + + off = BDay() * 10 + rs = datetime(2014, 1, 5) + off # see #5890 + xp = datetime(2014, 1, 17) + assert rs == xp + + 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 TestBusinessHour(Base): + _offset = BusinessHour + + def setup_method(self, method): + self.d = datetime(2014, 7, 1, 10, 00) + + self.offset1 = BusinessHour() + self.offset2 = BusinessHour(n=3) + + self.offset3 = BusinessHour(n=-1) + self.offset4 = BusinessHour(n=-4) + + from datetime import time as dt_time + + self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) + self.offset6 = BusinessHour(start="20:00", end="05:00") + self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) + self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) + self.offset9 = BusinessHour( + n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] + ) + self.offset10 = BusinessHour( + n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] + ) + + @pytest.mark.parametrize( + "start,end,match", + [ + ( + dt_time(11, 0, 5), + "17:00", + "time data must be specified only with hour and minute", + ), + ("AAA", "17:00", "time data must match '%H:%M' format"), + ("14:00:05", "17:00", "time data must match '%H:%M' format"), + ([], "17:00", "Must include at least 1 start time"), + ("09:00", [], "Must include at least 1 end time"), + ( + ["09:00", "11:00"], + "17:00", + "number of starting time and ending time must be the same", + ), + ( + ["09:00", "11:00"], + ["10:00"], + "number of starting time and ending time must be the same", + ), + ( + ["09:00", "11:00"], + ["12:00", "20:00"], + r"invalid starting and ending time\(s\): opening hours should not " + "touch or overlap with one another", + ), + ( + ["12:00", "20:00"], + ["09:00", "11:00"], + r"invalid starting and ending time\(s\): opening hours should not " + "touch or overlap with one another", + ), + ], + ) + def test_constructor_errors(self, start, end, match): + with pytest.raises(ValueError, match=match): + BusinessHour(start=start, end=end) + + 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.offset1) == "" + assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" + assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" + assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" + + assert repr(self.offset5) == "" + assert repr(self.offset6) == "" + assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" + assert repr(self.offset8) == "" + assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" + assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" + + def test_with_offset(self): + expected = Timestamp("2014-07-01 13:00") + + assert self.d + BusinessHour() * 3 == expected + assert self.d + BusinessHour(n=3) == expected + + @pytest.mark.parametrize( + "offset_name", + ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], + ) + def test_eq_attribute(self, offset_name): + offset = getattr(self, offset_name) + assert offset == offset + + @pytest.mark.parametrize( + "offset1,offset2", + [ + (BusinessHour(start="09:00"), BusinessHour()), + ( + BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), + BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), + ), + ], + ) + def test_eq(self, offset1, offset2): + assert offset1 == offset2 + + @pytest.mark.parametrize( + "offset1,offset2", + [ + (BusinessHour(), BusinessHour(-1)), + (BusinessHour(start="09:00"), BusinessHour(start="09:01")), + ( + BusinessHour(start="09:00", end="17:00"), + BusinessHour(start="17:00", end="09:01"), + ), + ( + BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), + BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), + ), + ], + ) + def test_neq(self, offset1, offset2): + assert offset1 != offset2 + + @pytest.mark.parametrize( + "offset_name", + ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], + ) + def test_hash(self, offset_name): + offset = getattr(self, offset_name) + assert offset == offset + + def test_call(self): + assert self.offset1(self.d) == datetime(2014, 7, 1, 11) + assert self.offset2(self.d) == datetime(2014, 7, 1, 13) + assert self.offset3(self.d) == datetime(2014, 6, 30, 17) + assert self.offset4(self.d) == datetime(2014, 6, 30, 14) + assert self.offset8(self.d) == datetime(2014, 7, 1, 11) + assert self.offset9(self.d) == datetime(2014, 7, 1, 22) + assert self.offset10(self.d) == datetime(2014, 7, 1, 1) + + def test_sub(self): + # we have to override test_sub here because self.offset2 is not + # defined as self._offset(2) + off = self.offset2 + msg = "Cannot subtract datetime from offset" + with pytest.raises(TypeError, match=msg): + off - self.d + assert 2 * off - off == off + + assert self.d - self.offset2 == self.d + self._offset(-3) + + def testRollback1(self): + assert self.offset1.rollback(self.d) == self.d + assert self.offset2.rollback(self.d) == self.d + assert self.offset3.rollback(self.d) == self.d + assert self.offset4.rollback(self.d) == self.d + assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) + assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) + assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) + assert self.offset8.rollback(self.d) == self.d + assert self.offset9.rollback(self.d) == self.d + assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) + assert self.offset6.rollback(d) == d + assert self.offset7.rollback(d) == d + assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset9.rollback(d) == d + assert self.offset10.rollback(d) == d + + assert self._offset(5).rollback(self.d) == self.d + + def testRollback2(self): + assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( + 2014, 7, 4, 17, 0 + ) + + def testRollforward1(self): + assert self.offset1.rollforward(self.d) == self.d + assert self.offset2.rollforward(self.d) == self.d + assert self.offset3.rollforward(self.d) == self.d + assert self.offset4.rollforward(self.d) == self.d + assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) + assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) + assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) + assert self.offset8.rollforward(self.d) == self.d + assert self.offset9.rollforward(self.d) == self.d + assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) + assert self.offset6.rollforward(d) == d + assert self.offset7.rollforward(d) == d + assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset9.rollforward(d) == d + assert self.offset10.rollforward(d) == d + + assert self._offset(5).rollforward(self.d) == self.d + + def testRollforward2(self): + assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( + 2014, 7, 7, 9 + ) + + def test_roll_date_object(self): + offset = BusinessHour() + + dt = datetime(2014, 7, 6, 15, 0) + + result = offset.rollback(dt) + assert result == datetime(2014, 7, 4, 17) + + result = offset.rollforward(dt) + assert result == datetime(2014, 7, 7, 9) + + normalize_cases = [] + normalize_cases.append( + ( + BusinessHour(normalize=True), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 1, 0): datetime(2014, 7, 1), + datetime(2014, 7, 4, 15): datetime(2014, 7, 4), + datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 7), + datetime(2014, 7, 6, 10): datetime(2014, 7, 7), + }, + ) + ) + + normalize_cases.append( + ( + BusinessHour(-1, normalize=True), + { + datetime(2014, 7, 1, 8): datetime(2014, 6, 30), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1), + datetime(2014, 7, 1, 10): datetime(2014, 6, 30), + datetime(2014, 7, 1, 0): datetime(2014, 6, 30), + datetime(2014, 7, 7, 10): datetime(2014, 7, 4), + datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 4), + datetime(2014, 7, 6, 10): datetime(2014, 7, 4), + }, + ) + ) + + normalize_cases.append( + ( + BusinessHour(1, normalize=True, start="17:00", end="04:00"), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 2, 2): datetime(2014, 7, 2), + datetime(2014, 7, 2, 3): datetime(2014, 7, 2), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5), + datetime(2014, 7, 5, 2): datetime(2014, 7, 5), + datetime(2014, 7, 7, 2): datetime(2014, 7, 7), + datetime(2014, 7, 7, 17): datetime(2014, 7, 7), + }, + ) + ) + + @pytest.mark.parametrize("case", normalize_cases) + def test_normalize(self, case): + offset, cases = case + for dt, expected in cases.items(): + assert offset.apply(dt) == expected + + on_offset_cases = [] + on_offset_cases.append( + ( + BusinessHour(), + { + datetime(2014, 7, 1, 9): True, + datetime(2014, 7, 1, 8, 59): False, + datetime(2014, 7, 1, 8): False, + datetime(2014, 7, 1, 17): True, + datetime(2014, 7, 1, 17, 1): False, + datetime(2014, 7, 1, 18): False, + datetime(2014, 7, 5, 9): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start="10:00", end="15:00"), + { + datetime(2014, 7, 1, 9): False, + datetime(2014, 7, 1, 10): True, + datetime(2014, 7, 1, 15): True, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 9, 0): False, + datetime(2014, 7, 1, 10, 0): False, + datetime(2014, 7, 1, 15): False, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12, 0): False, + datetime(2014, 7, 6, 12, 0): False, + datetime(2014, 7, 1, 19, 0): True, + datetime(2014, 7, 2, 0, 0): True, + datetime(2014, 7, 4, 23): True, + datetime(2014, 7, 5, 1): True, + datetime(2014, 7, 5, 5, 0): True, + datetime(2014, 7, 6, 23, 0): False, + datetime(2014, 7, 7, 3, 0): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), + { + datetime(2014, 7, 1, 9): True, + datetime(2014, 7, 1, 8, 59): False, + datetime(2014, 7, 1, 8): False, + datetime(2014, 7, 1, 17): True, + datetime(2014, 7, 1, 17, 1): False, + datetime(2014, 7, 1, 18): False, + datetime(2014, 7, 5, 9): False, + datetime(2014, 7, 6, 12): False, + datetime(2014, 7, 1, 12, 30): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), + { + datetime(2014, 7, 1, 9, 0): False, + datetime(2014, 7, 1, 10, 0): False, + datetime(2014, 7, 1, 15): False, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12, 0): False, + datetime(2014, 7, 6, 12, 0): False, + datetime(2014, 7, 1, 19, 0): True, + datetime(2014, 7, 2, 0, 0): True, + datetime(2014, 7, 4, 23): True, + datetime(2014, 7, 5, 1): True, + datetime(2014, 7, 5, 5, 0): True, + datetime(2014, 7, 6, 23, 0): False, + datetime(2014, 7, 7, 3, 0): False, + datetime(2014, 7, 4, 22): False, + }, + ) + ) + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, cases = case + for dt, expected in cases.items(): + assert offset.onOffset(dt) == expected + + opening_time_cases = [] + # opening time should be affected by sign of n, not by n's value and + # end + opening_time_cases.append( + ( + [ + BusinessHour(), + BusinessHour(n=2), + BusinessHour(n=4), + BusinessHour(end="10:00"), + BusinessHour(n=2, end="4:00"), + BusinessHour(n=4, end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + # if timestamp is on opening time, next opening time is + # as it is + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 3, 9), + datetime(2014, 7, 2, 9), + ), + # 2014-07-05 is saturday + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 8, 9), + datetime(2014, 7, 7, 9), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start="11:15"), + BusinessHour(n=2, start="11:15"), + BusinessHour(n=3, start="11:15"), + BusinessHour(start="11:15", end="10:00"), + BusinessHour(n=2, start="11:15", end="4:00"), + BusinessHour(n=3, start="11:15", end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 11, 15), + datetime(2014, 6, 30, 11, 15), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 11, 15): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 2, 11, 15, 1): ( + datetime(2014, 7, 3, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 11, 15), + datetime(2014, 7, 3, 11, 15), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(-1), + BusinessHour(n=-2), + BusinessHour(n=-4), + BusinessHour(n=-1, end="10:00"), + BusinessHour(n=-2, end="4:00"), + BusinessHour(n=-4, end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 3, 9), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 9): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 8, 9), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start="17:00", end="05:00"), + BusinessHour(n=3, start="17:00", end="03:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 17), + datetime(2014, 6, 30, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 4, 17): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 3, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 7, 17, 1): ( + datetime(2014, 7, 8, 17), + datetime(2014, 7, 7, 17), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(-1, start="17:00", end="05:00"), + BusinessHour(n=-2, start="17:00", end="03:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 16, 59): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 3, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 7, 18): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 8, 17), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), + BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), + BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), + BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), + BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 11, 15), + datetime(2014, 6, 30, 15), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 11, 15): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 2, 11, 15, 1): ( + datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 11, 15), + datetime(2014, 7, 3, 15), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 12): ( + datetime(2014, 7, 7, 15), + datetime(2014, 7, 7, 11, 15), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), + BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 8), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 16, 59): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 8), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 7, 18): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 8, 8), + ), + }, + ) + ) + + @pytest.mark.parametrize("case", opening_time_cases) + def test_opening_time(self, case): + _offsets, cases = case + for offset in _offsets: + for dt, (exp_next, exp_prev) in cases.items(): + assert offset._next_opening_time(dt) == exp_next + assert offset._prev_opening_time(dt) == exp_prev + + apply_cases = [] + apply_cases.append( + ( + BusinessHour(), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(4), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(-1), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), + datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), + datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(-4), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), + datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(start="13:00", end="16:00"), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), + datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=2, start="13:00", end="16:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), + datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), + datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start="13:00", end="16:00"), + { + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), + datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-3, start="10:00", end="16:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), + datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), + datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), + datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), + datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), + datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), + datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), + datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), + datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), + datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), + datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), + datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), + datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), + datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), + }, + ) + ) + + # long business hours (see gh-26381) + apply_cases.append( + ( + BusinessHour(n=4, start="00:00", end="23:00"), + { + datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), + datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), + datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), + datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), + datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), + datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-4, start="00:00", end="23:00"), + { + datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), + datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), + datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), + datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), + datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), + datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), + }, + ) + ) + + # multiple business hours + apply_cases.append( + ( + BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), + # out of business hours + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), + datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), + datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), + datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), + datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), + datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), + datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), + datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), + datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), + datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), + datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), + datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), + }, + ) + ) + + @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) + + apply_large_n_cases = [] + # A week later + apply_large_n_cases.append( + ( + BusinessHour(40), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), + datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), + datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), + datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), + datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), + datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), + datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), + datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), + datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), + datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), + datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), + datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), + }, + ) + ) + + # 3 days and 1 hour before + apply_large_n_cases.append( + ( + BusinessHour(-25), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), + datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), + datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), + datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), + datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), + datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), + datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), + datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), + datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), + datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), + datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), + }, + ) + ) + + # 5 days and 3 hours later + apply_large_n_cases.append( + ( + BusinessHour(28, start="21:00", end="02:00"), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), + datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), + datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), + datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), + datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), + datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), + datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), + datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), + datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), + datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), + }, + ) + ) + + # large n for multiple opening hours (3 days and 1 hour before) + apply_large_n_cases.append( + ( + BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), + datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), + datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), + datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), + datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), + datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), + datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), + datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), + datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), + datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), + datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), + datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), + }, + ) + ) + + # 5 days and 3 hours later + apply_large_n_cases.append( + ( + BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), + datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), + datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), + datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), + datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), + datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), + datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), + datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), + datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), + datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), + }, + ) + ) + + @pytest.mark.parametrize("case", apply_large_n_cases) + def test_apply_large_n(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_apply_nanoseconds(self): + tests = [] + + tests.append( + ( + BusinessHour(), + { + Timestamp("2014-07-04 15:00") + + Nano(5): Timestamp("2014-07-04 16:00") + + Nano(5), + Timestamp("2014-07-04 16:00") + + Nano(5): Timestamp("2014-07-07 09:00") + + Nano(5), + Timestamp("2014-07-04 16:00") + - Nano(5): Timestamp("2014-07-04 17:00") + - Nano(5), + }, + ) + ) + + tests.append( + ( + BusinessHour(-1), + { + Timestamp("2014-07-04 15:00") + + Nano(5): Timestamp("2014-07-04 14:00") + + Nano(5), + Timestamp("2014-07-04 10:00") + + Nano(5): Timestamp("2014-07-04 09:00") + + Nano(5), + Timestamp("2014-07-04 10:00") + - Nano(5): Timestamp("2014-07-03 17:00") + - Nano(5), + }, + ) + ) + + for offset, cases in tests: + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_datetimeindex(self): + idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") + idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") + idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") + expected = DatetimeIndex( + [ + "2014-07-04 15:00", + "2014-07-04 16:00", + "2014-07-07 09:00", + "2014-07-07 10:00", + "2014-07-07 11:00", + "2014-07-07 12:00", + "2014-07-07 13:00", + "2014-07-07 14:00", + "2014-07-07 15:00", + "2014-07-07 16:00", + "2014-07-08 09:00", + "2014-07-08 10:00", + ], + freq="BH", + ) + for idx in [idx1, idx2, idx3]: + tm.assert_index_equal(idx, expected) + + idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") + idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") + idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") + + expected = DatetimeIndex( + [ + "2014-07-04 15:45", + "2014-07-04 16:45", + "2014-07-07 09:45", + "2014-07-07 10:45", + "2014-07-07 11:45", + "2014-07-07 12:45", + "2014-07-07 13:45", + "2014-07-07 14:45", + "2014-07-07 15:45", + "2014-07-07 16:45", + "2014-07-08 09:45", + "2014-07-08 10:45", + ], + freq="BH", + ) + expected = idx1 + for idx in [idx1, idx2, idx3]: + tm.assert_index_equal(idx, expected) + + +class TestCustomBusinessHour(Base): + _offset = CustomBusinessHour + holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] + + def setup_method(self, method): + # 2014 Calendar to check custom holidays + # Sun Mon Tue Wed Thu Fri Sat + # 6/22 23 24 25 26 27 28 + # 29 30 7/1 2 3 4 5 + # 6 7 8 9 10 11 12 + self.d = datetime(2014, 7, 1, 10, 00) + self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") + + self.offset2 = CustomBusinessHour(holidays=self.holidays) + + def test_constructor_errors(self): + from datetime import time as dt_time + + with pytest.raises(ValueError): + CustomBusinessHour(start=dt_time(11, 0, 5)) + with pytest.raises(ValueError): + CustomBusinessHour(start="AAA") + with pytest.raises(ValueError): + CustomBusinessHour(start="14:00:05") + + 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.offset1) == "" + assert repr(self.offset2) == "" + + def test_with_offset(self): + expected = Timestamp("2014-07-01 13:00") + + assert self.d + CustomBusinessHour() * 3 == expected + assert self.d + CustomBusinessHour(n=3) == expected + + def test_eq(self): + for offset in [self.offset1, self.offset2]: + assert offset == offset + + assert CustomBusinessHour() != CustomBusinessHour(-1) + assert CustomBusinessHour(start="09:00") == CustomBusinessHour() + assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") + assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( + start="17:00", end="09:01" + ) + + assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( + weekmask="Mon Tue Wed Thu Fri" + ) + assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( + holidays=["2014-06-28"] + ) + + def test_sub(self): + # override the Base.test_sub implementation because self.offset2 is + # defined differently in this class than the test expects + pass + + def test_hash(self): + assert hash(self.offset1) == hash(self.offset1) + assert hash(self.offset2) == hash(self.offset2) + + def test_call(self): + assert self.offset1(self.d) == datetime(2014, 7, 1, 11) + assert self.offset2(self.d) == datetime(2014, 7, 1, 11) + + def testRollback1(self): + assert self.offset1.rollback(self.d) == self.d + assert self.offset2.rollback(self.d) == self.d + + d = datetime(2014, 7, 1, 0) + + # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) + assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) + + # 2014/6/30 and 2014/6/27 are holidays + assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) + + def testRollback2(self): + assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( + 2014, 7, 4, 17, 0 + ) + + def testRollforward1(self): + assert self.offset1.rollforward(self.d) == self.d + assert self.offset2.rollforward(self.d) == self.d + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) + + def testRollforward2(self): + assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( + 2014, 7, 7, 9 + ) + + def test_roll_date_object(self): + offset = BusinessHour() + + dt = datetime(2014, 7, 6, 15, 0) + + result = offset.rollback(dt) + assert result == datetime(2014, 7, 4, 17) + + result = offset.rollforward(dt) + assert result == datetime(2014, 7, 7, 9) + + normalize_cases = [] + normalize_cases.append( + ( + CustomBusinessHour(normalize=True, holidays=holidays), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3), + datetime(2014, 7, 1, 23): datetime(2014, 7, 3), + datetime(2014, 7, 1, 0): datetime(2014, 7, 1), + datetime(2014, 7, 4, 15): datetime(2014, 7, 4), + datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 7), + datetime(2014, 7, 6, 10): datetime(2014, 7, 7), + }, + ) + ) + + normalize_cases.append( + ( + CustomBusinessHour(-1, normalize=True, holidays=holidays), + { + datetime(2014, 7, 1, 8): datetime(2014, 6, 26), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1), + datetime(2014, 7, 1, 10): datetime(2014, 6, 26), + datetime(2014, 7, 1, 0): datetime(2014, 6, 26), + datetime(2014, 7, 7, 10): datetime(2014, 7, 4), + datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 4), + datetime(2014, 7, 6, 10): datetime(2014, 7, 4), + }, + ) + ) + + normalize_cases.append( + ( + CustomBusinessHour( + 1, normalize=True, start="17:00", end="04:00", holidays=holidays + ), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 2, 2): datetime(2014, 7, 2), + datetime(2014, 7, 2, 3): datetime(2014, 7, 3), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5), + datetime(2014, 7, 5, 2): datetime(2014, 7, 5), + datetime(2014, 7, 7, 2): datetime(2014, 7, 7), + datetime(2014, 7, 7, 17): datetime(2014, 7, 7), + }, + ) + ) + + @pytest.mark.parametrize("norm_cases", normalize_cases) + def test_normalize(self, norm_cases): + offset, cases = norm_cases + for dt, expected in cases.items(): + assert offset.apply(dt) == expected + + def test_onOffset(self): + tests = [] + + tests.append( + ( + CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), + { + datetime(2014, 7, 1, 9): False, + datetime(2014, 7, 1, 10): True, + datetime(2014, 7, 1, 15): True, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + for offset, cases in tests: + for dt, expected in cases.items(): + assert offset.onOffset(dt) == expected + + apply_cases = [] + apply_cases.append( + ( + CustomBusinessHour(holidays=holidays), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + CustomBusinessHour(4, holidays=holidays), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), + }, + ) + ) + + @pytest.mark.parametrize("apply_case", apply_cases) + def test_apply(self, apply_case): + offset, cases = apply_case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + nano_cases = [] + nano_cases.append( + ( + CustomBusinessHour(holidays=holidays), + { + Timestamp("2014-07-01 15:00") + + Nano(5): Timestamp("2014-07-01 16:00") + + Nano(5), + Timestamp("2014-07-01 16:00") + + Nano(5): Timestamp("2014-07-03 09:00") + + Nano(5), + Timestamp("2014-07-01 16:00") + - Nano(5): Timestamp("2014-07-01 17:00") + - Nano(5), + }, + ) + ) + + nano_cases.append( + ( + CustomBusinessHour(-1, holidays=holidays), + { + Timestamp("2014-07-01 15:00") + + Nano(5): Timestamp("2014-07-01 14:00") + + Nano(5), + Timestamp("2014-07-01 10:00") + + Nano(5): Timestamp("2014-07-01 09:00") + + Nano(5), + Timestamp("2014-07-01 10:00") + - Nano(5): Timestamp("2014-06-26 17:00") + - Nano(5), + }, + ) + ) + + @pytest.mark.parametrize("nano_case", nano_cases) + def test_apply_nanoseconds(self, nano_case): + offset, cases = nano_case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + +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>" + + if compat.PY37: + expected = "" + else: + 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_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): + 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_onOffset(self, case): + offset, d, expected = case + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + 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), + }, + ) + ) + + apply_cases.append( + ( + 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), + }, + ) + ) + + apply_cases.append( + ( + -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), + }, + ) + ) + + apply_cases.append( + ( + -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), + }, + ) + ) + + apply_cases.append( + ( + 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 + + +class CustomBusinessMonthBase: + def setup_method(self, method): + self.d = datetime(2008, 1, 1) + + self.offset = self._offset() + self.offset1 = self.offset + self.offset2 = self._offset(2) + + 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_roundtrip_pickle(self): + def _check_roundtrip(obj): + unpickled = tm.round_trip_pickle(obj) + assert unpickled == obj + + _check_roundtrip(self._offset()) + _check_roundtrip(self._offset(2)) + _check_roundtrip(self._offset() * 2) + + def test_copy(self): + # GH 17452 + off = self._offset(weekmask="Mon Wed Fri") + assert off == off.copy() + + +class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): + _offset = CBMonthEnd + + 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 * CustomBusinessMonthEnds>" + + def testCall(self): + assert self.offset2(self.d) == datetime(2008, 2, 29) + + def testRollback1(self): + assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) + + def testRollback2(self): + assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) + + def testRollforward1(self): + assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) + + def test_roll_date_object(self): + offset = CBMonthEnd() + + dt = date(2012, 9, 15) + + result = offset.rollback(dt) + assert result == datetime(2012, 8, 31) + + result = offset.rollforward(dt) + assert result == datetime(2012, 9, 28) + + 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 = [ + (CBMonthEnd(), datetime(2008, 1, 31), True), + (CBMonthEnd(), datetime(2008, 1, 1), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, d, expected = case + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 2, 7): datetime(2008, 2, 29), + }, + ) + ) + + apply_cases.append( + ( + 2 * CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 2, 29), + datetime(2008, 2, 7): datetime(2008, 3, 31), + }, + ) + ) + + apply_cases.append( + ( + -CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2007, 12, 31), + datetime(2008, 2, 8): datetime(2008, 1, 31), + }, + ) + ) + + apply_cases.append( + ( + -2 * CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2007, 11, 30), + datetime(2008, 2, 9): datetime(2007, 12, 31), + }, + ) + ) + + apply_cases.append( + ( + CBMonthEnd(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 2, 7): datetime(2008, 2, 29), + }, + ) + ) + + @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 + CBMonthEnd(10) + assert result == datetime(2013, 7, 31) + + result = dt + CDay(100) - CDay(100) + assert result == dt + + off = CBMonthEnd() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 7, 29) + assert rs == xp + + st = datetime(2011, 12, 18) + rs = st + off + xp = datetime(2012, 5, 31) + assert rs == xp + + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] + bm_offset = CBMonthEnd(holidays=holidays) + dt = datetime(2012, 1, 1) + assert dt + bm_offset == datetime(2012, 1, 30) + assert dt + 2 * bm_offset == datetime(2012, 2, 27) + + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_datetimeindex(self): + from pandas.tseries.holiday import USFederalHolidayCalendar + + hcal = USFederalHolidayCalendar() + freq = CBMonthEnd(calendar=hcal) + + assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ + 0 + ] == datetime(2012, 1, 31) + + +class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): + _offset = CBMonthBegin + + 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 * CustomBusinessMonthBegins>" + + def testCall(self): + assert self.offset2(self.d) == datetime(2008, 3, 3) + + def testRollback1(self): + assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) + + def testRollback2(self): + assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) + + def testRollforward1(self): + assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) + + def test_roll_date_object(self): + offset = CBMonthBegin() + + dt = date(2012, 9, 15) + + result = offset.rollback(dt) + assert result == datetime(2012, 9, 3) + + result = offset.rollforward(dt) + assert result == datetime(2012, 10, 1) + + 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 = [ + (CBMonthBegin(), datetime(2008, 1, 1), True), + (CBMonthBegin(), datetime(2008, 1, 31), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, dt, expected = case + assert_onOffset(offset, dt, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 2, 1), + datetime(2008, 2, 7): datetime(2008, 3, 3), + }, + ) + ) + + apply_cases.append( + ( + 2 * CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 3, 3), + datetime(2008, 2, 7): datetime(2008, 4, 1), + }, + ) + ) + + apply_cases.append( + ( + -CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2007, 12, 3), + datetime(2008, 2, 8): datetime(2008, 2, 1), + }, + ) + ) + + apply_cases.append( + ( + -2 * CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2007, 11, 1), + datetime(2008, 2, 9): datetime(2008, 1, 1), + }, + ) + ) + + apply_cases.append( + ( + CBMonthBegin(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 7): datetime(2008, 2, 1), + }, + ) + ) + + @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 + CBMonthBegin(10) + assert result == datetime(2013, 8, 1) + + result = dt + CDay(100) - CDay(100) + assert result == dt + + off = CBMonthBegin() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 7, 1) + assert rs == xp + + st = datetime(2011, 12, 18) + rs = st + off + + xp = datetime(2012, 6, 1) + assert rs == xp + + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] + bm_offset = CBMonthBegin(holidays=holidays) + dt = datetime(2012, 1, 1) + + assert dt + bm_offset == datetime(2012, 1, 2) + assert dt + 2 * bm_offset == datetime(2012, 2, 3) + + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_datetimeindex(self): + hcal = USFederalHolidayCalendar() + cbmb = CBMonthBegin(calendar=hcal) + assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ + 0 + ] == datetime(2012, 1, 3) + + +class TestWeek(Base): + _offset = Week + d = Timestamp(datetime(2008, 1, 2)) + offset1 = _offset() + offset2 = _offset(2) + + def test_repr(self): + assert repr(Week(weekday=0)) == "" + assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>" + assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>" + + def test_corner(self): + with pytest.raises(ValueError): + Week(weekday=7) + + with pytest.raises(ValueError, match="Day must be"): + Week(weekday=-1) + + def test_isAnchored(self): + assert Week(weekday=0).isAnchored() + assert not Week().isAnchored() + assert not Week(2, weekday=2).isAnchored() + assert not Week(2).isAnchored() + + offset_cases = [] + # not business week + offset_cases.append( + ( + Week(), + { + datetime(2008, 1, 1): datetime(2008, 1, 8), + datetime(2008, 1, 4): datetime(2008, 1, 11), + datetime(2008, 1, 5): datetime(2008, 1, 12), + datetime(2008, 1, 6): datetime(2008, 1, 13), + datetime(2008, 1, 7): datetime(2008, 1, 14), + }, + ) + ) + + # Mon + offset_cases.append( + ( + Week(weekday=0), + { + datetime(2007, 12, 31): datetime(2008, 1, 7), + 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, 14), + }, + ) + ) + + # n=0 -> roll forward. Mon + offset_cases.append( + ( + Week(0, weekday=0), + { + datetime(2007, 12, 31): datetime(2007, 12, 31), + 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, 7), + }, + ) + ) + + # n=0 -> roll forward. Mon + offset_cases.append( + ( + Week(-2, weekday=1), + { + datetime(2010, 4, 6): datetime(2010, 3, 23), + datetime(2010, 4, 8): datetime(2010, 3, 30), + datetime(2010, 4, 5): datetime(2010, 3, 23), + }, + ) + ) + + @pytest.mark.parametrize("case", offset_cases) + def test_offset(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + @pytest.mark.parametrize("weekday", range(7)) + def test_onOffset(self, weekday): + offset = Week(weekday=weekday) + + for day in range(1, 8): + date = datetime(2008, 1, day) + + if day % 7 == weekday: + expected = True + else: + expected = False + assert_onOffset(offset, date, expected) + + +class TestWeekOfMonth(Base): + _offset = WeekOfMonth + offset1 = _offset() + offset2 = _offset(2) + + def test_constructor(self): + with pytest.raises(ValueError, match="^Week"): + WeekOfMonth(n=1, week=4, weekday=0) + + with pytest.raises(ValueError, match="^Week"): + WeekOfMonth(n=1, week=-1, weekday=0) + + with pytest.raises(ValueError, match="^Day"): + WeekOfMonth(n=1, week=0, weekday=-1) + + with pytest.raises(ValueError, match="^Day"): + WeekOfMonth(n=1, week=0, weekday=-7) + + def test_repr(self): + assert ( + repr(WeekOfMonth(weekday=1, week=2)) == "" + ) + + def test_offset(self): + date1 = datetime(2011, 1, 4) # 1st Tuesday of Month + date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month + date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month + date4 = datetime(2011, 1, 25) # 4th Tuesday of Month + + # see for loop for structure + test_cases = [ + (-2, 2, 1, date1, datetime(2010, 11, 16)), + (-2, 2, 1, date2, datetime(2010, 11, 16)), + (-2, 2, 1, date3, datetime(2010, 11, 16)), + (-2, 2, 1, date4, datetime(2010, 12, 21)), + (-1, 2, 1, date1, datetime(2010, 12, 21)), + (-1, 2, 1, date2, datetime(2010, 12, 21)), + (-1, 2, 1, date3, datetime(2010, 12, 21)), + (-1, 2, 1, date4, datetime(2011, 1, 18)), + (0, 0, 1, date1, datetime(2011, 1, 4)), + (0, 0, 1, date2, datetime(2011, 2, 1)), + (0, 0, 1, date3, datetime(2011, 2, 1)), + (0, 0, 1, date4, datetime(2011, 2, 1)), + (0, 1, 1, date1, datetime(2011, 1, 11)), + (0, 1, 1, date2, datetime(2011, 1, 11)), + (0, 1, 1, date3, datetime(2011, 2, 8)), + (0, 1, 1, date4, datetime(2011, 2, 8)), + (0, 0, 1, date1, datetime(2011, 1, 4)), + (0, 1, 1, date2, datetime(2011, 1, 11)), + (0, 2, 1, date3, datetime(2011, 1, 18)), + (0, 3, 1, date4, datetime(2011, 1, 25)), + (1, 0, 0, date1, datetime(2011, 2, 7)), + (1, 0, 0, date2, datetime(2011, 2, 7)), + (1, 0, 0, date3, datetime(2011, 2, 7)), + (1, 0, 0, date4, datetime(2011, 2, 7)), + (1, 0, 1, date1, datetime(2011, 2, 1)), + (1, 0, 1, date2, datetime(2011, 2, 1)), + (1, 0, 1, date3, datetime(2011, 2, 1)), + (1, 0, 1, date4, datetime(2011, 2, 1)), + (1, 0, 2, date1, datetime(2011, 1, 5)), + (1, 0, 2, date2, datetime(2011, 2, 2)), + (1, 0, 2, date3, datetime(2011, 2, 2)), + (1, 0, 2, date4, datetime(2011, 2, 2)), + (1, 2, 1, date1, datetime(2011, 1, 18)), + (1, 2, 1, date2, datetime(2011, 1, 18)), + (1, 2, 1, date3, datetime(2011, 2, 15)), + (1, 2, 1, date4, datetime(2011, 2, 15)), + (2, 2, 1, date1, datetime(2011, 2, 15)), + (2, 2, 1, date2, datetime(2011, 2, 15)), + (2, 2, 1, date3, datetime(2011, 3, 15)), + (2, 2, 1, date4, datetime(2011, 3, 15)), + ] + + for n, week, weekday, dt, expected in test_cases: + offset = WeekOfMonth(n, week=week, weekday=weekday) + assert_offset_equal(offset, dt, expected) + + # try subtracting + result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2) + assert result == datetime(2011, 1, 12) + + result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2) + assert result == datetime(2011, 2, 2) + + on_offset_cases = [ + (0, 0, datetime(2011, 2, 7), True), + (0, 0, datetime(2011, 2, 6), False), + (0, 0, datetime(2011, 2, 14), False), + (1, 0, datetime(2011, 2, 14), True), + (0, 1, datetime(2011, 2, 1), True), + (0, 1, datetime(2011, 2, 8), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + week, weekday, dt, expected = case + offset = WeekOfMonth(week=week, weekday=weekday) + assert offset.onOffset(dt) == expected + + +class TestLastWeekOfMonth(Base): + _offset = LastWeekOfMonth + offset1 = _offset() + offset2 = _offset(2) + + def test_constructor(self): + with pytest.raises(ValueError, match="^N cannot be 0"): + LastWeekOfMonth(n=0, weekday=1) + + with pytest.raises(ValueError, match="^Day"): + LastWeekOfMonth(n=1, weekday=-1) + + with pytest.raises(ValueError, match="^Day"): + LastWeekOfMonth(n=1, weekday=7) + + def test_offset(self): + # Saturday + last_sat = datetime(2013, 8, 31) + next_sat = datetime(2013, 9, 28) + offset_sat = LastWeekOfMonth(n=1, weekday=5) + + one_day_before = last_sat + timedelta(days=-1) + assert one_day_before + offset_sat == last_sat + + one_day_after = last_sat + timedelta(days=+1) + assert one_day_after + offset_sat == next_sat + + # Test On that day + assert last_sat + offset_sat == next_sat + + # Thursday + + offset_thur = LastWeekOfMonth(n=1, weekday=3) + last_thurs = datetime(2013, 1, 31) + next_thurs = datetime(2013, 2, 28) + + one_day_before = last_thurs + timedelta(days=-1) + assert one_day_before + offset_thur == last_thurs + + one_day_after = last_thurs + timedelta(days=+1) + assert one_day_after + offset_thur == next_thurs + + # Test on that day + assert last_thurs + offset_thur == next_thurs + + three_before = last_thurs + timedelta(days=-3) + assert three_before + offset_thur == last_thurs + + two_after = last_thurs + timedelta(days=+2) + assert two_after + offset_thur == next_thurs + + offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN) + assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25) + + on_offset_cases = [ + (WeekDay.SUN, datetime(2013, 1, 27), True), + (WeekDay.SAT, datetime(2013, 3, 30), True), + (WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon + (WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN + (WeekDay.MON, datetime(2013, 2, 25), True), + (WeekDay.SAT, datetime(2013, 11, 30), True), + (WeekDay.SAT, datetime(2006, 8, 26), True), + (WeekDay.SAT, datetime(2007, 8, 25), True), + (WeekDay.SAT, datetime(2008, 8, 30), True), + (WeekDay.SAT, datetime(2009, 8, 29), True), + (WeekDay.SAT, datetime(2010, 8, 28), True), + (WeekDay.SAT, datetime(2011, 8, 27), True), + (WeekDay.SAT, datetime(2019, 8, 31), True), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + weekday, dt, expected = case + offset = LastWeekOfMonth(weekday=weekday) + assert offset.onOffset(dt) == expected + + +class TestSemiMonthEnd(Base): + _offset = SemiMonthEnd + offset1 = _offset() + offset2 = _offset(2) + + def test_offset_whole_year(self): + dates = ( + datetime(2007, 12, 31), + datetime(2008, 1, 15), + datetime(2008, 1, 31), + datetime(2008, 2, 15), + datetime(2008, 2, 29), + datetime(2008, 3, 15), + datetime(2008, 3, 31), + datetime(2008, 4, 15), + datetime(2008, 4, 30), + datetime(2008, 5, 15), + datetime(2008, 5, 31), + datetime(2008, 6, 15), + datetime(2008, 6, 30), + datetime(2008, 7, 15), + datetime(2008, 7, 31), + datetime(2008, 8, 15), + datetime(2008, 8, 31), + datetime(2008, 9, 15), + datetime(2008, 9, 30), + datetime(2008, 10, 15), + datetime(2008, 10, 31), + datetime(2008, 11, 15), + datetime(2008, 11, 30), + datetime(2008, 12, 15), + datetime(2008, 12, 31), + ) + + for base, exp_date in zip(dates[:-1], dates[1:]): + assert_offset_equal(SemiMonthEnd(), base, exp_date) + + # ensure .apply_index works as expected + s = DatetimeIndex(dates[:-1]) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = SemiMonthEnd().apply_index(s) + + exp = DatetimeIndex(dates[1:]) + tm.assert_index_equal(result, exp) + + # ensure generating a range with DatetimeIndex gives same result + result = date_range(start=dates[0], end=dates[-1], freq="SM") + exp = DatetimeIndex(dates) + tm.assert_index_equal(result, exp) + + offset_cases = [] + offset_cases.append( + ( + SemiMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 1, 15), + datetime(2008, 1, 15): datetime(2008, 1, 31), + datetime(2008, 1, 31): datetime(2008, 2, 15), + datetime(2006, 12, 14): datetime(2006, 12, 15), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2007, 1, 15), + datetime(2007, 1, 1): datetime(2007, 1, 15), + datetime(2006, 12, 1): datetime(2006, 12, 15), + datetime(2006, 12, 15): datetime(2006, 12, 31), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(day_of_month=20), + { + datetime(2008, 1, 1): datetime(2008, 1, 20), + datetime(2008, 1, 15): datetime(2008, 1, 20), + datetime(2008, 1, 21): datetime(2008, 1, 31), + datetime(2008, 1, 31): datetime(2008, 2, 20), + datetime(2006, 12, 14): datetime(2006, 12, 20), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2007, 1, 20), + datetime(2007, 1, 1): datetime(2007, 1, 20), + datetime(2006, 12, 1): datetime(2006, 12, 20), + datetime(2006, 12, 15): datetime(2006, 12, 20), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 15), + datetime(2008, 1, 16): datetime(2008, 1, 31), + datetime(2008, 1, 15): datetime(2008, 1, 15), + datetime(2008, 1, 31): datetime(2008, 1, 31), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2006, 12, 31), + datetime(2007, 1, 1): datetime(2007, 1, 15), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(0, day_of_month=16), + { + datetime(2008, 1, 1): datetime(2008, 1, 16), + datetime(2008, 1, 16): datetime(2008, 1, 16), + datetime(2008, 1, 15): datetime(2008, 1, 16), + datetime(2008, 1, 31): datetime(2008, 1, 31), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2006, 12, 31), + datetime(2007, 1, 1): datetime(2007, 1, 16), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(2), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 1, 31): datetime(2008, 2, 29), + datetime(2006, 12, 29): datetime(2007, 1, 15), + datetime(2006, 12, 31): datetime(2007, 1, 31), + datetime(2007, 1, 1): datetime(2007, 1, 31), + datetime(2007, 1, 16): datetime(2007, 2, 15), + datetime(2006, 11, 1): datetime(2006, 11, 30), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(-1), + { + datetime(2007, 1, 1): datetime(2006, 12, 31), + datetime(2008, 6, 30): datetime(2008, 6, 15), + datetime(2008, 12, 31): datetime(2008, 12, 15), + datetime(2006, 12, 29): datetime(2006, 12, 15), + datetime(2006, 12, 30): datetime(2006, 12, 15), + datetime(2007, 1, 1): datetime(2006, 12, 31), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(-1, day_of_month=4), + { + datetime(2007, 1, 1): datetime(2006, 12, 31), + datetime(2007, 1, 4): datetime(2006, 12, 31), + datetime(2008, 6, 30): datetime(2008, 6, 4), + datetime(2008, 12, 31): datetime(2008, 12, 4), + datetime(2006, 12, 5): datetime(2006, 12, 4), + datetime(2006, 12, 30): datetime(2006, 12, 4), + datetime(2007, 1, 1): datetime(2006, 12, 31), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(-2), + { + datetime(2007, 1, 1): datetime(2006, 12, 15), + datetime(2008, 6, 30): datetime(2008, 5, 31), + datetime(2008, 3, 15): datetime(2008, 2, 15), + datetime(2008, 12, 31): datetime(2008, 11, 30), + datetime(2006, 12, 29): datetime(2006, 11, 30), + datetime(2006, 12, 14): datetime(2006, 11, 15), + datetime(2007, 1, 1): datetime(2006, 12, 15), + }, + ) + ) + + @pytest.mark.parametrize("case", offset_cases) + def test_offset(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + @pytest.mark.parametrize("case", offset_cases) + def test_apply_index(self, case): + offset, cases = case + s = DatetimeIndex(cases.keys()) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = offset.apply_index(s) + + exp = DatetimeIndex(cases.values()) + tm.assert_index_equal(result, exp) + + on_offset_cases = [ + (datetime(2007, 12, 31), True), + (datetime(2007, 12, 15), True), + (datetime(2007, 12, 14), False), + (datetime(2007, 12, 1), False), + (datetime(2008, 2, 29), True), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + dt, expected = case + assert_onOffset(SemiMonthEnd(), dt, expected) + + @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) + def test_vectorized_offset_addition(self, klass): + s = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthEnd() + result2 = SemiMonthEnd() + s + + exp = klass( + [ + Timestamp("2000-01-31 00:15:00", tz="US/Central"), + Timestamp("2000-02-29", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + s = klass( + [ + Timestamp("2000-01-01 00:15:00", tz="US/Central"), + Timestamp("2000-02-01", tz="US/Central"), + ], + name="a", + ) + + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthEnd() + result2 = SemiMonthEnd() + s + + exp = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + +class TestSemiMonthBegin(Base): + _offset = SemiMonthBegin + offset1 = _offset() + offset2 = _offset(2) + + def test_offset_whole_year(self): + dates = ( + datetime(2007, 12, 15), + datetime(2008, 1, 1), + datetime(2008, 1, 15), + datetime(2008, 2, 1), + datetime(2008, 2, 15), + datetime(2008, 3, 1), + datetime(2008, 3, 15), + datetime(2008, 4, 1), + datetime(2008, 4, 15), + datetime(2008, 5, 1), + datetime(2008, 5, 15), + datetime(2008, 6, 1), + datetime(2008, 6, 15), + datetime(2008, 7, 1), + datetime(2008, 7, 15), + datetime(2008, 8, 1), + datetime(2008, 8, 15), + datetime(2008, 9, 1), + datetime(2008, 9, 15), + datetime(2008, 10, 1), + datetime(2008, 10, 15), + datetime(2008, 11, 1), + datetime(2008, 11, 15), + datetime(2008, 12, 1), + datetime(2008, 12, 15), + ) + + for base, exp_date in zip(dates[:-1], dates[1:]): + assert_offset_equal(SemiMonthBegin(), base, exp_date) + + # ensure .apply_index works as expected + s = DatetimeIndex(dates[:-1]) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = SemiMonthBegin().apply_index(s) + + exp = DatetimeIndex(dates[1:]) + tm.assert_index_equal(result, exp) + + # ensure generating a range with DatetimeIndex gives same result + result = date_range(start=dates[0], end=dates[-1], freq="SMS") + exp = DatetimeIndex(dates) + tm.assert_index_equal(result, exp) + + offset_cases = [] + offset_cases.append( + ( + SemiMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 1, 15), + datetime(2008, 1, 15): datetime(2008, 2, 1), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 14): datetime(2006, 12, 15), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 31): datetime(2007, 1, 1), + datetime(2007, 1, 1): datetime(2007, 1, 15), + datetime(2006, 12, 1): datetime(2006, 12, 15), + datetime(2006, 12, 15): datetime(2007, 1, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(day_of_month=20), + { + datetime(2008, 1, 1): datetime(2008, 1, 20), + datetime(2008, 1, 15): datetime(2008, 1, 20), + datetime(2008, 1, 21): datetime(2008, 2, 1), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 14): datetime(2006, 12, 20), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 31): datetime(2007, 1, 1), + datetime(2007, 1, 1): datetime(2007, 1, 20), + datetime(2006, 12, 1): datetime(2006, 12, 20), + datetime(2006, 12, 15): datetime(2006, 12, 20), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 16): datetime(2008, 2, 1), + datetime(2008, 1, 15): datetime(2008, 1, 15), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 2): datetime(2006, 12, 15), + datetime(2007, 1, 1): datetime(2007, 1, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(0, day_of_month=16), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 16): datetime(2008, 1, 16), + datetime(2008, 1, 15): datetime(2008, 1, 16), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 31): datetime(2007, 1, 1), + datetime(2007, 1, 5): datetime(2007, 1, 16), + datetime(2007, 1, 1): datetime(2007, 1, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(2), + { + datetime(2008, 1, 1): datetime(2008, 2, 1), + datetime(2008, 1, 31): datetime(2008, 2, 15), + datetime(2006, 12, 1): datetime(2007, 1, 1), + datetime(2006, 12, 29): datetime(2007, 1, 15), + datetime(2006, 12, 15): datetime(2007, 1, 15), + datetime(2007, 1, 1): datetime(2007, 2, 1), + datetime(2007, 1, 16): datetime(2007, 2, 15), + datetime(2006, 11, 1): datetime(2006, 12, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(-1), + { + datetime(2007, 1, 1): datetime(2006, 12, 15), + datetime(2008, 6, 30): datetime(2008, 6, 15), + datetime(2008, 6, 14): datetime(2008, 6, 1), + datetime(2008, 12, 31): datetime(2008, 12, 15), + datetime(2006, 12, 29): datetime(2006, 12, 15), + datetime(2006, 12, 15): datetime(2006, 12, 1), + datetime(2007, 1, 1): datetime(2006, 12, 15), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(-1, day_of_month=4), + { + datetime(2007, 1, 1): datetime(2006, 12, 4), + datetime(2007, 1, 4): datetime(2007, 1, 1), + datetime(2008, 6, 30): datetime(2008, 6, 4), + datetime(2008, 12, 31): datetime(2008, 12, 4), + datetime(2006, 12, 5): datetime(2006, 12, 4), + datetime(2006, 12, 30): datetime(2006, 12, 4), + datetime(2006, 12, 2): datetime(2006, 12, 1), + datetime(2007, 1, 1): datetime(2006, 12, 4), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(-2), + { + datetime(2007, 1, 1): datetime(2006, 12, 1), + datetime(2008, 6, 30): datetime(2008, 6, 1), + datetime(2008, 6, 14): datetime(2008, 5, 15), + datetime(2008, 12, 31): datetime(2008, 12, 1), + datetime(2006, 12, 29): datetime(2006, 12, 1), + datetime(2006, 12, 15): datetime(2006, 11, 15), + datetime(2007, 1, 1): datetime(2006, 12, 1), + }, + ) + ) + + @pytest.mark.parametrize("case", offset_cases) + def test_offset(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + @pytest.mark.parametrize("case", offset_cases) + def test_apply_index(self, case): + offset, cases = case + s = DatetimeIndex(cases.keys()) + + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = offset.apply_index(s) + + exp = DatetimeIndex(cases.values()) + tm.assert_index_equal(result, exp) + + on_offset_cases = [ + (datetime(2007, 12, 1), True), + (datetime(2007, 12, 15), True), + (datetime(2007, 12, 14), False), + (datetime(2007, 12, 31), False), + (datetime(2008, 2, 15), True), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + dt, expected = case + assert_onOffset(SemiMonthBegin(), dt, expected) + + @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) + def test_vectorized_offset_addition(self, klass): + s = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthBegin() + result2 = SemiMonthBegin() + s + + exp = klass( + [ + Timestamp("2000-02-01 00:15:00", tz="US/Central"), + Timestamp("2000-03-01", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + s = klass( + [ + Timestamp("2000-01-01 00:15:00", tz="US/Central"), + Timestamp("2000-02-01", tz="US/Central"), + ], + name="a", + ) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthBegin() + result2 = SemiMonthBegin() + s + + exp = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + +def test_Easter(): + assert_offset_equal(Easter(), datetime(2010, 1, 1), datetime(2010, 4, 4)) + assert_offset_equal(Easter(), datetime(2010, 4, 5), datetime(2011, 4, 24)) + assert_offset_equal(Easter(2), datetime(2010, 1, 1), datetime(2011, 4, 24)) + + assert_offset_equal(Easter(), datetime(2010, 4, 4), datetime(2011, 4, 24)) + assert_offset_equal(Easter(2), datetime(2010, 4, 4), datetime(2012, 4, 8)) + + assert_offset_equal(-Easter(), datetime(2011, 1, 1), datetime(2010, 4, 4)) + assert_offset_equal(-Easter(), datetime(2010, 4, 5), datetime(2010, 4, 4)) + assert_offset_equal(-Easter(2), datetime(2011, 1, 1), datetime(2009, 4, 12)) + + assert_offset_equal(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)) + assert_offset_equal(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)) + + +class TestOffsetNames: + def test_get_offset_name(self): + assert BDay().freqstr == "B" + assert BDay(2).freqstr == "2B" + assert BMonthEnd().freqstr == "BM" + assert Week(weekday=0).freqstr == "W-MON" + assert Week(weekday=1).freqstr == "W-TUE" + assert Week(weekday=2).freqstr == "W-WED" + assert Week(weekday=3).freqstr == "W-THU" + assert Week(weekday=4).freqstr == "W-FRI" + + assert LastWeekOfMonth(weekday=WeekDay.SUN).freqstr == "LWOM-SUN" + + +def test_get_offset(): + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset("gibberish") + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset("QS-JAN-B") + + pairs = [ + ("B", BDay()), + ("b", BDay()), + ("bm", BMonthEnd()), + ("Bm", BMonthEnd()), + ("W-MON", Week(weekday=0)), + ("W-TUE", Week(weekday=1)), + ("W-WED", Week(weekday=2)), + ("W-THU", Week(weekday=3)), + ("W-FRI", Week(weekday=4)), + ] + + for name, expected in pairs: + offset = get_offset(name) + assert ( + offset == expected + ), "Expected {name!r} to yield {expected!r} (actual: {offset!r})".format( + name=name, expected=expected, offset=offset + ) + + +def test_get_offset_legacy(): + pairs = [("w@Sat", Week(weekday=5))] + for name, expected in pairs: + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset(name) + + +class TestOffsetAliases: + def setup_method(self, method): + _offset_map.clear() + + def test_alias_equality(self): + for k, v in _offset_map.items(): + if v is None: + continue + assert k == v.copy() + + def test_rule_code(self): + lst = ["M", "MS", "BM", "BMS", "D", "B", "H", "T", "S", "L", "U"] + for k in lst: + assert k == get_offset(k).rule_code + # should be cached - this is kind of an internals test... + assert k in _offset_map + assert k == (get_offset(k) * 3).rule_code + + suffix_lst = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] + base = "W" + for v in suffix_lst: + alias = "-".join([base, v]) + assert alias == get_offset(alias).rule_code + assert alias == (get_offset(alias) * 5).rule_code + + suffix_lst = [ + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC", + ] + base_lst = ["A", "AS", "BA", "BAS", "Q", "QS", "BQ", "BQS"] + for base in base_lst: + for v in suffix_lst: + alias = "-".join([base, v]) + assert alias == get_offset(alias).rule_code + assert alias == (get_offset(alias) * 5).rule_code + + lst = ["M", "D", "B", "H", "T", "S", "L", "U"] + for k in lst: + code, stride = get_freq_code("3" + k) + assert isinstance(code, int) + assert stride == 3 + assert k == get_freq_str(code) + + +def test_dateoffset_misc(): + oset = offsets.DateOffset(months=2, days=4) + # it works + oset.freqstr + + assert not offsets.DateOffset(months=2) == 2 + + +def test_freq_offsets(): + off = BDay(1, offset=timedelta(0, 1800)) + assert off.freqstr == "B+30Min" + + off = BDay(1, offset=timedelta(0, -1800)) + assert off.freqstr == "B-30Min" + + +class TestReprNames: + def test_str_for_named_is_name(self): + # look at all the amazing combinations! + month_prefixes = ["A", "AS", "BA", "BAS", "Q", "BQ", "BQS", "QS"] + names = [ + prefix + "-" + month + for prefix in month_prefixes + for month in [ + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC", + ] + ] + days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] + names += ["W-" + day for day in days] + names += ["WOM-" + week + day for week in ("1", "2", "3", "4") for day in days] + _offset_map.clear() + for name in names: + offset = get_offset(name) + assert offset.freqstr == name + + +def get_utc_offset_hours(ts): + # take a Timestamp and compute total hours of utc offset + o = ts.utcoffset() + return (o.days * 24 * 3600 + o.seconds) / 3600.0 + + +class TestDST: + """ + test DateOffset additions over Daylight Savings Time + """ + + # one microsecond before the DST transition + ts_pre_fallback = "2013-11-03 01:59:59.999999" + ts_pre_springfwd = "2013-03-10 01:59:59.999999" + + # test both basic names and dateutil timezones + timezone_utc_offsets = { + "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), + "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), + } + valid_date_offsets_singular = [ + "weekday", + "day", + "hour", + "minute", + "second", + "microsecond", + ] + valid_date_offsets_plural = [ + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + ] + + def _test_all_offsets(self, n, **kwds): + valid_offsets = ( + self.valid_date_offsets_plural + if n > 1 + else self.valid_date_offsets_singular + ) + + for name in valid_offsets: + self._test_offset(offset_name=name, offset_n=n, **kwds) + + def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): + offset = DateOffset(**{offset_name: offset_n}) + + t = tstart + offset + if expected_utc_offset is not None: + assert get_utc_offset_hours(t) == expected_utc_offset + + if offset_name == "weeks": + # dates should match + assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() + # expect the same day of week, hour of day, minute, second, ... + assert ( + t.dayofweek == tstart.dayofweek + and t.hour == tstart.hour + and t.minute == tstart.minute + and t.second == tstart.second + ) + elif offset_name == "days": + # dates should match + assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() + # expect the same hour of day, minute, second, ... + assert ( + t.hour == tstart.hour + and t.minute == tstart.minute + and t.second == tstart.second + ) + elif offset_name in self.valid_date_offsets_singular: + # expect the singular offset value to match between tstart and t + datepart_offset = getattr( + t, offset_name if offset_name != "weekday" else "dayofweek" + ) + assert datepart_offset == offset.kwds[offset_name] + else: + # the offset should be the same as if it was done in UTC + assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") + + def _make_timestamp(self, string, hrs_offset, tz): + if hrs_offset >= 0: + offset_string = "{hrs:02d}00".format(hrs=hrs_offset) + else: + offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) + return Timestamp(string + offset_string).tz_convert(tz) + + def test_springforward_plural(self): + # test moving from standard to daylight savings + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + hrs_post = utc_offsets["utc_offset_daylight"] + self._test_all_offsets( + n=3, + tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), + expected_utc_offset=hrs_post, + ) + + def test_fallback_singular(self): + # in the case of singular offsets, we don't necessarily know which utc + # offset the new Timestamp will wind up in (the tz for 1 month may be + # different from 1 second) so we don't specify an expected_utc_offset + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + self._test_all_offsets( + n=1, + tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), + expected_utc_offset=None, + ) + + def test_springforward_singular(self): + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + self._test_all_offsets( + n=1, + tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), + expected_utc_offset=None, + ) + + offset_classes = { + MonthBegin: ["11/2/2012", "12/1/2012"], + MonthEnd: ["11/2/2012", "11/30/2012"], + BMonthBegin: ["11/2/2012", "12/3/2012"], + BMonthEnd: ["11/2/2012", "11/30/2012"], + CBMonthBegin: ["11/2/2012", "12/3/2012"], + CBMonthEnd: ["11/2/2012", "11/30/2012"], + SemiMonthBegin: ["11/2/2012", "11/15/2012"], + SemiMonthEnd: ["11/2/2012", "11/15/2012"], + Week: ["11/2/2012", "11/9/2012"], + YearBegin: ["11/2/2012", "1/1/2013"], + YearEnd: ["11/2/2012", "12/31/2012"], + BYearBegin: ["11/2/2012", "1/1/2013"], + BYearEnd: ["11/2/2012", "12/31/2012"], + QuarterBegin: ["11/2/2012", "12/1/2012"], + QuarterEnd: ["11/2/2012", "12/31/2012"], + BQuarterBegin: ["11/2/2012", "12/3/2012"], + BQuarterEnd: ["11/2/2012", "12/31/2012"], + Day: ["11/4/2012", "11/4/2012 23:00"], + }.items() + + @pytest.mark.parametrize("tup", offset_classes) + def test_all_offset_classes(self, tup): + offset, test_values = tup + + first = Timestamp(test_values[0], tz="US/Eastern") + offset() + second = Timestamp(test_values[1], tz="US/Eastern") + assert first == second + + +# --------------------------------------------------------------------- +def test_get_offset_day_error(): + # subclass of _BaseOffset must override _day_opt attribute, or we should + # get a NotImplementedError + + with pytest.raises(NotImplementedError): + DateOffset()._get_offset_day(datetime.now()) + + +def test_valid_default_arguments(offset_types): + # GH#19142 check that the calling the constructors without passing + # any keyword arguments produce valid offsets + cls = offset_types + cls() + + +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_month_attributes(kwd, month_classes): + # GH#18226 + cls = month_classes + # check that we cannot create e.g. MonthEnd(weeks=3) + with pytest.raises(TypeError): + cls(**{kwd: 3}) + + +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_relativedelta_kwargs(kwd): + # Check that all the arguments specified in liboffsets.relativedelta_kwds + # are in fact valid relativedelta keyword args + DateOffset(**{kwd: 1}) + + +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_tick_attributes(kwd, tick_classes): + # GH#18226 + cls = tick_classes + # check that we cannot create e.g. Hour(weeks=3) + with pytest.raises(TypeError): + cls(**{kwd: 3}) + + +def test_validate_n_error(): + with pytest.raises(TypeError): + DateOffset(n="Doh!") + + with pytest.raises(TypeError): + MonthBegin(n=timedelta(1)) + + with pytest.raises(TypeError): + BDay(n=np.array([1, 2], dtype=np.int64)) + + +def test_require_integers(offset_types): + cls = offset_types + with pytest.raises(ValueError): + cls(n=1.5) + + +def test_tick_normalize_raises(tick_classes): + # check that trying to create a Tick object with normalize=True raises + # GH#21427 + cls = tick_classes + with pytest.raises(ValueError): + cls(n=3, normalize=True) + + +def test_weeks_onoffset(): + # GH#18510 Week with weekday = None, normalize = False should always + # be onOffset + offset = Week(n=2, weekday=None) + ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + # negative n + offset = Week(n=2, weekday=None) + ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + +def test_weekofmonth_onoffset(): + # GH#18864 + # Make sure that nanoseconds don't trip up onOffset (and with it apply) + offset = WeekOfMonth(n=2, week=2, weekday=0) + ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + # negative n + offset = WeekOfMonth(n=-3, week=1, weekday=0) + ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + +def test_last_week_of_month_on_offset(): + # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth + offset = LastWeekOfMonth(n=4, weekday=6) + ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") + slow = (ts + offset) - offset == ts + fast = offset.onOffset(ts) + assert fast == slow + + # negative n + offset = LastWeekOfMonth(n=-4, weekday=5) + ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") + slow = (ts + offset) - offset == ts + fast = offset.onOffset(ts) + assert fast == slow + + +def test_week_add_invalid(): + # Week with weekday should raise TypeError and _not_ AttributeError + # when adding invalid offset + offset = Week(weekday=1) + other = Day() + with pytest.raises(TypeError, match="Cannot add"): + offset + other From 96ed14374e4f29422b075a69251113ea7cebdb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Mon, 11 Nov 2019 14:59:07 +0100 Subject: [PATCH 02/12] Initial separation --- .../tseries/offsets/test_business_offsets.py | 884 +----- .../tseries/offsets/test_date_offsets.py | 2490 ----------------- 2 files changed, 2 insertions(+), 3372 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index bed8d2461f65d..3708c2c9397bd 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -31,7 +31,6 @@ import pandas.tseries.offsets as offsets from pandas.tseries.offsets import ( FY5253, - BaseOffset, BDay, BMonthBegin, BMonthEnd, @@ -44,23 +43,7 @@ CBMonthEnd, CDay, CustomBusinessHour, - DateOffset, - Day, - Easter, - FY5253Quarter, - LastWeekOfMonth, - MonthBegin, - MonthEnd, - Nano, - QuarterBegin, - QuarterEnd, - SemiMonthBegin, - SemiMonthEnd, - Tick, - Week, - WeekOfMonth, - YearBegin, - YearEnd, + FY5253Quarter ) from .common import assert_offset_equal, assert_onOffset @@ -89,7 +72,7 @@ def test_to_M8(): ##### -# DateOffset Tests +# BusinessOffset Tests ##### _ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]] @@ -623,44 +606,6 @@ def test_pickle_v0_15_2(self, datapath): tm.assert_dict_equal(offsets, read_pickle(pickle_path)) -class TestDateOffset(Base): - def setup_method(self, method): - self.d = Timestamp(datetime(2008, 1, 2)) - _offset_map.clear() - - def test_repr(self): - repr(DateOffset()) - repr(DateOffset(2)) - repr(2 * DateOffset()) - repr(2 * DateOffset(months=2)) - - def test_mul(self): - assert DateOffset(2) == 2 * DateOffset(1) - assert DateOffset(2) == DateOffset(1) * 2 - - def test_constructor(self): - - assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2) - assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2) - - assert (self.d + DateOffset(2)) == datetime(2008, 1, 4) - - assert not DateOffset(2).isAnchored() - assert DateOffset(1).isAnchored() - - d = datetime(2008, 1, 31) - assert (d + DateOffset(months=1)) == datetime(2008, 2, 29) - - def test_copy(self): - assert DateOffset(months=2).copy() == DateOffset(months=2) - - def test_eq(self): - offset1 = DateOffset(days=1) - offset2 = DateOffset(days=365) - - assert offset1 != offset2 - - class TestBusinessDay(Base): _offset = BDay @@ -3122,831 +3067,11 @@ def test_datetimeindex(self): ] == datetime(2012, 1, 3) -class TestWeek(Base): - _offset = Week - d = Timestamp(datetime(2008, 1, 2)) - offset1 = _offset() - offset2 = _offset(2) - - def test_repr(self): - assert repr(Week(weekday=0)) == "" - assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>" - assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>" - - def test_corner(self): - with pytest.raises(ValueError): - Week(weekday=7) - - with pytest.raises(ValueError, match="Day must be"): - Week(weekday=-1) - - def test_isAnchored(self): - assert Week(weekday=0).isAnchored() - assert not Week().isAnchored() - assert not Week(2, weekday=2).isAnchored() - assert not Week(2).isAnchored() - - offset_cases = [] - # not business week - offset_cases.append( - ( - Week(), - { - datetime(2008, 1, 1): datetime(2008, 1, 8), - datetime(2008, 1, 4): datetime(2008, 1, 11), - datetime(2008, 1, 5): datetime(2008, 1, 12), - datetime(2008, 1, 6): datetime(2008, 1, 13), - datetime(2008, 1, 7): datetime(2008, 1, 14), - }, - ) - ) - - # Mon - offset_cases.append( - ( - Week(weekday=0), - { - datetime(2007, 12, 31): datetime(2008, 1, 7), - 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, 14), - }, - ) - ) - - # n=0 -> roll forward. Mon - offset_cases.append( - ( - Week(0, weekday=0), - { - datetime(2007, 12, 31): datetime(2007, 12, 31), - 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, 7), - }, - ) - ) - - # n=0 -> roll forward. Mon - offset_cases.append( - ( - Week(-2, weekday=1), - { - datetime(2010, 4, 6): datetime(2010, 3, 23), - datetime(2010, 4, 8): datetime(2010, 3, 30), - datetime(2010, 4, 5): datetime(2010, 3, 23), - }, - ) - ) - - @pytest.mark.parametrize("case", offset_cases) - def test_offset(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - @pytest.mark.parametrize("weekday", range(7)) - def test_onOffset(self, weekday): - offset = Week(weekday=weekday) - - for day in range(1, 8): - date = datetime(2008, 1, day) - - if day % 7 == weekday: - expected = True - else: - expected = False - assert_onOffset(offset, date, expected) - - -class TestWeekOfMonth(Base): - _offset = WeekOfMonth - offset1 = _offset() - offset2 = _offset(2) - - def test_constructor(self): - with pytest.raises(ValueError, match="^Week"): - WeekOfMonth(n=1, week=4, weekday=0) - - with pytest.raises(ValueError, match="^Week"): - WeekOfMonth(n=1, week=-1, weekday=0) - - with pytest.raises(ValueError, match="^Day"): - WeekOfMonth(n=1, week=0, weekday=-1) - - with pytest.raises(ValueError, match="^Day"): - WeekOfMonth(n=1, week=0, weekday=-7) - - def test_repr(self): - assert ( - repr(WeekOfMonth(weekday=1, week=2)) == "" - ) - - def test_offset(self): - date1 = datetime(2011, 1, 4) # 1st Tuesday of Month - date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month - date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month - date4 = datetime(2011, 1, 25) # 4th Tuesday of Month - - # see for loop for structure - test_cases = [ - (-2, 2, 1, date1, datetime(2010, 11, 16)), - (-2, 2, 1, date2, datetime(2010, 11, 16)), - (-2, 2, 1, date3, datetime(2010, 11, 16)), - (-2, 2, 1, date4, datetime(2010, 12, 21)), - (-1, 2, 1, date1, datetime(2010, 12, 21)), - (-1, 2, 1, date2, datetime(2010, 12, 21)), - (-1, 2, 1, date3, datetime(2010, 12, 21)), - (-1, 2, 1, date4, datetime(2011, 1, 18)), - (0, 0, 1, date1, datetime(2011, 1, 4)), - (0, 0, 1, date2, datetime(2011, 2, 1)), - (0, 0, 1, date3, datetime(2011, 2, 1)), - (0, 0, 1, date4, datetime(2011, 2, 1)), - (0, 1, 1, date1, datetime(2011, 1, 11)), - (0, 1, 1, date2, datetime(2011, 1, 11)), - (0, 1, 1, date3, datetime(2011, 2, 8)), - (0, 1, 1, date4, datetime(2011, 2, 8)), - (0, 0, 1, date1, datetime(2011, 1, 4)), - (0, 1, 1, date2, datetime(2011, 1, 11)), - (0, 2, 1, date3, datetime(2011, 1, 18)), - (0, 3, 1, date4, datetime(2011, 1, 25)), - (1, 0, 0, date1, datetime(2011, 2, 7)), - (1, 0, 0, date2, datetime(2011, 2, 7)), - (1, 0, 0, date3, datetime(2011, 2, 7)), - (1, 0, 0, date4, datetime(2011, 2, 7)), - (1, 0, 1, date1, datetime(2011, 2, 1)), - (1, 0, 1, date2, datetime(2011, 2, 1)), - (1, 0, 1, date3, datetime(2011, 2, 1)), - (1, 0, 1, date4, datetime(2011, 2, 1)), - (1, 0, 2, date1, datetime(2011, 1, 5)), - (1, 0, 2, date2, datetime(2011, 2, 2)), - (1, 0, 2, date3, datetime(2011, 2, 2)), - (1, 0, 2, date4, datetime(2011, 2, 2)), - (1, 2, 1, date1, datetime(2011, 1, 18)), - (1, 2, 1, date2, datetime(2011, 1, 18)), - (1, 2, 1, date3, datetime(2011, 2, 15)), - (1, 2, 1, date4, datetime(2011, 2, 15)), - (2, 2, 1, date1, datetime(2011, 2, 15)), - (2, 2, 1, date2, datetime(2011, 2, 15)), - (2, 2, 1, date3, datetime(2011, 3, 15)), - (2, 2, 1, date4, datetime(2011, 3, 15)), - ] - - for n, week, weekday, dt, expected in test_cases: - offset = WeekOfMonth(n, week=week, weekday=weekday) - assert_offset_equal(offset, dt, expected) - - # try subtracting - result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2) - assert result == datetime(2011, 1, 12) - - result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2) - assert result == datetime(2011, 2, 2) - - on_offset_cases = [ - (0, 0, datetime(2011, 2, 7), True), - (0, 0, datetime(2011, 2, 6), False), - (0, 0, datetime(2011, 2, 14), False), - (1, 0, datetime(2011, 2, 14), True), - (0, 1, datetime(2011, 2, 1), True), - (0, 1, datetime(2011, 2, 8), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - week, weekday, dt, expected = case - offset = WeekOfMonth(week=week, weekday=weekday) - assert offset.onOffset(dt) == expected - - -class TestLastWeekOfMonth(Base): - _offset = LastWeekOfMonth - offset1 = _offset() - offset2 = _offset(2) - - def test_constructor(self): - with pytest.raises(ValueError, match="^N cannot be 0"): - LastWeekOfMonth(n=0, weekday=1) - - with pytest.raises(ValueError, match="^Day"): - LastWeekOfMonth(n=1, weekday=-1) - - with pytest.raises(ValueError, match="^Day"): - LastWeekOfMonth(n=1, weekday=7) - - def test_offset(self): - # Saturday - last_sat = datetime(2013, 8, 31) - next_sat = datetime(2013, 9, 28) - offset_sat = LastWeekOfMonth(n=1, weekday=5) - - one_day_before = last_sat + timedelta(days=-1) - assert one_day_before + offset_sat == last_sat - - one_day_after = last_sat + timedelta(days=+1) - assert one_day_after + offset_sat == next_sat - - # Test On that day - assert last_sat + offset_sat == next_sat - - # Thursday - - offset_thur = LastWeekOfMonth(n=1, weekday=3) - last_thurs = datetime(2013, 1, 31) - next_thurs = datetime(2013, 2, 28) - - one_day_before = last_thurs + timedelta(days=-1) - assert one_day_before + offset_thur == last_thurs - - one_day_after = last_thurs + timedelta(days=+1) - assert one_day_after + offset_thur == next_thurs - - # Test on that day - assert last_thurs + offset_thur == next_thurs - - three_before = last_thurs + timedelta(days=-3) - assert three_before + offset_thur == last_thurs - - two_after = last_thurs + timedelta(days=+2) - assert two_after + offset_thur == next_thurs - - offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN) - assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25) - - on_offset_cases = [ - (WeekDay.SUN, datetime(2013, 1, 27), True), - (WeekDay.SAT, datetime(2013, 3, 30), True), - (WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon - (WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN - (WeekDay.MON, datetime(2013, 2, 25), True), - (WeekDay.SAT, datetime(2013, 11, 30), True), - (WeekDay.SAT, datetime(2006, 8, 26), True), - (WeekDay.SAT, datetime(2007, 8, 25), True), - (WeekDay.SAT, datetime(2008, 8, 30), True), - (WeekDay.SAT, datetime(2009, 8, 29), True), - (WeekDay.SAT, datetime(2010, 8, 28), True), - (WeekDay.SAT, datetime(2011, 8, 27), True), - (WeekDay.SAT, datetime(2019, 8, 31), True), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - weekday, dt, expected = case - offset = LastWeekOfMonth(weekday=weekday) - assert offset.onOffset(dt) == expected - - -class TestSemiMonthEnd(Base): - _offset = SemiMonthEnd - offset1 = _offset() - offset2 = _offset(2) - - def test_offset_whole_year(self): - dates = ( - datetime(2007, 12, 31), - datetime(2008, 1, 15), - datetime(2008, 1, 31), - datetime(2008, 2, 15), - datetime(2008, 2, 29), - datetime(2008, 3, 15), - datetime(2008, 3, 31), - datetime(2008, 4, 15), - datetime(2008, 4, 30), - datetime(2008, 5, 15), - datetime(2008, 5, 31), - datetime(2008, 6, 15), - datetime(2008, 6, 30), - datetime(2008, 7, 15), - datetime(2008, 7, 31), - datetime(2008, 8, 15), - datetime(2008, 8, 31), - datetime(2008, 9, 15), - datetime(2008, 9, 30), - datetime(2008, 10, 15), - datetime(2008, 10, 31), - datetime(2008, 11, 15), - datetime(2008, 11, 30), - datetime(2008, 12, 15), - datetime(2008, 12, 31), - ) - - for base, exp_date in zip(dates[:-1], dates[1:]): - assert_offset_equal(SemiMonthEnd(), base, exp_date) - - # ensure .apply_index works as expected - s = DatetimeIndex(dates[:-1]) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = SemiMonthEnd().apply_index(s) - - exp = DatetimeIndex(dates[1:]) - tm.assert_index_equal(result, exp) - - # ensure generating a range with DatetimeIndex gives same result - result = date_range(start=dates[0], end=dates[-1], freq="SM") - exp = DatetimeIndex(dates) - tm.assert_index_equal(result, exp) - - offset_cases = [] - offset_cases.append( - ( - SemiMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 1, 15), - datetime(2008, 1, 15): datetime(2008, 1, 31), - datetime(2008, 1, 31): datetime(2008, 2, 15), - datetime(2006, 12, 14): datetime(2006, 12, 15), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2007, 1, 15), - datetime(2007, 1, 1): datetime(2007, 1, 15), - datetime(2006, 12, 1): datetime(2006, 12, 15), - datetime(2006, 12, 15): datetime(2006, 12, 31), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(day_of_month=20), - { - datetime(2008, 1, 1): datetime(2008, 1, 20), - datetime(2008, 1, 15): datetime(2008, 1, 20), - datetime(2008, 1, 21): datetime(2008, 1, 31), - datetime(2008, 1, 31): datetime(2008, 2, 20), - datetime(2006, 12, 14): datetime(2006, 12, 20), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2007, 1, 20), - datetime(2007, 1, 1): datetime(2007, 1, 20), - datetime(2006, 12, 1): datetime(2006, 12, 20), - datetime(2006, 12, 15): datetime(2006, 12, 20), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 15), - datetime(2008, 1, 16): datetime(2008, 1, 31), - datetime(2008, 1, 15): datetime(2008, 1, 15), - datetime(2008, 1, 31): datetime(2008, 1, 31), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2006, 12, 31), - datetime(2007, 1, 1): datetime(2007, 1, 15), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(0, day_of_month=16), - { - datetime(2008, 1, 1): datetime(2008, 1, 16), - datetime(2008, 1, 16): datetime(2008, 1, 16), - datetime(2008, 1, 15): datetime(2008, 1, 16), - datetime(2008, 1, 31): datetime(2008, 1, 31), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2006, 12, 31), - datetime(2007, 1, 1): datetime(2007, 1, 16), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(2), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 1, 31): datetime(2008, 2, 29), - datetime(2006, 12, 29): datetime(2007, 1, 15), - datetime(2006, 12, 31): datetime(2007, 1, 31), - datetime(2007, 1, 1): datetime(2007, 1, 31), - datetime(2007, 1, 16): datetime(2007, 2, 15), - datetime(2006, 11, 1): datetime(2006, 11, 30), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(-1), - { - datetime(2007, 1, 1): datetime(2006, 12, 31), - datetime(2008, 6, 30): datetime(2008, 6, 15), - datetime(2008, 12, 31): datetime(2008, 12, 15), - datetime(2006, 12, 29): datetime(2006, 12, 15), - datetime(2006, 12, 30): datetime(2006, 12, 15), - datetime(2007, 1, 1): datetime(2006, 12, 31), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(-1, day_of_month=4), - { - datetime(2007, 1, 1): datetime(2006, 12, 31), - datetime(2007, 1, 4): datetime(2006, 12, 31), - datetime(2008, 6, 30): datetime(2008, 6, 4), - datetime(2008, 12, 31): datetime(2008, 12, 4), - datetime(2006, 12, 5): datetime(2006, 12, 4), - datetime(2006, 12, 30): datetime(2006, 12, 4), - datetime(2007, 1, 1): datetime(2006, 12, 31), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(-2), - { - datetime(2007, 1, 1): datetime(2006, 12, 15), - datetime(2008, 6, 30): datetime(2008, 5, 31), - datetime(2008, 3, 15): datetime(2008, 2, 15), - datetime(2008, 12, 31): datetime(2008, 11, 30), - datetime(2006, 12, 29): datetime(2006, 11, 30), - datetime(2006, 12, 14): datetime(2006, 11, 15), - datetime(2007, 1, 1): datetime(2006, 12, 15), - }, - ) - ) - - @pytest.mark.parametrize("case", offset_cases) - def test_offset(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - @pytest.mark.parametrize("case", offset_cases) - def test_apply_index(self, case): - offset, cases = case - s = DatetimeIndex(cases.keys()) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = offset.apply_index(s) - - exp = DatetimeIndex(cases.values()) - tm.assert_index_equal(result, exp) - - on_offset_cases = [ - (datetime(2007, 12, 31), True), - (datetime(2007, 12, 15), True), - (datetime(2007, 12, 14), False), - (datetime(2007, 12, 1), False), - (datetime(2008, 2, 29), True), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - dt, expected = case - assert_onOffset(SemiMonthEnd(), dt, expected) - - @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) - def test_vectorized_offset_addition(self, klass): - s = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthEnd() - result2 = SemiMonthEnd() + s - - exp = klass( - [ - Timestamp("2000-01-31 00:15:00", tz="US/Central"), - Timestamp("2000-02-29", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - s = klass( - [ - Timestamp("2000-01-01 00:15:00", tz="US/Central"), - Timestamp("2000-02-01", tz="US/Central"), - ], - name="a", - ) - - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthEnd() - result2 = SemiMonthEnd() + s - - exp = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - -class TestSemiMonthBegin(Base): - _offset = SemiMonthBegin - offset1 = _offset() - offset2 = _offset(2) - - def test_offset_whole_year(self): - dates = ( - datetime(2007, 12, 15), - datetime(2008, 1, 1), - datetime(2008, 1, 15), - datetime(2008, 2, 1), - datetime(2008, 2, 15), - datetime(2008, 3, 1), - datetime(2008, 3, 15), - datetime(2008, 4, 1), - datetime(2008, 4, 15), - datetime(2008, 5, 1), - datetime(2008, 5, 15), - datetime(2008, 6, 1), - datetime(2008, 6, 15), - datetime(2008, 7, 1), - datetime(2008, 7, 15), - datetime(2008, 8, 1), - datetime(2008, 8, 15), - datetime(2008, 9, 1), - datetime(2008, 9, 15), - datetime(2008, 10, 1), - datetime(2008, 10, 15), - datetime(2008, 11, 1), - datetime(2008, 11, 15), - datetime(2008, 12, 1), - datetime(2008, 12, 15), - ) - - for base, exp_date in zip(dates[:-1], dates[1:]): - assert_offset_equal(SemiMonthBegin(), base, exp_date) - - # ensure .apply_index works as expected - s = DatetimeIndex(dates[:-1]) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = SemiMonthBegin().apply_index(s) - - exp = DatetimeIndex(dates[1:]) - tm.assert_index_equal(result, exp) - - # ensure generating a range with DatetimeIndex gives same result - result = date_range(start=dates[0], end=dates[-1], freq="SMS") - exp = DatetimeIndex(dates) - tm.assert_index_equal(result, exp) - - offset_cases = [] - offset_cases.append( - ( - SemiMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 1, 15), - datetime(2008, 1, 15): datetime(2008, 2, 1), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 14): datetime(2006, 12, 15), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 31): datetime(2007, 1, 1), - datetime(2007, 1, 1): datetime(2007, 1, 15), - datetime(2006, 12, 1): datetime(2006, 12, 15), - datetime(2006, 12, 15): datetime(2007, 1, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(day_of_month=20), - { - datetime(2008, 1, 1): datetime(2008, 1, 20), - datetime(2008, 1, 15): datetime(2008, 1, 20), - datetime(2008, 1, 21): datetime(2008, 2, 1), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 14): datetime(2006, 12, 20), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 31): datetime(2007, 1, 1), - datetime(2007, 1, 1): datetime(2007, 1, 20), - datetime(2006, 12, 1): datetime(2006, 12, 20), - datetime(2006, 12, 15): datetime(2006, 12, 20), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 16): datetime(2008, 2, 1), - datetime(2008, 1, 15): datetime(2008, 1, 15), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 2): datetime(2006, 12, 15), - datetime(2007, 1, 1): datetime(2007, 1, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(0, day_of_month=16), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 16): datetime(2008, 1, 16), - datetime(2008, 1, 15): datetime(2008, 1, 16), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 31): datetime(2007, 1, 1), - datetime(2007, 1, 5): datetime(2007, 1, 16), - datetime(2007, 1, 1): datetime(2007, 1, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(2), - { - datetime(2008, 1, 1): datetime(2008, 2, 1), - datetime(2008, 1, 31): datetime(2008, 2, 15), - datetime(2006, 12, 1): datetime(2007, 1, 1), - datetime(2006, 12, 29): datetime(2007, 1, 15), - datetime(2006, 12, 15): datetime(2007, 1, 15), - datetime(2007, 1, 1): datetime(2007, 2, 1), - datetime(2007, 1, 16): datetime(2007, 2, 15), - datetime(2006, 11, 1): datetime(2006, 12, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(-1), - { - datetime(2007, 1, 1): datetime(2006, 12, 15), - datetime(2008, 6, 30): datetime(2008, 6, 15), - datetime(2008, 6, 14): datetime(2008, 6, 1), - datetime(2008, 12, 31): datetime(2008, 12, 15), - datetime(2006, 12, 29): datetime(2006, 12, 15), - datetime(2006, 12, 15): datetime(2006, 12, 1), - datetime(2007, 1, 1): datetime(2006, 12, 15), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(-1, day_of_month=4), - { - datetime(2007, 1, 1): datetime(2006, 12, 4), - datetime(2007, 1, 4): datetime(2007, 1, 1), - datetime(2008, 6, 30): datetime(2008, 6, 4), - datetime(2008, 12, 31): datetime(2008, 12, 4), - datetime(2006, 12, 5): datetime(2006, 12, 4), - datetime(2006, 12, 30): datetime(2006, 12, 4), - datetime(2006, 12, 2): datetime(2006, 12, 1), - datetime(2007, 1, 1): datetime(2006, 12, 4), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(-2), - { - datetime(2007, 1, 1): datetime(2006, 12, 1), - datetime(2008, 6, 30): datetime(2008, 6, 1), - datetime(2008, 6, 14): datetime(2008, 5, 15), - datetime(2008, 12, 31): datetime(2008, 12, 1), - datetime(2006, 12, 29): datetime(2006, 12, 1), - datetime(2006, 12, 15): datetime(2006, 11, 15), - datetime(2007, 1, 1): datetime(2006, 12, 1), - }, - ) - ) - - @pytest.mark.parametrize("case", offset_cases) - def test_offset(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - @pytest.mark.parametrize("case", offset_cases) - def test_apply_index(self, case): - offset, cases = case - s = DatetimeIndex(cases.keys()) - - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = offset.apply_index(s) - - exp = DatetimeIndex(cases.values()) - tm.assert_index_equal(result, exp) - - on_offset_cases = [ - (datetime(2007, 12, 1), True), - (datetime(2007, 12, 15), True), - (datetime(2007, 12, 14), False), - (datetime(2007, 12, 31), False), - (datetime(2008, 2, 15), True), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - dt, expected = case - assert_onOffset(SemiMonthBegin(), dt, expected) - - @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) - def test_vectorized_offset_addition(self, klass): - s = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthBegin() - result2 = SemiMonthBegin() + s - - exp = klass( - [ - Timestamp("2000-02-01 00:15:00", tz="US/Central"), - Timestamp("2000-03-01", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - s = klass( - [ - Timestamp("2000-01-01 00:15:00", tz="US/Central"), - Timestamp("2000-02-01", tz="US/Central"), - ], - name="a", - ) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthBegin() - result2 = SemiMonthBegin() + s - - exp = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - -def test_Easter(): - assert_offset_equal(Easter(), datetime(2010, 1, 1), datetime(2010, 4, 4)) - assert_offset_equal(Easter(), datetime(2010, 4, 5), datetime(2011, 4, 24)) - assert_offset_equal(Easter(2), datetime(2010, 1, 1), datetime(2011, 4, 24)) - - assert_offset_equal(Easter(), datetime(2010, 4, 4), datetime(2011, 4, 24)) - assert_offset_equal(Easter(2), datetime(2010, 4, 4), datetime(2012, 4, 8)) - - assert_offset_equal(-Easter(), datetime(2011, 1, 1), datetime(2010, 4, 4)) - assert_offset_equal(-Easter(), datetime(2010, 4, 5), datetime(2010, 4, 4)) - assert_offset_equal(-Easter(2), datetime(2011, 1, 1), datetime(2009, 4, 12)) - - assert_offset_equal(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)) - assert_offset_equal(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)) - - class TestOffsetNames: def test_get_offset_name(self): assert BDay().freqstr == "B" assert BDay(2).freqstr == "2B" assert BMonthEnd().freqstr == "BM" - assert Week(weekday=0).freqstr == "W-MON" - assert Week(weekday=1).freqstr == "W-TUE" - assert Week(weekday=2).freqstr == "W-WED" - assert Week(weekday=3).freqstr == "W-THU" - assert Week(weekday=4).freqstr == "W-FRI" - - assert LastWeekOfMonth(weekday=WeekDay.SUN).freqstr == "LWOM-SUN" def test_get_offset(): @@ -3960,11 +3085,6 @@ def test_get_offset(): ("b", BDay()), ("bm", BMonthEnd()), ("Bm", BMonthEnd()), - ("W-MON", Week(weekday=0)), - ("W-TUE", Week(weekday=1)), - ("W-WED", Week(weekday=2)), - ("W-THU", Week(weekday=3)), - ("W-FRI", Week(weekday=4)), ] for name, expected in pairs: diff --git a/pandas/tests/tseries/offsets/test_date_offsets.py b/pandas/tests/tseries/offsets/test_date_offsets.py index bed8d2461f65d..9955c4b587308 100644 --- a/pandas/tests/tseries/offsets/test_date_offsets.py +++ b/pandas/tests/tseries/offsets/test_date_offsets.py @@ -30,24 +30,10 @@ from pandas.tseries.holiday import USFederalHolidayCalendar import pandas.tseries.offsets as offsets from pandas.tseries.offsets import ( - FY5253, BaseOffset, - BDay, - BMonthBegin, - BMonthEnd, - BQuarterBegin, - BQuarterEnd, - BusinessHour, - BYearBegin, - BYearEnd, - CBMonthBegin, - CBMonthEnd, - CDay, - CustomBusinessHour, DateOffset, Day, Easter, - FY5253Quarter, LastWeekOfMonth, MonthBegin, MonthEnd, @@ -661,2467 +647,6 @@ def test_eq(self): assert offset1 != offset2 -class TestBusinessDay(Base): - _offset = BDay - - def setup_method(self, method): - self.d = datetime(2008, 1, 1) - - self.offset = BDay() - self.offset1 = self.offset - self.offset2 = BDay(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 * BusinessDays>" - - if compat.PY37: - expected = "" - else: - 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_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): - assert self.offset2(self.d) == datetime(2008, 1, 3) - - def testRollback1(self): - assert BDay(10).rollback(self.d) == self.d - - def testRollback2(self): - assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) - - def testRollforward1(self): - assert BDay(10).rollforward(self.d) == self.d - - def testRollforward2(self): - assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) - - def test_roll_date_object(self): - offset = BDay() - - 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) - - def test_onOffset(self): - tests = [ - (BDay(), datetime(2008, 1, 1), True), - (BDay(), datetime(2008, 1, 5), False), - ] - - for offset, d, expected in tests: - assert_onOffset(offset, d, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - 2 * BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - -BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - -2 * BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - BDay(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 + BDay(10) - assert result == datetime(2012, 11, 6) - - result = dt + BDay(100) - BDay(100) - assert result == dt - - off = BDay() * 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 - - off = BDay() * 10 - rs = datetime(2014, 1, 5) + off # see #5890 - xp = datetime(2014, 1, 17) - assert rs == xp - - 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 TestBusinessHour(Base): - _offset = BusinessHour - - def setup_method(self, method): - self.d = datetime(2014, 7, 1, 10, 00) - - self.offset1 = BusinessHour() - self.offset2 = BusinessHour(n=3) - - self.offset3 = BusinessHour(n=-1) - self.offset4 = BusinessHour(n=-4) - - from datetime import time as dt_time - - self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) - self.offset6 = BusinessHour(start="20:00", end="05:00") - self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) - self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) - self.offset9 = BusinessHour( - n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] - ) - self.offset10 = BusinessHour( - n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] - ) - - @pytest.mark.parametrize( - "start,end,match", - [ - ( - dt_time(11, 0, 5), - "17:00", - "time data must be specified only with hour and minute", - ), - ("AAA", "17:00", "time data must match '%H:%M' format"), - ("14:00:05", "17:00", "time data must match '%H:%M' format"), - ([], "17:00", "Must include at least 1 start time"), - ("09:00", [], "Must include at least 1 end time"), - ( - ["09:00", "11:00"], - "17:00", - "number of starting time and ending time must be the same", - ), - ( - ["09:00", "11:00"], - ["10:00"], - "number of starting time and ending time must be the same", - ), - ( - ["09:00", "11:00"], - ["12:00", "20:00"], - r"invalid starting and ending time\(s\): opening hours should not " - "touch or overlap with one another", - ), - ( - ["12:00", "20:00"], - ["09:00", "11:00"], - r"invalid starting and ending time\(s\): opening hours should not " - "touch or overlap with one another", - ), - ], - ) - def test_constructor_errors(self, start, end, match): - with pytest.raises(ValueError, match=match): - BusinessHour(start=start, end=end) - - 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.offset1) == "" - assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" - assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" - assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" - - assert repr(self.offset5) == "" - assert repr(self.offset6) == "" - assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" - assert repr(self.offset8) == "" - assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" - assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" - - def test_with_offset(self): - expected = Timestamp("2014-07-01 13:00") - - assert self.d + BusinessHour() * 3 == expected - assert self.d + BusinessHour(n=3) == expected - - @pytest.mark.parametrize( - "offset_name", - ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], - ) - def test_eq_attribute(self, offset_name): - offset = getattr(self, offset_name) - assert offset == offset - - @pytest.mark.parametrize( - "offset1,offset2", - [ - (BusinessHour(start="09:00"), BusinessHour()), - ( - BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), - BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), - ), - ], - ) - def test_eq(self, offset1, offset2): - assert offset1 == offset2 - - @pytest.mark.parametrize( - "offset1,offset2", - [ - (BusinessHour(), BusinessHour(-1)), - (BusinessHour(start="09:00"), BusinessHour(start="09:01")), - ( - BusinessHour(start="09:00", end="17:00"), - BusinessHour(start="17:00", end="09:01"), - ), - ( - BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), - BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), - ), - ], - ) - def test_neq(self, offset1, offset2): - assert offset1 != offset2 - - @pytest.mark.parametrize( - "offset_name", - ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], - ) - def test_hash(self, offset_name): - offset = getattr(self, offset_name) - assert offset == offset - - def test_call(self): - assert self.offset1(self.d) == datetime(2014, 7, 1, 11) - assert self.offset2(self.d) == datetime(2014, 7, 1, 13) - assert self.offset3(self.d) == datetime(2014, 6, 30, 17) - assert self.offset4(self.d) == datetime(2014, 6, 30, 14) - assert self.offset8(self.d) == datetime(2014, 7, 1, 11) - assert self.offset9(self.d) == datetime(2014, 7, 1, 22) - assert self.offset10(self.d) == datetime(2014, 7, 1, 1) - - def test_sub(self): - # we have to override test_sub here because self.offset2 is not - # defined as self._offset(2) - off = self.offset2 - msg = "Cannot subtract datetime from offset" - with pytest.raises(TypeError, match=msg): - off - self.d - assert 2 * off - off == off - - assert self.d - self.offset2 == self.d + self._offset(-3) - - def testRollback1(self): - assert self.offset1.rollback(self.d) == self.d - assert self.offset2.rollback(self.d) == self.d - assert self.offset3.rollback(self.d) == self.d - assert self.offset4.rollback(self.d) == self.d - assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) - assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) - assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) - assert self.offset8.rollback(self.d) == self.d - assert self.offset9.rollback(self.d) == self.d - assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) - assert self.offset6.rollback(d) == d - assert self.offset7.rollback(d) == d - assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset9.rollback(d) == d - assert self.offset10.rollback(d) == d - - assert self._offset(5).rollback(self.d) == self.d - - def testRollback2(self): - assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( - 2014, 7, 4, 17, 0 - ) - - def testRollforward1(self): - assert self.offset1.rollforward(self.d) == self.d - assert self.offset2.rollforward(self.d) == self.d - assert self.offset3.rollforward(self.d) == self.d - assert self.offset4.rollforward(self.d) == self.d - assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) - assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) - assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) - assert self.offset8.rollforward(self.d) == self.d - assert self.offset9.rollforward(self.d) == self.d - assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) - assert self.offset6.rollforward(d) == d - assert self.offset7.rollforward(d) == d - assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset9.rollforward(d) == d - assert self.offset10.rollforward(d) == d - - assert self._offset(5).rollforward(self.d) == self.d - - def testRollforward2(self): - assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( - 2014, 7, 7, 9 - ) - - def test_roll_date_object(self): - offset = BusinessHour() - - dt = datetime(2014, 7, 6, 15, 0) - - result = offset.rollback(dt) - assert result == datetime(2014, 7, 4, 17) - - result = offset.rollforward(dt) - assert result == datetime(2014, 7, 7, 9) - - normalize_cases = [] - normalize_cases.append( - ( - BusinessHour(normalize=True), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 1, 0): datetime(2014, 7, 1), - datetime(2014, 7, 4, 15): datetime(2014, 7, 4), - datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 7), - datetime(2014, 7, 6, 10): datetime(2014, 7, 7), - }, - ) - ) - - normalize_cases.append( - ( - BusinessHour(-1, normalize=True), - { - datetime(2014, 7, 1, 8): datetime(2014, 6, 30), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1), - datetime(2014, 7, 1, 10): datetime(2014, 6, 30), - datetime(2014, 7, 1, 0): datetime(2014, 6, 30), - datetime(2014, 7, 7, 10): datetime(2014, 7, 4), - datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 4), - datetime(2014, 7, 6, 10): datetime(2014, 7, 4), - }, - ) - ) - - normalize_cases.append( - ( - BusinessHour(1, normalize=True, start="17:00", end="04:00"), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 2, 2): datetime(2014, 7, 2), - datetime(2014, 7, 2, 3): datetime(2014, 7, 2), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5), - datetime(2014, 7, 5, 2): datetime(2014, 7, 5), - datetime(2014, 7, 7, 2): datetime(2014, 7, 7), - datetime(2014, 7, 7, 17): datetime(2014, 7, 7), - }, - ) - ) - - @pytest.mark.parametrize("case", normalize_cases) - def test_normalize(self, case): - offset, cases = case - for dt, expected in cases.items(): - assert offset.apply(dt) == expected - - on_offset_cases = [] - on_offset_cases.append( - ( - BusinessHour(), - { - datetime(2014, 7, 1, 9): True, - datetime(2014, 7, 1, 8, 59): False, - datetime(2014, 7, 1, 8): False, - datetime(2014, 7, 1, 17): True, - datetime(2014, 7, 1, 17, 1): False, - datetime(2014, 7, 1, 18): False, - datetime(2014, 7, 5, 9): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start="10:00", end="15:00"), - { - datetime(2014, 7, 1, 9): False, - datetime(2014, 7, 1, 10): True, - datetime(2014, 7, 1, 15): True, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 9, 0): False, - datetime(2014, 7, 1, 10, 0): False, - datetime(2014, 7, 1, 15): False, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12, 0): False, - datetime(2014, 7, 6, 12, 0): False, - datetime(2014, 7, 1, 19, 0): True, - datetime(2014, 7, 2, 0, 0): True, - datetime(2014, 7, 4, 23): True, - datetime(2014, 7, 5, 1): True, - datetime(2014, 7, 5, 5, 0): True, - datetime(2014, 7, 6, 23, 0): False, - datetime(2014, 7, 7, 3, 0): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), - { - datetime(2014, 7, 1, 9): True, - datetime(2014, 7, 1, 8, 59): False, - datetime(2014, 7, 1, 8): False, - datetime(2014, 7, 1, 17): True, - datetime(2014, 7, 1, 17, 1): False, - datetime(2014, 7, 1, 18): False, - datetime(2014, 7, 5, 9): False, - datetime(2014, 7, 6, 12): False, - datetime(2014, 7, 1, 12, 30): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), - { - datetime(2014, 7, 1, 9, 0): False, - datetime(2014, 7, 1, 10, 0): False, - datetime(2014, 7, 1, 15): False, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12, 0): False, - datetime(2014, 7, 6, 12, 0): False, - datetime(2014, 7, 1, 19, 0): True, - datetime(2014, 7, 2, 0, 0): True, - datetime(2014, 7, 4, 23): True, - datetime(2014, 7, 5, 1): True, - datetime(2014, 7, 5, 5, 0): True, - datetime(2014, 7, 6, 23, 0): False, - datetime(2014, 7, 7, 3, 0): False, - datetime(2014, 7, 4, 22): False, - }, - ) - ) - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, cases = case - for dt, expected in cases.items(): - assert offset.onOffset(dt) == expected - - opening_time_cases = [] - # opening time should be affected by sign of n, not by n's value and - # end - opening_time_cases.append( - ( - [ - BusinessHour(), - BusinessHour(n=2), - BusinessHour(n=4), - BusinessHour(end="10:00"), - BusinessHour(n=2, end="4:00"), - BusinessHour(n=4, end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - # if timestamp is on opening time, next opening time is - # as it is - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 3, 9), - datetime(2014, 7, 2, 9), - ), - # 2014-07-05 is saturday - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 8, 9), - datetime(2014, 7, 7, 9), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start="11:15"), - BusinessHour(n=2, start="11:15"), - BusinessHour(n=3, start="11:15"), - BusinessHour(start="11:15", end="10:00"), - BusinessHour(n=2, start="11:15", end="4:00"), - BusinessHour(n=3, start="11:15", end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 11, 15), - datetime(2014, 6, 30, 11, 15), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 11, 15): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 2, 11, 15, 1): ( - datetime(2014, 7, 3, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 11, 15), - datetime(2014, 7, 3, 11, 15), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(-1), - BusinessHour(n=-2), - BusinessHour(n=-4), - BusinessHour(n=-1, end="10:00"), - BusinessHour(n=-2, end="4:00"), - BusinessHour(n=-4, end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 3, 9), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 9): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 8, 9), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start="17:00", end="05:00"), - BusinessHour(n=3, start="17:00", end="03:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 17), - datetime(2014, 6, 30, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 4, 17): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 3, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 7, 17, 1): ( - datetime(2014, 7, 8, 17), - datetime(2014, 7, 7, 17), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(-1, start="17:00", end="05:00"), - BusinessHour(n=-2, start="17:00", end="03:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 16, 59): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 3, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 7, 18): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 8, 17), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), - BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), - BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), - BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), - BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 11, 15), - datetime(2014, 6, 30, 15), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 11, 15): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 2, 11, 15, 1): ( - datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 11, 15), - datetime(2014, 7, 3, 15), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 12): ( - datetime(2014, 7, 7, 15), - datetime(2014, 7, 7, 11, 15), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), - BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 8), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 16, 59): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 8), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 7, 18): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 8, 8), - ), - }, - ) - ) - - @pytest.mark.parametrize("case", opening_time_cases) - def test_opening_time(self, case): - _offsets, cases = case - for offset in _offsets: - for dt, (exp_next, exp_prev) in cases.items(): - assert offset._next_opening_time(dt) == exp_next - assert offset._prev_opening_time(dt) == exp_prev - - apply_cases = [] - apply_cases.append( - ( - BusinessHour(), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(4), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(-1), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), - datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), - datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(-4), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), - datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(start="13:00", end="16:00"), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), - datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=2, start="13:00", end="16:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), - datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), - datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start="13:00", end="16:00"), - { - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), - datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-3, start="10:00", end="16:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), - datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), - datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), - datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), - datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), - datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), - datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), - datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), - datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), - datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), - datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), - datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), - datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), - datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), - }, - ) - ) - - # long business hours (see gh-26381) - apply_cases.append( - ( - BusinessHour(n=4, start="00:00", end="23:00"), - { - datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), - datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), - datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), - datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), - datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), - datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-4, start="00:00", end="23:00"), - { - datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), - datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), - datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), - datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), - datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), - datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), - }, - ) - ) - - # multiple business hours - apply_cases.append( - ( - BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), - # out of business hours - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), - datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), - datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), - datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), - datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), - datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), - datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), - datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), - datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), - datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), - datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), - datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), - }, - ) - ) - - @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) - - apply_large_n_cases = [] - # A week later - apply_large_n_cases.append( - ( - BusinessHour(40), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), - datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), - datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), - datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), - datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), - datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), - datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), - datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), - datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), - datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), - datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), - datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), - }, - ) - ) - - # 3 days and 1 hour before - apply_large_n_cases.append( - ( - BusinessHour(-25), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), - datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), - datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), - datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), - datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), - datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), - datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), - datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), - datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), - datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), - datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), - }, - ) - ) - - # 5 days and 3 hours later - apply_large_n_cases.append( - ( - BusinessHour(28, start="21:00", end="02:00"), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), - datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), - datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), - datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), - datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), - datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), - datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), - datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), - datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), - datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), - }, - ) - ) - - # large n for multiple opening hours (3 days and 1 hour before) - apply_large_n_cases.append( - ( - BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), - datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), - datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), - datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), - datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), - datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), - datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), - datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), - datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), - datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), - datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), - datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), - }, - ) - ) - - # 5 days and 3 hours later - apply_large_n_cases.append( - ( - BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), - datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), - datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), - datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), - datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), - datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), - datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), - datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), - datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), - datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), - }, - ) - ) - - @pytest.mark.parametrize("case", apply_large_n_cases) - def test_apply_large_n(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_apply_nanoseconds(self): - tests = [] - - tests.append( - ( - BusinessHour(), - { - Timestamp("2014-07-04 15:00") - + Nano(5): Timestamp("2014-07-04 16:00") - + Nano(5), - Timestamp("2014-07-04 16:00") - + Nano(5): Timestamp("2014-07-07 09:00") - + Nano(5), - Timestamp("2014-07-04 16:00") - - Nano(5): Timestamp("2014-07-04 17:00") - - Nano(5), - }, - ) - ) - - tests.append( - ( - BusinessHour(-1), - { - Timestamp("2014-07-04 15:00") - + Nano(5): Timestamp("2014-07-04 14:00") - + Nano(5), - Timestamp("2014-07-04 10:00") - + Nano(5): Timestamp("2014-07-04 09:00") - + Nano(5), - Timestamp("2014-07-04 10:00") - - Nano(5): Timestamp("2014-07-03 17:00") - - Nano(5), - }, - ) - ) - - for offset, cases in tests: - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_datetimeindex(self): - idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") - idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") - idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") - expected = DatetimeIndex( - [ - "2014-07-04 15:00", - "2014-07-04 16:00", - "2014-07-07 09:00", - "2014-07-07 10:00", - "2014-07-07 11:00", - "2014-07-07 12:00", - "2014-07-07 13:00", - "2014-07-07 14:00", - "2014-07-07 15:00", - "2014-07-07 16:00", - "2014-07-08 09:00", - "2014-07-08 10:00", - ], - freq="BH", - ) - for idx in [idx1, idx2, idx3]: - tm.assert_index_equal(idx, expected) - - idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") - idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") - idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") - - expected = DatetimeIndex( - [ - "2014-07-04 15:45", - "2014-07-04 16:45", - "2014-07-07 09:45", - "2014-07-07 10:45", - "2014-07-07 11:45", - "2014-07-07 12:45", - "2014-07-07 13:45", - "2014-07-07 14:45", - "2014-07-07 15:45", - "2014-07-07 16:45", - "2014-07-08 09:45", - "2014-07-08 10:45", - ], - freq="BH", - ) - expected = idx1 - for idx in [idx1, idx2, idx3]: - tm.assert_index_equal(idx, expected) - - -class TestCustomBusinessHour(Base): - _offset = CustomBusinessHour - holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] - - def setup_method(self, method): - # 2014 Calendar to check custom holidays - # Sun Mon Tue Wed Thu Fri Sat - # 6/22 23 24 25 26 27 28 - # 29 30 7/1 2 3 4 5 - # 6 7 8 9 10 11 12 - self.d = datetime(2014, 7, 1, 10, 00) - self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") - - self.offset2 = CustomBusinessHour(holidays=self.holidays) - - def test_constructor_errors(self): - from datetime import time as dt_time - - with pytest.raises(ValueError): - CustomBusinessHour(start=dt_time(11, 0, 5)) - with pytest.raises(ValueError): - CustomBusinessHour(start="AAA") - with pytest.raises(ValueError): - CustomBusinessHour(start="14:00:05") - - 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.offset1) == "" - assert repr(self.offset2) == "" - - def test_with_offset(self): - expected = Timestamp("2014-07-01 13:00") - - assert self.d + CustomBusinessHour() * 3 == expected - assert self.d + CustomBusinessHour(n=3) == expected - - def test_eq(self): - for offset in [self.offset1, self.offset2]: - assert offset == offset - - assert CustomBusinessHour() != CustomBusinessHour(-1) - assert CustomBusinessHour(start="09:00") == CustomBusinessHour() - assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") - assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( - start="17:00", end="09:01" - ) - - assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( - weekmask="Mon Tue Wed Thu Fri" - ) - assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( - holidays=["2014-06-28"] - ) - - def test_sub(self): - # override the Base.test_sub implementation because self.offset2 is - # defined differently in this class than the test expects - pass - - def test_hash(self): - assert hash(self.offset1) == hash(self.offset1) - assert hash(self.offset2) == hash(self.offset2) - - def test_call(self): - assert self.offset1(self.d) == datetime(2014, 7, 1, 11) - assert self.offset2(self.d) == datetime(2014, 7, 1, 11) - - def testRollback1(self): - assert self.offset1.rollback(self.d) == self.d - assert self.offset2.rollback(self.d) == self.d - - d = datetime(2014, 7, 1, 0) - - # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) - assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) - - # 2014/6/30 and 2014/6/27 are holidays - assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) - - def testRollback2(self): - assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( - 2014, 7, 4, 17, 0 - ) - - def testRollforward1(self): - assert self.offset1.rollforward(self.d) == self.d - assert self.offset2.rollforward(self.d) == self.d - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) - - def testRollforward2(self): - assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( - 2014, 7, 7, 9 - ) - - def test_roll_date_object(self): - offset = BusinessHour() - - dt = datetime(2014, 7, 6, 15, 0) - - result = offset.rollback(dt) - assert result == datetime(2014, 7, 4, 17) - - result = offset.rollforward(dt) - assert result == datetime(2014, 7, 7, 9) - - normalize_cases = [] - normalize_cases.append( - ( - CustomBusinessHour(normalize=True, holidays=holidays), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3), - datetime(2014, 7, 1, 23): datetime(2014, 7, 3), - datetime(2014, 7, 1, 0): datetime(2014, 7, 1), - datetime(2014, 7, 4, 15): datetime(2014, 7, 4), - datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 7), - datetime(2014, 7, 6, 10): datetime(2014, 7, 7), - }, - ) - ) - - normalize_cases.append( - ( - CustomBusinessHour(-1, normalize=True, holidays=holidays), - { - datetime(2014, 7, 1, 8): datetime(2014, 6, 26), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1), - datetime(2014, 7, 1, 10): datetime(2014, 6, 26), - datetime(2014, 7, 1, 0): datetime(2014, 6, 26), - datetime(2014, 7, 7, 10): datetime(2014, 7, 4), - datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 4), - datetime(2014, 7, 6, 10): datetime(2014, 7, 4), - }, - ) - ) - - normalize_cases.append( - ( - CustomBusinessHour( - 1, normalize=True, start="17:00", end="04:00", holidays=holidays - ), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 2, 2): datetime(2014, 7, 2), - datetime(2014, 7, 2, 3): datetime(2014, 7, 3), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5), - datetime(2014, 7, 5, 2): datetime(2014, 7, 5), - datetime(2014, 7, 7, 2): datetime(2014, 7, 7), - datetime(2014, 7, 7, 17): datetime(2014, 7, 7), - }, - ) - ) - - @pytest.mark.parametrize("norm_cases", normalize_cases) - def test_normalize(self, norm_cases): - offset, cases = norm_cases - for dt, expected in cases.items(): - assert offset.apply(dt) == expected - - def test_onOffset(self): - tests = [] - - tests.append( - ( - CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), - { - datetime(2014, 7, 1, 9): False, - datetime(2014, 7, 1, 10): True, - datetime(2014, 7, 1, 15): True, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - for offset, cases in tests: - for dt, expected in cases.items(): - assert offset.onOffset(dt) == expected - - apply_cases = [] - apply_cases.append( - ( - CustomBusinessHour(holidays=holidays), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - CustomBusinessHour(4, holidays=holidays), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), - }, - ) - ) - - @pytest.mark.parametrize("apply_case", apply_cases) - def test_apply(self, apply_case): - offset, cases = apply_case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - nano_cases = [] - nano_cases.append( - ( - CustomBusinessHour(holidays=holidays), - { - Timestamp("2014-07-01 15:00") - + Nano(5): Timestamp("2014-07-01 16:00") - + Nano(5), - Timestamp("2014-07-01 16:00") - + Nano(5): Timestamp("2014-07-03 09:00") - + Nano(5), - Timestamp("2014-07-01 16:00") - - Nano(5): Timestamp("2014-07-01 17:00") - - Nano(5), - }, - ) - ) - - nano_cases.append( - ( - CustomBusinessHour(-1, holidays=holidays), - { - Timestamp("2014-07-01 15:00") - + Nano(5): Timestamp("2014-07-01 14:00") - + Nano(5), - Timestamp("2014-07-01 10:00") - + Nano(5): Timestamp("2014-07-01 09:00") - + Nano(5), - Timestamp("2014-07-01 10:00") - - Nano(5): Timestamp("2014-06-26 17:00") - - Nano(5), - }, - ) - ) - - @pytest.mark.parametrize("nano_case", nano_cases) - def test_apply_nanoseconds(self, nano_case): - offset, cases = nano_case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - -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>" - - if compat.PY37: - expected = "" - else: - 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_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): - 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_onOffset(self, case): - offset, d, expected = case - assert_onOffset(offset, d, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - 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), - }, - ) - ) - - apply_cases.append( - ( - 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), - }, - ) - ) - - apply_cases.append( - ( - -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), - }, - ) - ) - - apply_cases.append( - ( - -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), - }, - ) - ) - - apply_cases.append( - ( - 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 - - -class CustomBusinessMonthBase: - def setup_method(self, method): - self.d = datetime(2008, 1, 1) - - self.offset = self._offset() - self.offset1 = self.offset - self.offset2 = self._offset(2) - - 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_roundtrip_pickle(self): - def _check_roundtrip(obj): - unpickled = tm.round_trip_pickle(obj) - assert unpickled == obj - - _check_roundtrip(self._offset()) - _check_roundtrip(self._offset(2)) - _check_roundtrip(self._offset() * 2) - - def test_copy(self): - # GH 17452 - off = self._offset(weekmask="Mon Wed Fri") - assert off == off.copy() - - -class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): - _offset = CBMonthEnd - - 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 * CustomBusinessMonthEnds>" - - def testCall(self): - assert self.offset2(self.d) == datetime(2008, 2, 29) - - def testRollback1(self): - assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - - def testRollback2(self): - assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) - - def testRollforward1(self): - assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) - - def test_roll_date_object(self): - offset = CBMonthEnd() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 8, 31) - - result = offset.rollforward(dt) - assert result == datetime(2012, 9, 28) - - 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 = [ - (CBMonthEnd(), datetime(2008, 1, 31), True), - (CBMonthEnd(), datetime(2008, 1, 1), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, d, expected = case - assert_onOffset(offset, d, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 2, 7): datetime(2008, 2, 29), - }, - ) - ) - - apply_cases.append( - ( - 2 * CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 2, 29), - datetime(2008, 2, 7): datetime(2008, 3, 31), - }, - ) - ) - - apply_cases.append( - ( - -CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2007, 12, 31), - datetime(2008, 2, 8): datetime(2008, 1, 31), - }, - ) - ) - - apply_cases.append( - ( - -2 * CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2007, 11, 30), - datetime(2008, 2, 9): datetime(2007, 12, 31), - }, - ) - ) - - apply_cases.append( - ( - CBMonthEnd(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 2, 7): datetime(2008, 2, 29), - }, - ) - ) - - @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 + CBMonthEnd(10) - assert result == datetime(2013, 7, 31) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CBMonthEnd() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 7, 29) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - xp = datetime(2012, 5, 31) - assert rs == xp - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] - bm_offset = CBMonthEnd(holidays=holidays) - dt = datetime(2012, 1, 1) - assert dt + bm_offset == datetime(2012, 1, 30) - assert dt + 2 * bm_offset == datetime(2012, 2, 27) - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_datetimeindex(self): - from pandas.tseries.holiday import USFederalHolidayCalendar - - hcal = USFederalHolidayCalendar() - freq = CBMonthEnd(calendar=hcal) - - assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ - 0 - ] == datetime(2012, 1, 31) - - -class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): - _offset = CBMonthBegin - - 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 * CustomBusinessMonthBegins>" - - def testCall(self): - assert self.offset2(self.d) == datetime(2008, 3, 3) - - def testRollback1(self): - assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - - def testRollback2(self): - assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) - - def testRollforward1(self): - assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) - - def test_roll_date_object(self): - offset = CBMonthBegin() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 9, 3) - - result = offset.rollforward(dt) - assert result == datetime(2012, 10, 1) - - 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 = [ - (CBMonthBegin(), datetime(2008, 1, 1), True), - (CBMonthBegin(), datetime(2008, 1, 31), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, dt, expected = case - assert_onOffset(offset, dt, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 2, 1), - datetime(2008, 2, 7): datetime(2008, 3, 3), - }, - ) - ) - - apply_cases.append( - ( - 2 * CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 3, 3), - datetime(2008, 2, 7): datetime(2008, 4, 1), - }, - ) - ) - - apply_cases.append( - ( - -CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2007, 12, 3), - datetime(2008, 2, 8): datetime(2008, 2, 1), - }, - ) - ) - - apply_cases.append( - ( - -2 * CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2007, 11, 1), - datetime(2008, 2, 9): datetime(2008, 1, 1), - }, - ) - ) - - apply_cases.append( - ( - CBMonthBegin(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 7): datetime(2008, 2, 1), - }, - ) - ) - - @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 + CBMonthBegin(10) - assert result == datetime(2013, 8, 1) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CBMonthBegin() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 7, 1) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - - xp = datetime(2012, 6, 1) - assert rs == xp - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] - bm_offset = CBMonthBegin(holidays=holidays) - dt = datetime(2012, 1, 1) - - assert dt + bm_offset == datetime(2012, 1, 2) - assert dt + 2 * bm_offset == datetime(2012, 2, 3) - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_datetimeindex(self): - hcal = USFederalHolidayCalendar() - cbmb = CBMonthBegin(calendar=hcal) - assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ - 0 - ] == datetime(2012, 1, 3) - - class TestWeek(Base): _offset = Week d = Timestamp(datetime(2008, 1, 2)) @@ -3937,9 +1462,6 @@ def test_Easter(): class TestOffsetNames: def test_get_offset_name(self): - assert BDay().freqstr == "B" - assert BDay(2).freqstr == "2B" - assert BMonthEnd().freqstr == "BM" assert Week(weekday=0).freqstr == "W-MON" assert Week(weekday=1).freqstr == "W-TUE" assert Week(weekday=2).freqstr == "W-WED" @@ -3956,10 +1478,6 @@ def test_get_offset(): get_offset("QS-JAN-B") pairs = [ - ("B", BDay()), - ("b", BDay()), - ("bm", BMonthEnd()), - ("Bm", BMonthEnd()), ("W-MON", Week(weekday=0)), ("W-TUE", Week(weekday=1)), ("W-WED", Week(weekday=2)), @@ -4045,14 +1563,6 @@ def test_dateoffset_misc(): assert not offsets.DateOffset(months=2) == 2 -def test_freq_offsets(): - off = BDay(1, offset=timedelta(0, 1800)) - assert off.freqstr == "B+30Min" - - off = BDay(1, offset=timedelta(0, -1800)) - assert off.freqstr == "B-30Min" - - class TestReprNames: def test_str_for_named_is_name(self): # look at all the amazing combinations! From 36a1122b005cb69591a549e66a39cfd492f5a017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Mon, 11 Nov 2019 19:05:11 +0100 Subject: [PATCH 03/12] Test Date Offsets processed --- pandas/tests/tseries/offsets/conftest.py | 2 +- .../tseries/offsets/test_business_offsets.py | 6363 +++++++++-------- .../tseries/offsets/test_date_offsets.py | 73 +- 3 files changed, 3186 insertions(+), 3252 deletions(-) diff --git a/pandas/tests/tseries/offsets/conftest.py b/pandas/tests/tseries/offsets/conftest.py index 2f6868f56c073..2e764123b5e84 100644 --- a/pandas/tests/tseries/offsets/conftest.py +++ b/pandas/tests/tseries/offsets/conftest.py @@ -4,7 +4,7 @@ @pytest.fixture(params=[getattr(offsets, o) for o in offsets.__all__]) -def offset_types(request): +def date_offset_types(request): """ Fixture for all the datetime offsets available for a time series. """ diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index 3708c2c9397bd..1fc3fb5089596 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -30,6 +30,7 @@ from pandas.tseries.holiday import USFederalHolidayCalendar import pandas.tseries.offsets as offsets from pandas.tseries.offsets import ( + BaseOffset, FY5253, BDay, BMonthBegin, @@ -77,2665 +78,2665 @@ def test_to_M8(): _ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]] -class Base: - _offset = None # type: Type[DateOffset] - d = Timestamp(datetime(2008, 1, 2)) - - timezones = [ - None, - "UTC", - "Asia/Tokyo", - "US/Eastern", - "dateutil/Asia/Tokyo", - "dateutil/US/Pacific", - ] - - def _get_offset(self, klass, value=1, normalize=False): - # create instance from offset class - if klass is FY5253: - klass = klass( - n=value, - startingMonth=1, - weekday=1, - variation="last", - normalize=normalize, - ) - elif klass is FY5253Quarter: - klass = klass( - n=value, - startingMonth=1, - weekday=1, - qtr_with_extra_week=1, - variation="last", - normalize=normalize, - ) - elif klass is LastWeekOfMonth: - klass = klass(n=value, weekday=5, normalize=normalize) - elif klass is WeekOfMonth: - klass = klass(n=value, week=1, weekday=5, normalize=normalize) - elif klass is Week: - klass = klass(n=value, weekday=5, normalize=normalize) - elif klass is DateOffset: - klass = klass(days=value, normalize=normalize) - else: - klass = klass(value, normalize=normalize) - return klass - - def test_apply_out_of_range(self, tz_naive_fixture): - tz = tz_naive_fixture - if self._offset is None: - return - - # try to create an out-of-bounds result timestamp; if we can't create - # the offset skip - try: - if self._offset in (BusinessHour, CustomBusinessHour): - # Using 10000 in BusinessHour fails in tz check because of DST - # difference - offset = self._get_offset(self._offset, value=100000) - else: - offset = self._get_offset(self._offset, value=10000) - - result = Timestamp("20080101") + offset - assert isinstance(result, datetime) - assert result.tzinfo is None - - # Check tz is preserved - t = Timestamp("20080101", tz=tz) - result = t + offset - assert isinstance(result, datetime) - assert t.tzinfo == result.tzinfo - - except OutOfBoundsDatetime: - pass - except (ValueError, KeyError): - # we are creating an invalid offset - # so ignore - pass - - def test_offsets_compare_equal(self): - # root cause of GH#456: __ne__ was not implemented - if self._offset is None: - return - offset1 = self._offset() - offset2 = self._offset() - assert not offset1 != offset2 - assert offset1 == offset2 - - def test_rsub(self): - if self._offset is None or not hasattr(self, "offset2"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset2 attr - return - assert self.d - self.offset2 == (-self.offset2).apply(self.d) - - def test_radd(self): - if self._offset is None or not hasattr(self, "offset2"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset2 attr - return - assert self.d + self.offset2 == self.offset2 + self.d - - def test_sub(self): - if self._offset is None or not hasattr(self, "offset2"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset2 attr - return - off = self.offset2 - msg = "Cannot subtract datetime from offset" - with pytest.raises(TypeError, match=msg): - off - self.d - - assert 2 * off - off == off - assert self.d - self.offset2 == self.d + self._offset(-2) - assert self.d - self.offset2 == self.d - (2 * off - off) - - def testMult1(self): - if self._offset is None or not hasattr(self, "offset1"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset1 attr - return - assert self.d + 10 * self.offset1 == self.d + self._offset(10) - assert self.d + 5 * self.offset1 == self.d + self._offset(5) - - def testMult2(self): - if self._offset is None: - return - assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) - assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) - - def test_compare_str(self): - # GH#23524 - # comparing to strings that cannot be cast to DateOffsets should - # not raise for __eq__ or __ne__ - if self._offset is None: - return - off = self._get_offset(self._offset) - - assert not off == "infer" - assert off != "foo" - # Note: inequalities are only implemented for Tick subclasses; - # tests for this are in test_ticks - - -class TestCommon(Base): - # exected value created by Base._get_offset - # are applied to 2011/01/01 09:00 (Saturday) - # used for .apply and .rollforward - expecteds = { - "Day": Timestamp("2011-01-02 09:00:00"), - "DateOffset": Timestamp("2011-01-02 09:00:00"), - "BusinessDay": Timestamp("2011-01-03 09:00:00"), - "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), - "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), - "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), - "MonthBegin": Timestamp("2011-02-01 09:00:00"), - "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), - "MonthEnd": Timestamp("2011-01-31 09:00:00"), - "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), - "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), - "YearBegin": Timestamp("2012-01-01 09:00:00"), - "BYearBegin": Timestamp("2011-01-03 09:00:00"), - "YearEnd": Timestamp("2011-12-31 09:00:00"), - "BYearEnd": Timestamp("2011-12-30 09:00:00"), - "QuarterBegin": Timestamp("2011-03-01 09:00:00"), - "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), - "QuarterEnd": Timestamp("2011-03-31 09:00:00"), - "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), - "BusinessHour": Timestamp("2011-01-03 10:00:00"), - "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), - "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), - "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), - "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), - "FY5253": Timestamp("2011-01-25 09:00:00"), - "Week": Timestamp("2011-01-08 09:00:00"), - "Easter": Timestamp("2011-04-24 09:00:00"), - "Hour": Timestamp("2011-01-01 10:00:00"), - "Minute": Timestamp("2011-01-01 09:01:00"), - "Second": Timestamp("2011-01-01 09:00:01"), - "Milli": Timestamp("2011-01-01 09:00:00.001000"), - "Micro": Timestamp("2011-01-01 09:00:00.000001"), - "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), - } - - def test_immutable(self, offset_types): - # GH#21341 check that __setattr__ raises - offset = self._get_offset(offset_types) - with pytest.raises(AttributeError): - offset.normalize = True - with pytest.raises(AttributeError): - offset.n = 91 - - def test_return_type(self, offset_types): - offset = self._get_offset(offset_types) - - # make sure that we are returning a Timestamp - result = Timestamp("20080101") + offset - assert isinstance(result, Timestamp) - - # make sure that we are returning NaT - assert NaT + offset is NaT - assert offset + NaT is NaT - - assert NaT - offset is NaT - assert (-offset).apply(NaT) is NaT - - def test_offset_n(self, offset_types): - offset = self._get_offset(offset_types) - assert offset.n == 1 - - neg_offset = offset * -1 - assert neg_offset.n == -1 - - mul_offset = offset * 3 - assert mul_offset.n == 3 - - def test_offset_timedelta64_arg(self, offset_types): - # check that offset._validate_n raises TypeError on a timedelt64 - # object - off = self._get_offset(offset_types) - - td64 = np.timedelta64(4567, "s") - with pytest.raises(TypeError, match="argument must be an integer"): - type(off)(n=td64, **off.kwds) - - def test_offset_mul_ndarray(self, offset_types): - off = self._get_offset(offset_types) - - expected = np.array([[off, off * 2], [off * 3, off * 4]]) - - result = np.array([[1, 2], [3, 4]]) * off - tm.assert_numpy_array_equal(result, expected) - - result = off * np.array([[1, 2], [3, 4]]) - tm.assert_numpy_array_equal(result, expected) - - def test_offset_freqstr(self, offset_types): - offset = self._get_offset(offset_types) - - freqstr = offset.freqstr - if freqstr not in ("", "", "LWOM-SAT"): - code = get_offset(freqstr) - assert offset.rule_code == code - - def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): - - if normalize and issubclass(offset, Tick): - # normalize=True disallowed for Tick subclasses GH#21427 - return - - offset_s = self._get_offset(offset, normalize=normalize) - func = getattr(offset_s, funcname) - - result = func(dt) - assert isinstance(result, Timestamp) - assert result == expected - - result = func(Timestamp(dt)) - assert isinstance(result, Timestamp) - assert result == expected - - # see gh-14101 - exp_warning = None - ts = Timestamp(dt) + Nano(5) - - if ( - offset_s.__class__.__name__ == "DateOffset" - and (funcname == "apply" or normalize) - and ts.nanosecond > 0 - ): - exp_warning = UserWarning - - # test nanosecond is preserved - with tm.assert_produces_warning(exp_warning, check_stacklevel=False): - result = func(ts) - assert isinstance(result, Timestamp) - if normalize is False: - assert result == expected + Nano(5) - else: - assert result == expected - - if isinstance(dt, np.datetime64): - # test tz when input is datetime or Timestamp - return - - for tz in self.timezones: - expected_localize = expected.tz_localize(tz) - tz_obj = timezones.maybe_get_tz(tz) - dt_tz = conversion.localize_pydatetime(dt, tz_obj) - - result = func(dt_tz) - assert isinstance(result, Timestamp) - assert result == expected_localize - - result = func(Timestamp(dt, tz=tz)) - assert isinstance(result, Timestamp) - assert result == expected_localize - - # see gh-14101 - exp_warning = None - ts = Timestamp(dt, tz=tz) + Nano(5) - - if ( - offset_s.__class__.__name__ == "DateOffset" - and (funcname == "apply" or normalize) - and ts.nanosecond > 0 - ): - exp_warning = UserWarning - - # test nanosecond is preserved - with tm.assert_produces_warning(exp_warning, check_stacklevel=False): - result = func(ts) - assert isinstance(result, Timestamp) - if normalize is False: - assert result == expected_localize + Nano(5) - else: - assert result == expected_localize - - def test_apply(self, offset_types): - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") - - for dt in [sdt, ndt]: - expected = self.expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "apply", dt, expected) - - expected = Timestamp(expected.date()) - self._check_offsetfunc_works( - offset_types, "apply", dt, expected, normalize=True - ) - - def test_rollforward(self, offset_types): - expecteds = self.expecteds.copy() - - # result will not be changed if the target is on the offset - no_changes = [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ] - for n in no_changes: - expecteds[n] = Timestamp("2011/01/01 09:00") - - expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") - expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") - - # but be changed when normalize=True - norm_expected = expecteds.copy() - for k in norm_expected: - norm_expected[k] = Timestamp(norm_expected[k].date()) - - normalized = { - "Day": Timestamp("2011-01-02 00:00:00"), - "DateOffset": Timestamp("2011-01-02 00:00:00"), - "MonthBegin": Timestamp("2011-02-01 00:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), - "YearBegin": Timestamp("2012-01-01 00:00:00"), - "Week": Timestamp("2011-01-08 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") - - for dt in [sdt, ndt]: - expected = expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) - expected = norm_expected[offset_types.__name__] - self._check_offsetfunc_works( - offset_types, "rollforward", dt, expected, normalize=True - ) - - def test_rollback(self, offset_types): - expecteds = { - "BusinessDay": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), - "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), - "MonthEnd": Timestamp("2010-12-31 09:00:00"), - "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), - "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), - "BYearBegin": Timestamp("2010-01-01 09:00:00"), - "YearEnd": Timestamp("2010-12-31 09:00:00"), - "BYearEnd": Timestamp("2010-12-31 09:00:00"), - "QuarterBegin": Timestamp("2010-12-01 09:00:00"), - "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), - "QuarterEnd": Timestamp("2010-12-31 09:00:00"), - "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), - "BusinessHour": Timestamp("2010-12-31 17:00:00"), - "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), - "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), - "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), - "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), - "FY5253": Timestamp("2010-01-26 09:00:00"), - "Easter": Timestamp("2010-04-04 09:00:00"), - } - - # result will not be changed if the target is on the offset - for n in [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ]: - expecteds[n] = Timestamp("2011/01/01 09:00") - - # but be changed when normalize=True - norm_expected = expecteds.copy() - for k in norm_expected: - norm_expected[k] = Timestamp(norm_expected[k].date()) - - normalized = { - "Day": Timestamp("2010-12-31 00:00:00"), - "DateOffset": Timestamp("2010-12-31 00:00:00"), - "MonthBegin": Timestamp("2010-12-01 00:00:00"), - "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), - "YearBegin": Timestamp("2010-01-01 00:00:00"), - "Week": Timestamp("2010-12-25 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") - - for dt in [sdt, ndt]: - expected = expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "rollback", dt, expected) - - expected = norm_expected[offset_types.__name__] - self._check_offsetfunc_works( - offset_types, "rollback", dt, expected, normalize=True - ) - - def test_onOffset(self, offset_types): - dt = self.expecteds[offset_types.__name__] - offset_s = self._get_offset(offset_types) - assert offset_s.onOffset(dt) - - # when normalize=True, onOffset checks time is 00:00:00 - if issubclass(offset_types, Tick): - # normalize=True disallowed for Tick subclasses GH#21427 - return - offset_n = self._get_offset(offset_types, normalize=True) - assert not offset_n.onOffset(dt) - - if offset_types in (BusinessHour, CustomBusinessHour): - # In default BusinessHour (9:00-17:00), normalized time - # cannot be in business hour range - return - date = datetime(dt.year, dt.month, dt.day) - assert offset_n.onOffset(date) - - def test_add(self, offset_types, tz_naive_fixture): - tz = tz_naive_fixture - dt = datetime(2011, 1, 1, 9, 0) - - offset_s = self._get_offset(offset_types) - expected = self.expecteds[offset_types.__name__] - - result_dt = dt + offset_s - result_ts = Timestamp(dt) + offset_s - for result in [result_dt, result_ts]: - assert isinstance(result, Timestamp) - assert result == expected - - expected_localize = expected.tz_localize(tz) - result = Timestamp(dt, tz=tz) + offset_s - assert isinstance(result, Timestamp) - assert result == expected_localize - - # normalize=True, disallowed for Tick subclasses GH#21427 - if issubclass(offset_types, Tick): - return - offset_s = self._get_offset(offset_types, normalize=True) - expected = Timestamp(expected.date()) - - result_dt = dt + offset_s - result_ts = Timestamp(dt) + offset_s - for result in [result_dt, result_ts]: - assert isinstance(result, Timestamp) - assert result == expected - - expected_localize = expected.tz_localize(tz) - result = Timestamp(dt, tz=tz) + offset_s - assert isinstance(result, Timestamp) - assert result == expected_localize - - def test_pickle_v0_15_2(self, datapath): - offsets = { - "DateOffset": DateOffset(years=1), - "MonthBegin": MonthBegin(1), - "Day": Day(1), - "YearBegin": YearBegin(1), - "Week": Week(1), - } - - pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") - # This code was executed once on v0.15.2 to generate the pickle: - # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) - # - tm.assert_dict_equal(offsets, read_pickle(pickle_path)) - - -class TestBusinessDay(Base): - _offset = BDay - - def setup_method(self, method): - self.d = datetime(2008, 1, 1) - - self.offset = BDay() - self.offset1 = self.offset - self.offset2 = BDay(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 * BusinessDays>" - - if compat.PY37: - expected = "" - else: - 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_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): - assert self.offset2(self.d) == datetime(2008, 1, 3) - - def testRollback1(self): - assert BDay(10).rollback(self.d) == self.d - - def testRollback2(self): - assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) - - def testRollforward1(self): - assert BDay(10).rollforward(self.d) == self.d - - def testRollforward2(self): - assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) - - def test_roll_date_object(self): - offset = BDay() - - 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) - - def test_onOffset(self): - tests = [ - (BDay(), datetime(2008, 1, 1), True), - (BDay(), datetime(2008, 1, 5), False), - ] - - for offset, d, expected in tests: - assert_onOffset(offset, d, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - 2 * BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - -BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - -2 * BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - BDay(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 + BDay(10) - assert result == datetime(2012, 11, 6) - - result = dt + BDay(100) - BDay(100) - assert result == dt - - off = BDay() * 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 - - off = BDay() * 10 - rs = datetime(2014, 1, 5) + off # see #5890 - xp = datetime(2014, 1, 17) - assert rs == xp - - 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 TestBusinessHour(Base): - _offset = BusinessHour - - def setup_method(self, method): - self.d = datetime(2014, 7, 1, 10, 00) - - self.offset1 = BusinessHour() - self.offset2 = BusinessHour(n=3) - - self.offset3 = BusinessHour(n=-1) - self.offset4 = BusinessHour(n=-4) - - from datetime import time as dt_time - - self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) - self.offset6 = BusinessHour(start="20:00", end="05:00") - self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) - self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) - self.offset9 = BusinessHour( - n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] - ) - self.offset10 = BusinessHour( - n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] - ) - - @pytest.mark.parametrize( - "start,end,match", - [ - ( - dt_time(11, 0, 5), - "17:00", - "time data must be specified only with hour and minute", - ), - ("AAA", "17:00", "time data must match '%H:%M' format"), - ("14:00:05", "17:00", "time data must match '%H:%M' format"), - ([], "17:00", "Must include at least 1 start time"), - ("09:00", [], "Must include at least 1 end time"), - ( - ["09:00", "11:00"], - "17:00", - "number of starting time and ending time must be the same", - ), - ( - ["09:00", "11:00"], - ["10:00"], - "number of starting time and ending time must be the same", - ), - ( - ["09:00", "11:00"], - ["12:00", "20:00"], - r"invalid starting and ending time\(s\): opening hours should not " - "touch or overlap with one another", - ), - ( - ["12:00", "20:00"], - ["09:00", "11:00"], - r"invalid starting and ending time\(s\): opening hours should not " - "touch or overlap with one another", - ), - ], - ) - def test_constructor_errors(self, start, end, match): - with pytest.raises(ValueError, match=match): - BusinessHour(start=start, end=end) - - 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.offset1) == "" - assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" - assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" - assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" - - assert repr(self.offset5) == "" - assert repr(self.offset6) == "" - assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" - assert repr(self.offset8) == "" - assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" - assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" - - def test_with_offset(self): - expected = Timestamp("2014-07-01 13:00") - - assert self.d + BusinessHour() * 3 == expected - assert self.d + BusinessHour(n=3) == expected - - @pytest.mark.parametrize( - "offset_name", - ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], - ) - def test_eq_attribute(self, offset_name): - offset = getattr(self, offset_name) - assert offset == offset - - @pytest.mark.parametrize( - "offset1,offset2", - [ - (BusinessHour(start="09:00"), BusinessHour()), - ( - BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), - BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), - ), - ], - ) - def test_eq(self, offset1, offset2): - assert offset1 == offset2 - - @pytest.mark.parametrize( - "offset1,offset2", - [ - (BusinessHour(), BusinessHour(-1)), - (BusinessHour(start="09:00"), BusinessHour(start="09:01")), - ( - BusinessHour(start="09:00", end="17:00"), - BusinessHour(start="17:00", end="09:01"), - ), - ( - BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), - BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), - ), - ], - ) - def test_neq(self, offset1, offset2): - assert offset1 != offset2 - - @pytest.mark.parametrize( - "offset_name", - ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], - ) - def test_hash(self, offset_name): - offset = getattr(self, offset_name) - assert offset == offset - - def test_call(self): - assert self.offset1(self.d) == datetime(2014, 7, 1, 11) - assert self.offset2(self.d) == datetime(2014, 7, 1, 13) - assert self.offset3(self.d) == datetime(2014, 6, 30, 17) - assert self.offset4(self.d) == datetime(2014, 6, 30, 14) - assert self.offset8(self.d) == datetime(2014, 7, 1, 11) - assert self.offset9(self.d) == datetime(2014, 7, 1, 22) - assert self.offset10(self.d) == datetime(2014, 7, 1, 1) - - def test_sub(self): - # we have to override test_sub here because self.offset2 is not - # defined as self._offset(2) - off = self.offset2 - msg = "Cannot subtract datetime from offset" - with pytest.raises(TypeError, match=msg): - off - self.d - assert 2 * off - off == off - - assert self.d - self.offset2 == self.d + self._offset(-3) - - def testRollback1(self): - assert self.offset1.rollback(self.d) == self.d - assert self.offset2.rollback(self.d) == self.d - assert self.offset3.rollback(self.d) == self.d - assert self.offset4.rollback(self.d) == self.d - assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) - assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) - assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) - assert self.offset8.rollback(self.d) == self.d - assert self.offset9.rollback(self.d) == self.d - assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) - assert self.offset6.rollback(d) == d - assert self.offset7.rollback(d) == d - assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset9.rollback(d) == d - assert self.offset10.rollback(d) == d - - assert self._offset(5).rollback(self.d) == self.d - - def testRollback2(self): - assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( - 2014, 7, 4, 17, 0 - ) - - def testRollforward1(self): - assert self.offset1.rollforward(self.d) == self.d - assert self.offset2.rollforward(self.d) == self.d - assert self.offset3.rollforward(self.d) == self.d - assert self.offset4.rollforward(self.d) == self.d - assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) - assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) - assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) - assert self.offset8.rollforward(self.d) == self.d - assert self.offset9.rollforward(self.d) == self.d - assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) - assert self.offset6.rollforward(d) == d - assert self.offset7.rollforward(d) == d - assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset9.rollforward(d) == d - assert self.offset10.rollforward(d) == d - - assert self._offset(5).rollforward(self.d) == self.d - - def testRollforward2(self): - assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( - 2014, 7, 7, 9 - ) - - def test_roll_date_object(self): - offset = BusinessHour() - - dt = datetime(2014, 7, 6, 15, 0) - - result = offset.rollback(dt) - assert result == datetime(2014, 7, 4, 17) - - result = offset.rollforward(dt) - assert result == datetime(2014, 7, 7, 9) - - normalize_cases = [] - normalize_cases.append( - ( - BusinessHour(normalize=True), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 1, 0): datetime(2014, 7, 1), - datetime(2014, 7, 4, 15): datetime(2014, 7, 4), - datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 7), - datetime(2014, 7, 6, 10): datetime(2014, 7, 7), - }, - ) - ) - - normalize_cases.append( - ( - BusinessHour(-1, normalize=True), - { - datetime(2014, 7, 1, 8): datetime(2014, 6, 30), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1), - datetime(2014, 7, 1, 10): datetime(2014, 6, 30), - datetime(2014, 7, 1, 0): datetime(2014, 6, 30), - datetime(2014, 7, 7, 10): datetime(2014, 7, 4), - datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 4), - datetime(2014, 7, 6, 10): datetime(2014, 7, 4), - }, - ) - ) - - normalize_cases.append( - ( - BusinessHour(1, normalize=True, start="17:00", end="04:00"), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 2, 2): datetime(2014, 7, 2), - datetime(2014, 7, 2, 3): datetime(2014, 7, 2), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5), - datetime(2014, 7, 5, 2): datetime(2014, 7, 5), - datetime(2014, 7, 7, 2): datetime(2014, 7, 7), - datetime(2014, 7, 7, 17): datetime(2014, 7, 7), - }, - ) - ) - - @pytest.mark.parametrize("case", normalize_cases) - def test_normalize(self, case): - offset, cases = case - for dt, expected in cases.items(): - assert offset.apply(dt) == expected - - on_offset_cases = [] - on_offset_cases.append( - ( - BusinessHour(), - { - datetime(2014, 7, 1, 9): True, - datetime(2014, 7, 1, 8, 59): False, - datetime(2014, 7, 1, 8): False, - datetime(2014, 7, 1, 17): True, - datetime(2014, 7, 1, 17, 1): False, - datetime(2014, 7, 1, 18): False, - datetime(2014, 7, 5, 9): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start="10:00", end="15:00"), - { - datetime(2014, 7, 1, 9): False, - datetime(2014, 7, 1, 10): True, - datetime(2014, 7, 1, 15): True, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 9, 0): False, - datetime(2014, 7, 1, 10, 0): False, - datetime(2014, 7, 1, 15): False, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12, 0): False, - datetime(2014, 7, 6, 12, 0): False, - datetime(2014, 7, 1, 19, 0): True, - datetime(2014, 7, 2, 0, 0): True, - datetime(2014, 7, 4, 23): True, - datetime(2014, 7, 5, 1): True, - datetime(2014, 7, 5, 5, 0): True, - datetime(2014, 7, 6, 23, 0): False, - datetime(2014, 7, 7, 3, 0): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), - { - datetime(2014, 7, 1, 9): True, - datetime(2014, 7, 1, 8, 59): False, - datetime(2014, 7, 1, 8): False, - datetime(2014, 7, 1, 17): True, - datetime(2014, 7, 1, 17, 1): False, - datetime(2014, 7, 1, 18): False, - datetime(2014, 7, 5, 9): False, - datetime(2014, 7, 6, 12): False, - datetime(2014, 7, 1, 12, 30): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), - { - datetime(2014, 7, 1, 9, 0): False, - datetime(2014, 7, 1, 10, 0): False, - datetime(2014, 7, 1, 15): False, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12, 0): False, - datetime(2014, 7, 6, 12, 0): False, - datetime(2014, 7, 1, 19, 0): True, - datetime(2014, 7, 2, 0, 0): True, - datetime(2014, 7, 4, 23): True, - datetime(2014, 7, 5, 1): True, - datetime(2014, 7, 5, 5, 0): True, - datetime(2014, 7, 6, 23, 0): False, - datetime(2014, 7, 7, 3, 0): False, - datetime(2014, 7, 4, 22): False, - }, - ) - ) - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, cases = case - for dt, expected in cases.items(): - assert offset.onOffset(dt) == expected - - opening_time_cases = [] - # opening time should be affected by sign of n, not by n's value and - # end - opening_time_cases.append( - ( - [ - BusinessHour(), - BusinessHour(n=2), - BusinessHour(n=4), - BusinessHour(end="10:00"), - BusinessHour(n=2, end="4:00"), - BusinessHour(n=4, end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - # if timestamp is on opening time, next opening time is - # as it is - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 3, 9), - datetime(2014, 7, 2, 9), - ), - # 2014-07-05 is saturday - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 8, 9), - datetime(2014, 7, 7, 9), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start="11:15"), - BusinessHour(n=2, start="11:15"), - BusinessHour(n=3, start="11:15"), - BusinessHour(start="11:15", end="10:00"), - BusinessHour(n=2, start="11:15", end="4:00"), - BusinessHour(n=3, start="11:15", end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 11, 15), - datetime(2014, 6, 30, 11, 15), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 11, 15): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 2, 11, 15, 1): ( - datetime(2014, 7, 3, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 11, 15), - datetime(2014, 7, 3, 11, 15), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(-1), - BusinessHour(n=-2), - BusinessHour(n=-4), - BusinessHour(n=-1, end="10:00"), - BusinessHour(n=-2, end="4:00"), - BusinessHour(n=-4, end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 3, 9), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 9): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 8, 9), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start="17:00", end="05:00"), - BusinessHour(n=3, start="17:00", end="03:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 17), - datetime(2014, 6, 30, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 4, 17): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 3, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 7, 17, 1): ( - datetime(2014, 7, 8, 17), - datetime(2014, 7, 7, 17), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(-1, start="17:00", end="05:00"), - BusinessHour(n=-2, start="17:00", end="03:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 16, 59): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 3, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 7, 18): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 8, 17), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), - BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), - BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), - BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), - BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 11, 15), - datetime(2014, 6, 30, 15), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 11, 15): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 2, 11, 15, 1): ( - datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 11, 15), - datetime(2014, 7, 3, 15), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 12): ( - datetime(2014, 7, 7, 15), - datetime(2014, 7, 7, 11, 15), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), - BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 8), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 16, 59): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 8), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 7, 18): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 8, 8), - ), - }, - ) - ) - - @pytest.mark.parametrize("case", opening_time_cases) - def test_opening_time(self, case): - _offsets, cases = case - for offset in _offsets: - for dt, (exp_next, exp_prev) in cases.items(): - assert offset._next_opening_time(dt) == exp_next - assert offset._prev_opening_time(dt) == exp_prev - - apply_cases = [] - apply_cases.append( - ( - BusinessHour(), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(4), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(-1), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), - datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), - datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(-4), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), - datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(start="13:00", end="16:00"), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), - datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=2, start="13:00", end="16:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), - datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), - datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start="13:00", end="16:00"), - { - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), - datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-3, start="10:00", end="16:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), - datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), - datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), - datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), - datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), - datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), - datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), - datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), - datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), - datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), - datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), - datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), - datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), - datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), - }, - ) - ) - - # long business hours (see gh-26381) - apply_cases.append( - ( - BusinessHour(n=4, start="00:00", end="23:00"), - { - datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), - datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), - datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), - datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), - datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), - datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-4, start="00:00", end="23:00"), - { - datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), - datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), - datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), - datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), - datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), - datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), - }, - ) - ) - - # multiple business hours - apply_cases.append( - ( - BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), - # out of business hours - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), - datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), - datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), - datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), - datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), - datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), - datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), - datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), - datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), - datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), - datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), - datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), - }, - ) - ) - - @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) - - apply_large_n_cases = [] - # A week later - apply_large_n_cases.append( - ( - BusinessHour(40), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), - datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), - datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), - datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), - datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), - datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), - datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), - datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), - datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), - datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), - datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), - datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), - }, - ) - ) - - # 3 days and 1 hour before - apply_large_n_cases.append( - ( - BusinessHour(-25), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), - datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), - datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), - datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), - datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), - datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), - datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), - datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), - datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), - datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), - datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), - }, - ) - ) - - # 5 days and 3 hours later - apply_large_n_cases.append( - ( - BusinessHour(28, start="21:00", end="02:00"), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), - datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), - datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), - datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), - datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), - datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), - datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), - datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), - datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), - datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), - }, - ) - ) - - # large n for multiple opening hours (3 days and 1 hour before) - apply_large_n_cases.append( - ( - BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), - datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), - datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), - datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), - datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), - datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), - datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), - datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), - datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), - datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), - datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), - datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), - }, - ) - ) - - # 5 days and 3 hours later - apply_large_n_cases.append( - ( - BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), - datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), - datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), - datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), - datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), - datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), - datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), - datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), - datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), - datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), - }, - ) - ) - - @pytest.mark.parametrize("case", apply_large_n_cases) - def test_apply_large_n(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_apply_nanoseconds(self): - tests = [] - - tests.append( - ( - BusinessHour(), - { - Timestamp("2014-07-04 15:00") - + Nano(5): Timestamp("2014-07-04 16:00") - + Nano(5), - Timestamp("2014-07-04 16:00") - + Nano(5): Timestamp("2014-07-07 09:00") - + Nano(5), - Timestamp("2014-07-04 16:00") - - Nano(5): Timestamp("2014-07-04 17:00") - - Nano(5), - }, - ) - ) - - tests.append( - ( - BusinessHour(-1), - { - Timestamp("2014-07-04 15:00") - + Nano(5): Timestamp("2014-07-04 14:00") - + Nano(5), - Timestamp("2014-07-04 10:00") - + Nano(5): Timestamp("2014-07-04 09:00") - + Nano(5), - Timestamp("2014-07-04 10:00") - - Nano(5): Timestamp("2014-07-03 17:00") - - Nano(5), - }, - ) - ) - - for offset, cases in tests: - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_datetimeindex(self): - idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") - idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") - idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") - expected = DatetimeIndex( - [ - "2014-07-04 15:00", - "2014-07-04 16:00", - "2014-07-07 09:00", - "2014-07-07 10:00", - "2014-07-07 11:00", - "2014-07-07 12:00", - "2014-07-07 13:00", - "2014-07-07 14:00", - "2014-07-07 15:00", - "2014-07-07 16:00", - "2014-07-08 09:00", - "2014-07-08 10:00", - ], - freq="BH", - ) - for idx in [idx1, idx2, idx3]: - tm.assert_index_equal(idx, expected) - - idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") - idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") - idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") - - expected = DatetimeIndex( - [ - "2014-07-04 15:45", - "2014-07-04 16:45", - "2014-07-07 09:45", - "2014-07-07 10:45", - "2014-07-07 11:45", - "2014-07-07 12:45", - "2014-07-07 13:45", - "2014-07-07 14:45", - "2014-07-07 15:45", - "2014-07-07 16:45", - "2014-07-08 09:45", - "2014-07-08 10:45", - ], - freq="BH", - ) - expected = idx1 - for idx in [idx1, idx2, idx3]: - tm.assert_index_equal(idx, expected) - - -class TestCustomBusinessHour(Base): - _offset = CustomBusinessHour - holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] - - def setup_method(self, method): - # 2014 Calendar to check custom holidays - # Sun Mon Tue Wed Thu Fri Sat - # 6/22 23 24 25 26 27 28 - # 29 30 7/1 2 3 4 5 - # 6 7 8 9 10 11 12 - self.d = datetime(2014, 7, 1, 10, 00) - self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") - - self.offset2 = CustomBusinessHour(holidays=self.holidays) - - def test_constructor_errors(self): - from datetime import time as dt_time - - with pytest.raises(ValueError): - CustomBusinessHour(start=dt_time(11, 0, 5)) - with pytest.raises(ValueError): - CustomBusinessHour(start="AAA") - with pytest.raises(ValueError): - CustomBusinessHour(start="14:00:05") - - 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.offset1) == "" - assert repr(self.offset2) == "" - - def test_with_offset(self): - expected = Timestamp("2014-07-01 13:00") - - assert self.d + CustomBusinessHour() * 3 == expected - assert self.d + CustomBusinessHour(n=3) == expected - - def test_eq(self): - for offset in [self.offset1, self.offset2]: - assert offset == offset - - assert CustomBusinessHour() != CustomBusinessHour(-1) - assert CustomBusinessHour(start="09:00") == CustomBusinessHour() - assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") - assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( - start="17:00", end="09:01" - ) - - assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( - weekmask="Mon Tue Wed Thu Fri" - ) - assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( - holidays=["2014-06-28"] - ) - - def test_sub(self): - # override the Base.test_sub implementation because self.offset2 is - # defined differently in this class than the test expects - pass - - def test_hash(self): - assert hash(self.offset1) == hash(self.offset1) - assert hash(self.offset2) == hash(self.offset2) - - def test_call(self): - assert self.offset1(self.d) == datetime(2014, 7, 1, 11) - assert self.offset2(self.d) == datetime(2014, 7, 1, 11) - - def testRollback1(self): - assert self.offset1.rollback(self.d) == self.d - assert self.offset2.rollback(self.d) == self.d - - d = datetime(2014, 7, 1, 0) - - # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) - assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) - - # 2014/6/30 and 2014/6/27 are holidays - assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) - - def testRollback2(self): - assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( - 2014, 7, 4, 17, 0 - ) - - def testRollforward1(self): - assert self.offset1.rollforward(self.d) == self.d - assert self.offset2.rollforward(self.d) == self.d - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) - - def testRollforward2(self): - assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( - 2014, 7, 7, 9 - ) - - def test_roll_date_object(self): - offset = BusinessHour() - - dt = datetime(2014, 7, 6, 15, 0) - - result = offset.rollback(dt) - assert result == datetime(2014, 7, 4, 17) - - result = offset.rollforward(dt) - assert result == datetime(2014, 7, 7, 9) - - normalize_cases = [] - normalize_cases.append( - ( - CustomBusinessHour(normalize=True, holidays=holidays), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3), - datetime(2014, 7, 1, 23): datetime(2014, 7, 3), - datetime(2014, 7, 1, 0): datetime(2014, 7, 1), - datetime(2014, 7, 4, 15): datetime(2014, 7, 4), - datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 7), - datetime(2014, 7, 6, 10): datetime(2014, 7, 7), - }, - ) - ) - - normalize_cases.append( - ( - CustomBusinessHour(-1, normalize=True, holidays=holidays), - { - datetime(2014, 7, 1, 8): datetime(2014, 6, 26), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1), - datetime(2014, 7, 1, 10): datetime(2014, 6, 26), - datetime(2014, 7, 1, 0): datetime(2014, 6, 26), - datetime(2014, 7, 7, 10): datetime(2014, 7, 4), - datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 4), - datetime(2014, 7, 6, 10): datetime(2014, 7, 4), - }, - ) - ) - - normalize_cases.append( - ( - CustomBusinessHour( - 1, normalize=True, start="17:00", end="04:00", holidays=holidays - ), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 2, 2): datetime(2014, 7, 2), - datetime(2014, 7, 2, 3): datetime(2014, 7, 3), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5), - datetime(2014, 7, 5, 2): datetime(2014, 7, 5), - datetime(2014, 7, 7, 2): datetime(2014, 7, 7), - datetime(2014, 7, 7, 17): datetime(2014, 7, 7), - }, - ) - ) - - @pytest.mark.parametrize("norm_cases", normalize_cases) - def test_normalize(self, norm_cases): - offset, cases = norm_cases - for dt, expected in cases.items(): - assert offset.apply(dt) == expected - - def test_onOffset(self): - tests = [] - - tests.append( - ( - CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), - { - datetime(2014, 7, 1, 9): False, - datetime(2014, 7, 1, 10): True, - datetime(2014, 7, 1, 15): True, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - for offset, cases in tests: - for dt, expected in cases.items(): - assert offset.onOffset(dt) == expected - - apply_cases = [] - apply_cases.append( - ( - CustomBusinessHour(holidays=holidays), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - CustomBusinessHour(4, holidays=holidays), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), - }, - ) - ) - - @pytest.mark.parametrize("apply_case", apply_cases) - def test_apply(self, apply_case): - offset, cases = apply_case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - nano_cases = [] - nano_cases.append( - ( - CustomBusinessHour(holidays=holidays), - { - Timestamp("2014-07-01 15:00") - + Nano(5): Timestamp("2014-07-01 16:00") - + Nano(5), - Timestamp("2014-07-01 16:00") - + Nano(5): Timestamp("2014-07-03 09:00") - + Nano(5), - Timestamp("2014-07-01 16:00") - - Nano(5): Timestamp("2014-07-01 17:00") - - Nano(5), - }, - ) - ) - - nano_cases.append( - ( - CustomBusinessHour(-1, holidays=holidays), - { - Timestamp("2014-07-01 15:00") - + Nano(5): Timestamp("2014-07-01 14:00") - + Nano(5), - Timestamp("2014-07-01 10:00") - + Nano(5): Timestamp("2014-07-01 09:00") - + Nano(5), - Timestamp("2014-07-01 10:00") - - Nano(5): Timestamp("2014-06-26 17:00") - - Nano(5), - }, - ) - ) - - @pytest.mark.parametrize("nano_case", nano_cases) - def test_apply_nanoseconds(self, nano_case): - offset, cases = nano_case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - -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>" - - if compat.PY37: - expected = "" - else: - 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_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): - 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_onOffset(self, case): - offset, d, expected = case - assert_onOffset(offset, d, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - 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), - }, - ) - ) - - apply_cases.append( - ( - 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), - }, - ) - ) - - apply_cases.append( - ( - -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), - }, - ) - ) - - apply_cases.append( - ( - -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), - }, - ) - ) - - apply_cases.append( - ( - 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 +# class Base: +# _offset = None # type: Type[DateOffset] +# d = Timestamp(datetime(2008, 1, 2)) +# +# timezones = [ +# None, +# "UTC", +# "Asia/Tokyo", +# "US/Eastern", +# "dateutil/Asia/Tokyo", +# "dateutil/US/Pacific", +# ] +# +# def _get_offset(self, klass, value=1, normalize=False): +# # create instance from offset class +# if klass is FY5253: +# klass = klass( +# n=value, +# startingMonth=1, +# weekday=1, +# variation="last", +# normalize=normalize, +# ) +# elif klass is FY5253Quarter: +# klass = klass( +# n=value, +# startingMonth=1, +# weekday=1, +# qtr_with_extra_week=1, +# variation="last", +# normalize=normalize, +# ) +# elif klass is LastWeekOfMonth: +# klass = klass(n=value, weekday=5, normalize=normalize) +# elif klass is WeekOfMonth: +# klass = klass(n=value, week=1, weekday=5, normalize=normalize) +# elif klass is Week: +# klass = klass(n=value, weekday=5, normalize=normalize) +# elif klass is DateOffset: +# klass = klass(days=value, normalize=normalize) +# else: +# klass = klass(value, normalize=normalize) +# return klass +# +# def test_apply_out_of_range(self, tz_naive_fixture): +# tz = tz_naive_fixture +# if self._offset is None: +# return +# +# # try to create an out-of-bounds result timestamp; if we can't create +# # the offset skip +# try: +# if self._offset in (BusinessHour, CustomBusinessHour): +# # Using 10000 in BusinessHour fails in tz check because of DST +# # difference +# offset = self._get_offset(self._offset, value=100000) +# else: +# offset = self._get_offset(self._offset, value=10000) +# +# result = Timestamp("20080101") + offset +# assert isinstance(result, datetime) +# assert result.tzinfo is None +# +# # Check tz is preserved +# t = Timestamp("20080101", tz=tz) +# result = t + offset +# assert isinstance(result, datetime) +# assert t.tzinfo == result.tzinfo +# +# except OutOfBoundsDatetime: +# pass +# except (ValueError, KeyError): +# # we are creating an invalid offset +# # so ignore +# pass +# +# def test_offsets_compare_equal(self): +# # root cause of GH#456: __ne__ was not implemented +# if self._offset is None: +# return +# offset1 = self._offset() +# offset2 = self._offset() +# assert not offset1 != offset2 +# assert offset1 == offset2 +# +# def test_rsub(self): +# if self._offset is None or not hasattr(self, "offset2"): +# # i.e. skip for TestCommon and YQM subclasses that do not have +# # offset2 attr +# return +# assert self.d - self.offset2 == (-self.offset2).apply(self.d) +# +# def test_radd(self): +# if self._offset is None or not hasattr(self, "offset2"): +# # i.e. skip for TestCommon and YQM subclasses that do not have +# # offset2 attr +# return +# assert self.d + self.offset2 == self.offset2 + self.d +# +# def test_sub(self): +# if self._offset is None or not hasattr(self, "offset2"): +# # i.e. skip for TestCommon and YQM subclasses that do not have +# # offset2 attr +# return +# off = self.offset2 +# msg = "Cannot subtract datetime from offset" +# with pytest.raises(TypeError, match=msg): +# off - self.d +# +# assert 2 * off - off == off +# assert self.d - self.offset2 == self.d + self._offset(-2) +# assert self.d - self.offset2 == self.d - (2 * off - off) +# +# def testMult1(self): +# if self._offset is None or not hasattr(self, "offset1"): +# # i.e. skip for TestCommon and YQM subclasses that do not have +# # offset1 attr +# return +# assert self.d + 10 * self.offset1 == self.d + self._offset(10) +# assert self.d + 5 * self.offset1 == self.d + self._offset(5) +# +# def testMult2(self): +# if self._offset is None: +# return +# assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) +# assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) +# +# def test_compare_str(self): +# # GH#23524 +# # comparing to strings that cannot be cast to DateOffsets should +# # not raise for __eq__ or __ne__ +# if self._offset is None: +# return +# off = self._get_offset(self._offset) +# +# assert not off == "infer" +# assert off != "foo" +# # Note: inequalities are only implemented for Tick subclasses; +# # tests for this are in test_ticks + + +# class TestCommon(Base): +# # exected value created by Base._get_offset +# # are applied to 2011/01/01 09:00 (Saturday) +# # used for .apply and .rollforward +# expecteds = { +# "Day": Timestamp("2011-01-02 09:00:00"), +# "DateOffset": Timestamp("2011-01-02 09:00:00"), +# "BusinessDay": Timestamp("2011-01-03 09:00:00"), +# "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), +# "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), +# "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), +# "MonthBegin": Timestamp("2011-02-01 09:00:00"), +# "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), +# "MonthEnd": Timestamp("2011-01-31 09:00:00"), +# "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), +# "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), +# "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), +# "YearBegin": Timestamp("2012-01-01 09:00:00"), +# "BYearBegin": Timestamp("2011-01-03 09:00:00"), +# "YearEnd": Timestamp("2011-12-31 09:00:00"), +# "BYearEnd": Timestamp("2011-12-30 09:00:00"), +# "QuarterBegin": Timestamp("2011-03-01 09:00:00"), +# "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), +# "QuarterEnd": Timestamp("2011-03-31 09:00:00"), +# "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), +# "BusinessHour": Timestamp("2011-01-03 10:00:00"), +# "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), +# "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), +# "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), +# "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), +# "FY5253": Timestamp("2011-01-25 09:00:00"), +# "Week": Timestamp("2011-01-08 09:00:00"), +# "Easter": Timestamp("2011-04-24 09:00:00"), +# "Hour": Timestamp("2011-01-01 10:00:00"), +# "Minute": Timestamp("2011-01-01 09:01:00"), +# "Second": Timestamp("2011-01-01 09:00:01"), +# "Milli": Timestamp("2011-01-01 09:00:00.001000"), +# "Micro": Timestamp("2011-01-01 09:00:00.000001"), +# "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), +# } +# +# def test_immutable(self, offset_types): +# # GH#21341 check that __setattr__ raises +# offset = self._get_offset(offset_types) +# with pytest.raises(AttributeError): +# offset.normalize = True +# with pytest.raises(AttributeError): +# offset.n = 91 +# +# def test_return_type(self, offset_types): +# offset = self._get_offset(offset_types) +# +# # make sure that we are returning a Timestamp +# result = Timestamp("20080101") + offset +# assert isinstance(result, Timestamp) +# +# # make sure that we are returning NaT +# assert NaT + offset is NaT +# assert offset + NaT is NaT +# +# assert NaT - offset is NaT +# assert (-offset).apply(NaT) is NaT +# +# def test_offset_n(self, offset_types): +# offset = self._get_offset(offset_types) +# assert offset.n == 1 +# +# neg_offset = offset * -1 +# assert neg_offset.n == -1 +# +# mul_offset = offset * 3 +# assert mul_offset.n == 3 +# +# def test_offset_timedelta64_arg(self, offset_types): +# # check that offset._validate_n raises TypeError on a timedelt64 +# # object +# off = self._get_offset(offset_types) +# +# td64 = np.timedelta64(4567, "s") +# with pytest.raises(TypeError, match="argument must be an integer"): +# type(off)(n=td64, **off.kwds) +# +# def test_offset_mul_ndarray(self, offset_types): +# off = self._get_offset(offset_types) +# +# expected = np.array([[off, off * 2], [off * 3, off * 4]]) +# +# result = np.array([[1, 2], [3, 4]]) * off +# tm.assert_numpy_array_equal(result, expected) +# +# result = off * np.array([[1, 2], [3, 4]]) +# tm.assert_numpy_array_equal(result, expected) +# +# def test_offset_freqstr(self, offset_types): +# offset = self._get_offset(offset_types) +# +# freqstr = offset.freqstr +# if freqstr not in ("", "", "LWOM-SAT"): +# code = get_offset(freqstr) +# assert offset.rule_code == code +# +# def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): +# +# if normalize and issubclass(offset, Tick): +# # normalize=True disallowed for Tick subclasses GH#21427 +# return +# +# offset_s = self._get_offset(offset, normalize=normalize) +# func = getattr(offset_s, funcname) +# +# result = func(dt) +# assert isinstance(result, Timestamp) +# assert result == expected +# +# result = func(Timestamp(dt)) +# assert isinstance(result, Timestamp) +# assert result == expected +# +# # see gh-14101 +# exp_warning = None +# ts = Timestamp(dt) + Nano(5) +# +# if ( +# offset_s.__class__.__name__ == "DateOffset" +# and (funcname == "apply" or normalize) +# and ts.nanosecond > 0 +# ): +# exp_warning = UserWarning +# +# # test nanosecond is preserved +# with tm.assert_produces_warning(exp_warning, check_stacklevel=False): +# result = func(ts) +# assert isinstance(result, Timestamp) +# if normalize is False: +# assert result == expected + Nano(5) +# else: +# assert result == expected +# +# if isinstance(dt, np.datetime64): +# # test tz when input is datetime or Timestamp +# return +# +# for tz in self.timezones: +# expected_localize = expected.tz_localize(tz) +# tz_obj = timezones.maybe_get_tz(tz) +# dt_tz = conversion.localize_pydatetime(dt, tz_obj) +# +# result = func(dt_tz) +# assert isinstance(result, Timestamp) +# assert result == expected_localize +# +# result = func(Timestamp(dt, tz=tz)) +# assert isinstance(result, Timestamp) +# assert result == expected_localize +# +# # see gh-14101 +# exp_warning = None +# ts = Timestamp(dt, tz=tz) + Nano(5) +# +# if ( +# offset_s.__class__.__name__ == "DateOffset" +# and (funcname == "apply" or normalize) +# and ts.nanosecond > 0 +# ): +# exp_warning = UserWarning +# +# # test nanosecond is preserved +# with tm.assert_produces_warning(exp_warning, check_stacklevel=False): +# result = func(ts) +# assert isinstance(result, Timestamp) +# if normalize is False: +# assert result == expected_localize + Nano(5) +# else: +# assert result == expected_localize +# +# def test_apply(self, offset_types): +# sdt = datetime(2011, 1, 1, 9, 0) +# ndt = np_datetime64_compat("2011-01-01 09:00Z") +# +# for dt in [sdt, ndt]: +# expected = self.expecteds[offset_types.__name__] +# self._check_offsetfunc_works(offset_types, "apply", dt, expected) +# +# expected = Timestamp(expected.date()) +# self._check_offsetfunc_works( +# offset_types, "apply", dt, expected, normalize=True +# ) +# +# def test_rollforward(self, offset_types): +# expecteds = self.expecteds.copy() +# +# # result will not be changed if the target is on the offset +# no_changes = [ +# "Day", +# "MonthBegin", +# "SemiMonthBegin", +# "YearBegin", +# "Week", +# "Hour", +# "Minute", +# "Second", +# "Milli", +# "Micro", +# "Nano", +# "DateOffset", +# ] +# for n in no_changes: +# expecteds[n] = Timestamp("2011/01/01 09:00") +# +# expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") +# expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") +# +# # but be changed when normalize=True +# norm_expected = expecteds.copy() +# for k in norm_expected: +# norm_expected[k] = Timestamp(norm_expected[k].date()) +# +# normalized = { +# "Day": Timestamp("2011-01-02 00:00:00"), +# "DateOffset": Timestamp("2011-01-02 00:00:00"), +# "MonthBegin": Timestamp("2011-02-01 00:00:00"), +# "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), +# "YearBegin": Timestamp("2012-01-01 00:00:00"), +# "Week": Timestamp("2011-01-08 00:00:00"), +# "Hour": Timestamp("2011-01-01 00:00:00"), +# "Minute": Timestamp("2011-01-01 00:00:00"), +# "Second": Timestamp("2011-01-01 00:00:00"), +# "Milli": Timestamp("2011-01-01 00:00:00"), +# "Micro": Timestamp("2011-01-01 00:00:00"), +# } +# norm_expected.update(normalized) +# +# sdt = datetime(2011, 1, 1, 9, 0) +# ndt = np_datetime64_compat("2011-01-01 09:00Z") +# +# for dt in [sdt, ndt]: +# expected = expecteds[offset_types.__name__] +# self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) +# expected = norm_expected[offset_types.__name__] +# self._check_offsetfunc_works( +# offset_types, "rollforward", dt, expected, normalize=True +# ) +# +# def test_rollback(self, offset_types): +# expecteds = { +# "BusinessDay": Timestamp("2010-12-31 09:00:00"), +# "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), +# "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), +# "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), +# "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), +# "MonthEnd": Timestamp("2010-12-31 09:00:00"), +# "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), +# "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), +# "BYearBegin": Timestamp("2010-01-01 09:00:00"), +# "YearEnd": Timestamp("2010-12-31 09:00:00"), +# "BYearEnd": Timestamp("2010-12-31 09:00:00"), +# "QuarterBegin": Timestamp("2010-12-01 09:00:00"), +# "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), +# "QuarterEnd": Timestamp("2010-12-31 09:00:00"), +# "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), +# "BusinessHour": Timestamp("2010-12-31 17:00:00"), +# "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), +# "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), +# "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), +# "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), +# "FY5253": Timestamp("2010-01-26 09:00:00"), +# "Easter": Timestamp("2010-04-04 09:00:00"), +# } +# +# # result will not be changed if the target is on the offset +# for n in [ +# "Day", +# "MonthBegin", +# "SemiMonthBegin", +# "YearBegin", +# "Week", +# "Hour", +# "Minute", +# "Second", +# "Milli", +# "Micro", +# "Nano", +# "DateOffset", +# ]: +# expecteds[n] = Timestamp("2011/01/01 09:00") +# +# # but be changed when normalize=True +# norm_expected = expecteds.copy() +# for k in norm_expected: +# norm_expected[k] = Timestamp(norm_expected[k].date()) +# +# normalized = { +# "Day": Timestamp("2010-12-31 00:00:00"), +# "DateOffset": Timestamp("2010-12-31 00:00:00"), +# "MonthBegin": Timestamp("2010-12-01 00:00:00"), +# "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), +# "YearBegin": Timestamp("2010-01-01 00:00:00"), +# "Week": Timestamp("2010-12-25 00:00:00"), +# "Hour": Timestamp("2011-01-01 00:00:00"), +# "Minute": Timestamp("2011-01-01 00:00:00"), +# "Second": Timestamp("2011-01-01 00:00:00"), +# "Milli": Timestamp("2011-01-01 00:00:00"), +# "Micro": Timestamp("2011-01-01 00:00:00"), +# } +# norm_expected.update(normalized) +# +# sdt = datetime(2011, 1, 1, 9, 0) +# ndt = np_datetime64_compat("2011-01-01 09:00Z") +# +# for dt in [sdt, ndt]: +# expected = expecteds[offset_types.__name__] +# self._check_offsetfunc_works(offset_types, "rollback", dt, expected) +# +# expected = norm_expected[offset_types.__name__] +# self._check_offsetfunc_works( +# offset_types, "rollback", dt, expected, normalize=True +# ) +# +# def test_onOffset(self, offset_types): +# dt = self.expecteds[offset_types.__name__] +# offset_s = self._get_offset(offset_types) +# assert offset_s.onOffset(dt) +# +# # when normalize=True, onOffset checks time is 00:00:00 +# if issubclass(offset_types, Tick): +# # normalize=True disallowed for Tick subclasses GH#21427 +# return +# offset_n = self._get_offset(offset_types, normalize=True) +# assert not offset_n.onOffset(dt) +# +# if offset_types in (BusinessHour, CustomBusinessHour): +# # In default BusinessHour (9:00-17:00), normalized time +# # cannot be in business hour range +# return +# date = datetime(dt.year, dt.month, dt.day) +# assert offset_n.onOffset(date) +# +# def test_add(self, offset_types, tz_naive_fixture): +# tz = tz_naive_fixture +# dt = datetime(2011, 1, 1, 9, 0) +# +# offset_s = self._get_offset(offset_types) +# expected = self.expecteds[offset_types.__name__] +# +# result_dt = dt + offset_s +# result_ts = Timestamp(dt) + offset_s +# for result in [result_dt, result_ts]: +# assert isinstance(result, Timestamp) +# assert result == expected +# +# expected_localize = expected.tz_localize(tz) +# result = Timestamp(dt, tz=tz) + offset_s +# assert isinstance(result, Timestamp) +# assert result == expected_localize +# +# # normalize=True, disallowed for Tick subclasses GH#21427 +# if issubclass(offset_types, Tick): +# return +# offset_s = self._get_offset(offset_types, normalize=True) +# expected = Timestamp(expected.date()) +# +# result_dt = dt + offset_s +# result_ts = Timestamp(dt) + offset_s +# for result in [result_dt, result_ts]: +# assert isinstance(result, Timestamp) +# assert result == expected +# +# expected_localize = expected.tz_localize(tz) +# result = Timestamp(dt, tz=tz) + offset_s +# assert isinstance(result, Timestamp) +# assert result == expected_localize +# +# def test_pickle_v0_15_2(self, datapath): +# offsets = { +# "DateOffset": DateOffset(years=1), +# "MonthBegin": MonthBegin(1), +# "Day": Day(1), +# "YearBegin": YearBegin(1), +# "Week": Week(1), +# } +# +# pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") +# # This code was executed once on v0.15.2 to generate the pickle: +# # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) +# # +# tm.assert_dict_equal(offsets, read_pickle(pickle_path)) + + +# class TestBusinessDay(Base): +# _offset = BDay +# +# def setup_method(self, method): +# self.d = datetime(2008, 1, 1) +# +# self.offset = BDay() +# self.offset1 = self.offset +# self.offset2 = BDay(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 * BusinessDays>" +# +# if compat.PY37: +# expected = "" +# else: +# 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_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): +# assert self.offset2(self.d) == datetime(2008, 1, 3) +# +# def testRollback1(self): +# assert BDay(10).rollback(self.d) == self.d +# +# def testRollback2(self): +# assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) +# +# def testRollforward1(self): +# assert BDay(10).rollforward(self.d) == self.d +# +# def testRollforward2(self): +# assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) +# +# def test_roll_date_object(self): +# offset = BDay() +# +# 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) +# +# def test_onOffset(self): +# tests = [ +# (BDay(), datetime(2008, 1, 1), True), +# (BDay(), datetime(2008, 1, 5), False), +# ] +# +# for offset, d, expected in tests: +# assert_onOffset(offset, d, expected) +# +# apply_cases = [] # type: _ApplyCases +# apply_cases.append( +# ( +# BDay(), +# { +# 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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# 2 * BDay(), +# { +# 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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -BDay(), +# { +# 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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -2 * BDay(), +# { +# 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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BDay(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 + BDay(10) +# assert result == datetime(2012, 11, 6) +# +# result = dt + BDay(100) - BDay(100) +# assert result == dt +# +# off = BDay() * 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 +# +# off = BDay() * 10 +# rs = datetime(2014, 1, 5) + off # see #5890 +# xp = datetime(2014, 1, 17) +# assert rs == xp +# +# 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 TestBusinessHour(Base): +# _offset = BusinessHour +# +# def setup_method(self, method): +# self.d = datetime(2014, 7, 1, 10, 00) +# +# self.offset1 = BusinessHour() +# self.offset2 = BusinessHour(n=3) +# +# self.offset3 = BusinessHour(n=-1) +# self.offset4 = BusinessHour(n=-4) +# +# from datetime import time as dt_time +# +# self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) +# self.offset6 = BusinessHour(start="20:00", end="05:00") +# self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) +# self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) +# self.offset9 = BusinessHour( +# n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] +# ) +# self.offset10 = BusinessHour( +# n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] +# ) +# +# @pytest.mark.parametrize( +# "start,end,match", +# [ +# ( +# dt_time(11, 0, 5), +# "17:00", +# "time data must be specified only with hour and minute", +# ), +# ("AAA", "17:00", "time data must match '%H:%M' format"), +# ("14:00:05", "17:00", "time data must match '%H:%M' format"), +# ([], "17:00", "Must include at least 1 start time"), +# ("09:00", [], "Must include at least 1 end time"), +# ( +# ["09:00", "11:00"], +# "17:00", +# "number of starting time and ending time must be the same", +# ), +# ( +# ["09:00", "11:00"], +# ["10:00"], +# "number of starting time and ending time must be the same", +# ), +# ( +# ["09:00", "11:00"], +# ["12:00", "20:00"], +# r"invalid starting and ending time\(s\): opening hours should not " +# "touch or overlap with one another", +# ), +# ( +# ["12:00", "20:00"], +# ["09:00", "11:00"], +# r"invalid starting and ending time\(s\): opening hours should not " +# "touch or overlap with one another", +# ), +# ], +# ) +# def test_constructor_errors(self, start, end, match): +# with pytest.raises(ValueError, match=match): +# BusinessHour(start=start, end=end) +# +# 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.offset1) == "" +# assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" +# assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" +# assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" +# +# assert repr(self.offset5) == "" +# assert repr(self.offset6) == "" +# assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" +# assert repr(self.offset8) == "" +# assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" +# assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" +# +# def test_with_offset(self): +# expected = Timestamp("2014-07-01 13:00") +# +# assert self.d + BusinessHour() * 3 == expected +# assert self.d + BusinessHour(n=3) == expected +# +# @pytest.mark.parametrize( +# "offset_name", +# ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], +# ) +# def test_eq_attribute(self, offset_name): +# offset = getattr(self, offset_name) +# assert offset == offset +# +# @pytest.mark.parametrize( +# "offset1,offset2", +# [ +# (BusinessHour(start="09:00"), BusinessHour()), +# ( +# BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), +# BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), +# ), +# ], +# ) +# def test_eq(self, offset1, offset2): +# assert offset1 == offset2 +# +# @pytest.mark.parametrize( +# "offset1,offset2", +# [ +# (BusinessHour(), BusinessHour(-1)), +# (BusinessHour(start="09:00"), BusinessHour(start="09:01")), +# ( +# BusinessHour(start="09:00", end="17:00"), +# BusinessHour(start="17:00", end="09:01"), +# ), +# ( +# BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), +# BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), +# ), +# ], +# ) +# def test_neq(self, offset1, offset2): +# assert offset1 != offset2 +# +# @pytest.mark.parametrize( +# "offset_name", +# ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], +# ) +# def test_hash(self, offset_name): +# offset = getattr(self, offset_name) +# assert offset == offset +# +# def test_call(self): +# assert self.offset1(self.d) == datetime(2014, 7, 1, 11) +# assert self.offset2(self.d) == datetime(2014, 7, 1, 13) +# assert self.offset3(self.d) == datetime(2014, 6, 30, 17) +# assert self.offset4(self.d) == datetime(2014, 6, 30, 14) +# assert self.offset8(self.d) == datetime(2014, 7, 1, 11) +# assert self.offset9(self.d) == datetime(2014, 7, 1, 22) +# assert self.offset10(self.d) == datetime(2014, 7, 1, 1) +# +# def test_sub(self): +# # we have to override test_sub here because self.offset2 is not +# # defined as self._offset(2) +# off = self.offset2 +# msg = "Cannot subtract datetime from offset" +# with pytest.raises(TypeError, match=msg): +# off - self.d +# assert 2 * off - off == off +# +# assert self.d - self.offset2 == self.d + self._offset(-3) +# +# def testRollback1(self): +# assert self.offset1.rollback(self.d) == self.d +# assert self.offset2.rollback(self.d) == self.d +# assert self.offset3.rollback(self.d) == self.d +# assert self.offset4.rollback(self.d) == self.d +# assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) +# assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) +# assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) +# assert self.offset8.rollback(self.d) == self.d +# assert self.offset9.rollback(self.d) == self.d +# assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) +# +# d = datetime(2014, 7, 1, 0) +# assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) +# assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) +# assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) +# assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) +# assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) +# assert self.offset6.rollback(d) == d +# assert self.offset7.rollback(d) == d +# assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) +# assert self.offset9.rollback(d) == d +# assert self.offset10.rollback(d) == d +# +# assert self._offset(5).rollback(self.d) == self.d +# +# def testRollback2(self): +# assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( +# 2014, 7, 4, 17, 0 +# ) +# +# def testRollforward1(self): +# assert self.offset1.rollforward(self.d) == self.d +# assert self.offset2.rollforward(self.d) == self.d +# assert self.offset3.rollforward(self.d) == self.d +# assert self.offset4.rollforward(self.d) == self.d +# assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) +# assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) +# assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) +# assert self.offset8.rollforward(self.d) == self.d +# assert self.offset9.rollforward(self.d) == self.d +# assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) +# +# d = datetime(2014, 7, 1, 0) +# assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) +# assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) +# assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) +# assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) +# assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) +# assert self.offset6.rollforward(d) == d +# assert self.offset7.rollforward(d) == d +# assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) +# assert self.offset9.rollforward(d) == d +# assert self.offset10.rollforward(d) == d +# +# assert self._offset(5).rollforward(self.d) == self.d +# +# def testRollforward2(self): +# assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( +# 2014, 7, 7, 9 +# ) +# +# def test_roll_date_object(self): +# offset = BusinessHour() +# +# dt = datetime(2014, 7, 6, 15, 0) +# +# result = offset.rollback(dt) +# assert result == datetime(2014, 7, 4, 17) +# +# result = offset.rollforward(dt) +# assert result == datetime(2014, 7, 7, 9) +# +# normalize_cases = [] +# normalize_cases.append( +# ( +# BusinessHour(normalize=True), +# { +# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 2), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 2), +# datetime(2014, 7, 1, 23): datetime(2014, 7, 2), +# datetime(2014, 7, 1, 0): datetime(2014, 7, 1), +# datetime(2014, 7, 4, 15): datetime(2014, 7, 4), +# datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), +# datetime(2014, 7, 5, 23): datetime(2014, 7, 7), +# datetime(2014, 7, 6, 10): datetime(2014, 7, 7), +# }, +# ) +# ) +# +# normalize_cases.append( +# ( +# BusinessHour(-1, normalize=True), +# { +# datetime(2014, 7, 1, 8): datetime(2014, 6, 30), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 10): datetime(2014, 6, 30), +# datetime(2014, 7, 1, 0): datetime(2014, 6, 30), +# datetime(2014, 7, 7, 10): datetime(2014, 7, 4), +# datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), +# datetime(2014, 7, 5, 23): datetime(2014, 7, 4), +# datetime(2014, 7, 6, 10): datetime(2014, 7, 4), +# }, +# ) +# ) +# +# normalize_cases.append( +# ( +# BusinessHour(1, normalize=True, start="17:00", end="04:00"), +# { +# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 23): datetime(2014, 7, 2), +# datetime(2014, 7, 2, 2): datetime(2014, 7, 2), +# datetime(2014, 7, 2, 3): datetime(2014, 7, 2), +# datetime(2014, 7, 4, 23): datetime(2014, 7, 5), +# datetime(2014, 7, 5, 2): datetime(2014, 7, 5), +# datetime(2014, 7, 7, 2): datetime(2014, 7, 7), +# datetime(2014, 7, 7, 17): datetime(2014, 7, 7), +# }, +# ) +# ) +# +# @pytest.mark.parametrize("case", normalize_cases) +# def test_normalize(self, case): +# offset, cases = case +# for dt, expected in cases.items(): +# assert offset.apply(dt) == expected +# +# on_offset_cases = [] +# on_offset_cases.append( +# ( +# BusinessHour(), +# { +# datetime(2014, 7, 1, 9): True, +# datetime(2014, 7, 1, 8, 59): False, +# datetime(2014, 7, 1, 8): False, +# datetime(2014, 7, 1, 17): True, +# datetime(2014, 7, 1, 17, 1): False, +# datetime(2014, 7, 1, 18): False, +# datetime(2014, 7, 5, 9): False, +# datetime(2014, 7, 6, 12): False, +# }, +# ) +# ) +# +# on_offset_cases.append( +# ( +# BusinessHour(start="10:00", end="15:00"), +# { +# datetime(2014, 7, 1, 9): False, +# datetime(2014, 7, 1, 10): True, +# datetime(2014, 7, 1, 15): True, +# datetime(2014, 7, 1, 15, 1): False, +# datetime(2014, 7, 5, 12): False, +# datetime(2014, 7, 6, 12): False, +# }, +# ) +# ) +# +# on_offset_cases.append( +# ( +# BusinessHour(start="19:00", end="05:00"), +# { +# datetime(2014, 7, 1, 9, 0): False, +# datetime(2014, 7, 1, 10, 0): False, +# datetime(2014, 7, 1, 15): False, +# datetime(2014, 7, 1, 15, 1): False, +# datetime(2014, 7, 5, 12, 0): False, +# datetime(2014, 7, 6, 12, 0): False, +# datetime(2014, 7, 1, 19, 0): True, +# datetime(2014, 7, 2, 0, 0): True, +# datetime(2014, 7, 4, 23): True, +# datetime(2014, 7, 5, 1): True, +# datetime(2014, 7, 5, 5, 0): True, +# datetime(2014, 7, 6, 23, 0): False, +# datetime(2014, 7, 7, 3, 0): False, +# }, +# ) +# ) +# +# on_offset_cases.append( +# ( +# BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), +# { +# datetime(2014, 7, 1, 9): True, +# datetime(2014, 7, 1, 8, 59): False, +# datetime(2014, 7, 1, 8): False, +# datetime(2014, 7, 1, 17): True, +# datetime(2014, 7, 1, 17, 1): False, +# datetime(2014, 7, 1, 18): False, +# datetime(2014, 7, 5, 9): False, +# datetime(2014, 7, 6, 12): False, +# datetime(2014, 7, 1, 12, 30): False, +# }, +# ) +# ) +# +# on_offset_cases.append( +# ( +# BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), +# { +# datetime(2014, 7, 1, 9, 0): False, +# datetime(2014, 7, 1, 10, 0): False, +# datetime(2014, 7, 1, 15): False, +# datetime(2014, 7, 1, 15, 1): False, +# datetime(2014, 7, 5, 12, 0): False, +# datetime(2014, 7, 6, 12, 0): False, +# datetime(2014, 7, 1, 19, 0): True, +# datetime(2014, 7, 2, 0, 0): True, +# datetime(2014, 7, 4, 23): True, +# datetime(2014, 7, 5, 1): True, +# datetime(2014, 7, 5, 5, 0): True, +# datetime(2014, 7, 6, 23, 0): False, +# datetime(2014, 7, 7, 3, 0): False, +# datetime(2014, 7, 4, 22): False, +# }, +# ) +# ) +# +# @pytest.mark.parametrize("case", on_offset_cases) +# def test_onOffset(self, case): +# offset, cases = case +# for dt, expected in cases.items(): +# assert offset.onOffset(dt) == expected +# +# opening_time_cases = [] +# # opening time should be affected by sign of n, not by n's value and +# # end +# opening_time_cases.append( +# ( +# [ +# BusinessHour(), +# BusinessHour(n=2), +# BusinessHour(n=4), +# BusinessHour(end="10:00"), +# BusinessHour(n=2, end="4:00"), +# BusinessHour(n=4, end="15:00"), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 9), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 9), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 9), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 9), +# ), +# # if timestamp is on opening time, next opening time is +# # as it is +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 2, 9), +# ), +# datetime(2014, 7, 2, 10): ( +# datetime(2014, 7, 3, 9), +# datetime(2014, 7, 2, 9), +# ), +# # 2014-07-05 is saturday +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 4, 9), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 4, 9), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 4, 9), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 4, 9), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 4, 9), +# ), +# datetime(2014, 7, 7, 9, 1): ( +# datetime(2014, 7, 8, 9), +# datetime(2014, 7, 7, 9), +# ), +# }, +# ) +# ) +# +# opening_time_cases.append( +# ( +# [ +# BusinessHour(start="11:15"), +# BusinessHour(n=2, start="11:15"), +# BusinessHour(n=3, start="11:15"), +# BusinessHour(start="11:15", end="10:00"), +# BusinessHour(n=2, start="11:15", end="4:00"), +# BusinessHour(n=3, start="11:15", end="15:00"), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 7, 1, 11, 15), +# datetime(2014, 6, 30, 11, 15), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 11, 15), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 11, 15), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 11, 15), +# ), +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 11, 15), +# ), +# datetime(2014, 7, 2, 10): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 11, 15), +# ), +# datetime(2014, 7, 2, 11, 15): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 2, 11, 15), +# ), +# datetime(2014, 7, 2, 11, 15, 1): ( +# datetime(2014, 7, 3, 11, 15), +# datetime(2014, 7, 2, 11, 15), +# ), +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 11, 15), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 4, 11, 15), +# datetime(2014, 7, 3, 11, 15), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 11, 15), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 11, 15), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 11, 15), +# ), +# datetime(2014, 7, 7, 9, 1): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 11, 15), +# ), +# }, +# ) +# ) +# +# opening_time_cases.append( +# ( +# [ +# BusinessHour(-1), +# BusinessHour(n=-2), +# BusinessHour(n=-4), +# BusinessHour(n=-1, end="10:00"), +# BusinessHour(n=-2, end="4:00"), +# BusinessHour(n=-4, end="15:00"), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 7, 1, 9), +# datetime(2014, 7, 2, 9), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 1, 9), +# datetime(2014, 7, 2, 9), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 1, 9), +# datetime(2014, 7, 2, 9), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 1, 9), +# datetime(2014, 7, 2, 9), +# ), +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 2, 9), +# ), +# datetime(2014, 7, 2, 10): ( +# datetime(2014, 7, 2, 9), +# datetime(2014, 7, 3, 9), +# ), +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 4, 9), +# datetime(2014, 7, 7, 9), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 4, 9), +# datetime(2014, 7, 7, 9), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 4, 9), +# datetime(2014, 7, 7, 9), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 4, 9), +# datetime(2014, 7, 7, 9), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 4, 9), +# datetime(2014, 7, 7, 9), +# ), +# datetime(2014, 7, 7, 9): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 7, 9), +# ), +# datetime(2014, 7, 7, 9, 1): ( +# datetime(2014, 7, 7, 9), +# datetime(2014, 7, 8, 9), +# ), +# }, +# ) +# ) +# +# opening_time_cases.append( +# ( +# [ +# BusinessHour(start="17:00", end="05:00"), +# BusinessHour(n=3, start="17:00", end="03:00"), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 6, 30, 17), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 2, 17), +# datetime(2014, 7, 1, 17), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 2, 17), +# datetime(2014, 7, 1, 17), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 2, 17), +# datetime(2014, 7, 1, 17), +# ), +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 2, 17), +# datetime(2014, 7, 1, 17), +# ), +# datetime(2014, 7, 4, 17): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 7, 17), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 3, 17), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 7, 17), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 7, 17), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 7, 17), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 7, 17, 1): ( +# datetime(2014, 7, 8, 17), +# datetime(2014, 7, 7, 17), +# ), +# }, +# ) +# ) +# +# opening_time_cases.append( +# ( +# [ +# BusinessHour(-1, start="17:00", end="05:00"), +# BusinessHour(n=-2, start="17:00", end="03:00"), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 6, 30, 17), +# datetime(2014, 7, 1, 17), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 2, 16, 59): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 17), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 3, 17), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 17), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 17), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 17), +# ), +# datetime(2014, 7, 7, 18): ( +# datetime(2014, 7, 7, 17), +# datetime(2014, 7, 8, 17), +# ), +# }, +# ) +# ) +# +# opening_time_cases.append( +# ( +# [ +# BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), +# BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), +# BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), +# BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), +# BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 7, 1, 11, 15), +# datetime(2014, 6, 30, 15), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 15), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 15), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 15), +# ), +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 15), +# ), +# datetime(2014, 7, 2, 10): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 1, 15), +# ), +# datetime(2014, 7, 2, 11, 15): ( +# datetime(2014, 7, 2, 11, 15), +# datetime(2014, 7, 2, 11, 15), +# ), +# datetime(2014, 7, 2, 11, 15, 1): ( +# datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 11, 15), +# ), +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 15), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 4, 11, 15), +# datetime(2014, 7, 3, 15), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 15), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 15), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 15), +# ), +# datetime(2014, 7, 7, 9, 1): ( +# datetime(2014, 7, 7, 11, 15), +# datetime(2014, 7, 4, 15), +# ), +# datetime(2014, 7, 7, 12): ( +# datetime(2014, 7, 7, 15), +# datetime(2014, 7, 7, 11, 15), +# ), +# }, +# ) +# ) +# +# opening_time_cases.append( +# ( +# [ +# BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), +# BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), +# ], +# { +# datetime(2014, 7, 1, 11): ( +# datetime(2014, 7, 1, 8), +# datetime(2014, 7, 1, 17), +# ), +# datetime(2014, 7, 1, 18): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 8), +# ), +# datetime(2014, 7, 1, 23): ( +# datetime(2014, 7, 1, 17), +# datetime(2014, 7, 2, 8), +# ), +# datetime(2014, 7, 2, 8): ( +# datetime(2014, 7, 2, 8), +# datetime(2014, 7, 2, 8), +# ), +# datetime(2014, 7, 2, 9): ( +# datetime(2014, 7, 2, 8), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 2, 16, 59): ( +# datetime(2014, 7, 2, 8), +# datetime(2014, 7, 2, 17), +# ), +# datetime(2014, 7, 5, 10): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 8), +# ), +# datetime(2014, 7, 4, 10): ( +# datetime(2014, 7, 4, 8), +# datetime(2014, 7, 4, 17), +# ), +# datetime(2014, 7, 4, 23): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 8), +# ), +# datetime(2014, 7, 6, 10): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 8), +# ), +# datetime(2014, 7, 7, 5): ( +# datetime(2014, 7, 4, 17), +# datetime(2014, 7, 7, 8), +# ), +# datetime(2014, 7, 7, 18): ( +# datetime(2014, 7, 7, 17), +# datetime(2014, 7, 8, 8), +# ), +# }, +# ) +# ) +# +# @pytest.mark.parametrize("case", opening_time_cases) +# def test_opening_time(self, case): +# _offsets, cases = case +# for offset in _offsets: +# for dt, (exp_next, exp_prev) in cases.items(): +# assert offset._next_opening_time(dt) == exp_next +# assert offset._prev_opening_time(dt) == exp_prev +# +# apply_cases = [] +# apply_cases.append( +# ( +# BusinessHour(), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), +# # out of business hours +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), +# # saturday +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), +# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(4), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), +# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(-1), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), +# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), +# datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), +# # out of business hours +# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), +# # saturday +# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), +# datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), +# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), +# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(-4), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), +# datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), +# datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), +# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), +# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(start="13:00", end="16:00"), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), +# datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=2, start="13:00", end="16:00"), +# { +# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), +# datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), +# datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), +# datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=-1, start="13:00", end="16:00"), +# { +# datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), +# datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=-3, start="10:00", end="16:00"), +# { +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), +# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), +# datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), +# datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), +# datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), +# datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), +# datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(start="19:00", end="05:00"), +# { +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), +# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), +# datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), +# datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), +# datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), +# datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), +# datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), +# datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), +# datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), +# datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=-1, start="19:00", end="05:00"), +# { +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), +# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), +# datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), +# datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), +# datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), +# datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), +# datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), +# datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), +# }, +# ) +# ) +# +# # long business hours (see gh-26381) +# apply_cases.append( +# ( +# BusinessHour(n=4, start="00:00", end="23:00"), +# { +# datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), +# datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), +# datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), +# datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), +# datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), +# datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=-4, start="00:00", end="23:00"), +# { +# datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), +# datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), +# datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), +# datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), +# datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), +# datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), +# }, +# ) +# ) +# +# # multiple business hours +# apply_cases.append( +# ( +# BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), +# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), +# # out of business hours +# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), +# # saturday +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), +# datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), +# datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), +# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), +# datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), +# datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), +# datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), +# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), +# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), +# { +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), +# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), +# datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), +# datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), +# datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), +# datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), +# datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), +# datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), +# datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), +# datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), +# datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), +# }, +# ) +# ) +# +# @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) +# +# apply_large_n_cases = [] +# # A week later +# apply_large_n_cases.append( +# ( +# BusinessHour(40), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), +# datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), +# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), +# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), +# }, +# ) +# ) +# +# # 3 days and 1 hour before +# apply_large_n_cases.append( +# ( +# BusinessHour(-25), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), +# datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), +# datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), +# datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), +# datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), +# datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), +# datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), +# datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), +# datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), +# datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), +# }, +# ) +# ) +# +# # 5 days and 3 hours later +# apply_large_n_cases.append( +# ( +# BusinessHour(28, start="21:00", end="02:00"), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), +# datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), +# datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), +# datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), +# datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), +# datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), +# datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), +# datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), +# datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), +# datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), +# datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), +# datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), +# }, +# ) +# ) +# +# # large n for multiple opening hours (3 days and 1 hour before) +# apply_large_n_cases.append( +# ( +# BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), +# datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), +# datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), +# datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), +# datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), +# datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), +# datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), +# datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), +# datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), +# datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), +# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), +# datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), +# }, +# ) +# ) +# +# # 5 days and 3 hours later +# apply_large_n_cases.append( +# ( +# BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), +# datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), +# datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), +# datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), +# datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), +# datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), +# datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), +# datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), +# datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), +# datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), +# datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), +# datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), +# datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), +# datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), +# }, +# ) +# ) +# +# @pytest.mark.parametrize("case", apply_large_n_cases) +# def test_apply_large_n(self, case): +# offset, cases = case +# for base, expected in cases.items(): +# assert_offset_equal(offset, base, expected) +# +# def test_apply_nanoseconds(self): +# tests = [] +# +# tests.append( +# ( +# BusinessHour(), +# { +# Timestamp("2014-07-04 15:00") +# + Nano(5): Timestamp("2014-07-04 16:00") +# + Nano(5), +# Timestamp("2014-07-04 16:00") +# + Nano(5): Timestamp("2014-07-07 09:00") +# + Nano(5), +# Timestamp("2014-07-04 16:00") +# - Nano(5): Timestamp("2014-07-04 17:00") +# - Nano(5), +# }, +# ) +# ) +# +# tests.append( +# ( +# BusinessHour(-1), +# { +# Timestamp("2014-07-04 15:00") +# + Nano(5): Timestamp("2014-07-04 14:00") +# + Nano(5), +# Timestamp("2014-07-04 10:00") +# + Nano(5): Timestamp("2014-07-04 09:00") +# + Nano(5), +# Timestamp("2014-07-04 10:00") +# - Nano(5): Timestamp("2014-07-03 17:00") +# - Nano(5), +# }, +# ) +# ) +# +# for offset, cases in tests: +# for base, expected in cases.items(): +# assert_offset_equal(offset, base, expected) +# +# def test_datetimeindex(self): +# idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") +# idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") +# idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") +# expected = DatetimeIndex( +# [ +# "2014-07-04 15:00", +# "2014-07-04 16:00", +# "2014-07-07 09:00", +# "2014-07-07 10:00", +# "2014-07-07 11:00", +# "2014-07-07 12:00", +# "2014-07-07 13:00", +# "2014-07-07 14:00", +# "2014-07-07 15:00", +# "2014-07-07 16:00", +# "2014-07-08 09:00", +# "2014-07-08 10:00", +# ], +# freq="BH", +# ) +# for idx in [idx1, idx2, idx3]: +# tm.assert_index_equal(idx, expected) +# +# idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") +# idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") +# idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") +# +# expected = DatetimeIndex( +# [ +# "2014-07-04 15:45", +# "2014-07-04 16:45", +# "2014-07-07 09:45", +# "2014-07-07 10:45", +# "2014-07-07 11:45", +# "2014-07-07 12:45", +# "2014-07-07 13:45", +# "2014-07-07 14:45", +# "2014-07-07 15:45", +# "2014-07-07 16:45", +# "2014-07-08 09:45", +# "2014-07-08 10:45", +# ], +# freq="BH", +# ) +# expected = idx1 +# for idx in [idx1, idx2, idx3]: +# tm.assert_index_equal(idx, expected) + + +# class TestCustomBusinessHour(Base): +# _offset = CustomBusinessHour +# holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] +# +# def setup_method(self, method): +# # 2014 Calendar to check custom holidays +# # Sun Mon Tue Wed Thu Fri Sat +# # 6/22 23 24 25 26 27 28 +# # 29 30 7/1 2 3 4 5 +# # 6 7 8 9 10 11 12 +# self.d = datetime(2014, 7, 1, 10, 00) +# self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") +# +# self.offset2 = CustomBusinessHour(holidays=self.holidays) +# +# def test_constructor_errors(self): +# from datetime import time as dt_time +# +# with pytest.raises(ValueError): +# CustomBusinessHour(start=dt_time(11, 0, 5)) +# with pytest.raises(ValueError): +# CustomBusinessHour(start="AAA") +# with pytest.raises(ValueError): +# CustomBusinessHour(start="14:00:05") +# +# 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.offset1) == "" +# assert repr(self.offset2) == "" +# +# def test_with_offset(self): +# expected = Timestamp("2014-07-01 13:00") +# +# assert self.d + CustomBusinessHour() * 3 == expected +# assert self.d + CustomBusinessHour(n=3) == expected +# +# def test_eq(self): +# for offset in [self.offset1, self.offset2]: +# assert offset == offset +# +# assert CustomBusinessHour() != CustomBusinessHour(-1) +# assert CustomBusinessHour(start="09:00") == CustomBusinessHour() +# assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") +# assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( +# start="17:00", end="09:01" +# ) +# +# assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( +# weekmask="Mon Tue Wed Thu Fri" +# ) +# assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( +# holidays=["2014-06-28"] +# ) +# +# def test_sub(self): +# # override the Base.test_sub implementation because self.offset2 is +# # defined differently in this class than the test expects +# pass +# +# def test_hash(self): +# assert hash(self.offset1) == hash(self.offset1) +# assert hash(self.offset2) == hash(self.offset2) +# +# def test_call(self): +# assert self.offset1(self.d) == datetime(2014, 7, 1, 11) +# assert self.offset2(self.d) == datetime(2014, 7, 1, 11) +# +# def testRollback1(self): +# assert self.offset1.rollback(self.d) == self.d +# assert self.offset2.rollback(self.d) == self.d +# +# d = datetime(2014, 7, 1, 0) +# +# # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) +# assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) +# +# # 2014/6/30 and 2014/6/27 are holidays +# assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) +# +# def testRollback2(self): +# assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( +# 2014, 7, 4, 17, 0 +# ) +# +# def testRollforward1(self): +# assert self.offset1.rollforward(self.d) == self.d +# assert self.offset2.rollforward(self.d) == self.d +# +# d = datetime(2014, 7, 1, 0) +# assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) +# assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) +# +# def testRollforward2(self): +# assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( +# 2014, 7, 7, 9 +# ) +# +# def test_roll_date_object(self): +# offset = BusinessHour() +# +# dt = datetime(2014, 7, 6, 15, 0) +# +# result = offset.rollback(dt) +# assert result == datetime(2014, 7, 4, 17) +# +# result = offset.rollforward(dt) +# assert result == datetime(2014, 7, 7, 9) +# +# normalize_cases = [] +# normalize_cases.append( +# ( +# CustomBusinessHour(normalize=True, holidays=holidays), +# { +# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 3), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 3), +# datetime(2014, 7, 1, 23): datetime(2014, 7, 3), +# datetime(2014, 7, 1, 0): datetime(2014, 7, 1), +# datetime(2014, 7, 4, 15): datetime(2014, 7, 4), +# datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), +# datetime(2014, 7, 5, 23): datetime(2014, 7, 7), +# datetime(2014, 7, 6, 10): datetime(2014, 7, 7), +# }, +# ) +# ) +# +# normalize_cases.append( +# ( +# CustomBusinessHour(-1, normalize=True, holidays=holidays), +# { +# datetime(2014, 7, 1, 8): datetime(2014, 6, 26), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 10): datetime(2014, 6, 26), +# datetime(2014, 7, 1, 0): datetime(2014, 6, 26), +# datetime(2014, 7, 7, 10): datetime(2014, 7, 4), +# datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), +# datetime(2014, 7, 5, 23): datetime(2014, 7, 4), +# datetime(2014, 7, 6, 10): datetime(2014, 7, 4), +# }, +# ) +# ) +# +# normalize_cases.append( +# ( +# CustomBusinessHour( +# 1, normalize=True, start="17:00", end="04:00", holidays=holidays +# ), +# { +# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), +# datetime(2014, 7, 1, 23): datetime(2014, 7, 2), +# datetime(2014, 7, 2, 2): datetime(2014, 7, 2), +# datetime(2014, 7, 2, 3): datetime(2014, 7, 3), +# datetime(2014, 7, 4, 23): datetime(2014, 7, 5), +# datetime(2014, 7, 5, 2): datetime(2014, 7, 5), +# datetime(2014, 7, 7, 2): datetime(2014, 7, 7), +# datetime(2014, 7, 7, 17): datetime(2014, 7, 7), +# }, +# ) +# ) +# +# @pytest.mark.parametrize("norm_cases", normalize_cases) +# def test_normalize(self, norm_cases): +# offset, cases = norm_cases +# for dt, expected in cases.items(): +# assert offset.apply(dt) == expected +# +# def test_onOffset(self): +# tests = [] +# +# tests.append( +# ( +# CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), +# { +# datetime(2014, 7, 1, 9): False, +# datetime(2014, 7, 1, 10): True, +# datetime(2014, 7, 1, 15): True, +# datetime(2014, 7, 1, 15, 1): False, +# datetime(2014, 7, 5, 12): False, +# datetime(2014, 7, 6, 12): False, +# }, +# ) +# ) +# +# for offset, cases in tests: +# for dt, expected in cases.items(): +# assert offset.onOffset(dt) == expected +# +# apply_cases = [] +# apply_cases.append( +# ( +# CustomBusinessHour(holidays=holidays), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), +# datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), +# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), +# # out of business hours +# datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), +# # saturday +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), +# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# CustomBusinessHour(4, holidays=holidays), +# { +# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), +# datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), +# datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), +# datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), +# datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), +# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), +# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), +# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), +# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), +# }, +# ) +# ) +# +# @pytest.mark.parametrize("apply_case", apply_cases) +# def test_apply(self, apply_case): +# offset, cases = apply_case +# for base, expected in cases.items(): +# assert_offset_equal(offset, base, expected) +# +# nano_cases = [] +# nano_cases.append( +# ( +# CustomBusinessHour(holidays=holidays), +# { +# Timestamp("2014-07-01 15:00") +# + Nano(5): Timestamp("2014-07-01 16:00") +# + Nano(5), +# Timestamp("2014-07-01 16:00") +# + Nano(5): Timestamp("2014-07-03 09:00") +# + Nano(5), +# Timestamp("2014-07-01 16:00") +# - Nano(5): Timestamp("2014-07-01 17:00") +# - Nano(5), +# }, +# ) +# ) +# +# nano_cases.append( +# ( +# CustomBusinessHour(-1, holidays=holidays), +# { +# Timestamp("2014-07-01 15:00") +# + Nano(5): Timestamp("2014-07-01 14:00") +# + Nano(5), +# Timestamp("2014-07-01 10:00") +# + Nano(5): Timestamp("2014-07-01 09:00") +# + Nano(5), +# Timestamp("2014-07-01 10:00") +# - Nano(5): Timestamp("2014-06-26 17:00") +# - Nano(5), +# }, +# ) +# ) +# +# @pytest.mark.parametrize("nano_case", nano_cases) +# def test_apply_nanoseconds(self, nano_case): +# offset, cases = nano_case +# for base, expected in cases.items(): +# assert_offset_equal(offset, base, expected) + + +# 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>" +# +# if compat.PY37: +# expected = "" +# else: +# 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_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): +# 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_onOffset(self, case): +# offset, d, expected = case +# assert_onOffset(offset, d, expected) +# +# apply_cases = [] # type: _ApplyCases +# apply_cases.append( +# ( +# 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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# 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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -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), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# 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 class CustomBusinessMonthBase: @@ -2770,301 +2771,301 @@ def test_copy(self): assert off == off.copy() -class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): - _offset = CBMonthEnd - - 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 * CustomBusinessMonthEnds>" - - def testCall(self): - assert self.offset2(self.d) == datetime(2008, 2, 29) - - def testRollback1(self): - assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - - def testRollback2(self): - assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) - - def testRollforward1(self): - assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) - - def test_roll_date_object(self): - offset = CBMonthEnd() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 8, 31) - - result = offset.rollforward(dt) - assert result == datetime(2012, 9, 28) - - 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 = [ - (CBMonthEnd(), datetime(2008, 1, 31), True), - (CBMonthEnd(), datetime(2008, 1, 1), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, d, expected = case - assert_onOffset(offset, d, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 2, 7): datetime(2008, 2, 29), - }, - ) - ) - - apply_cases.append( - ( - 2 * CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 2, 29), - datetime(2008, 2, 7): datetime(2008, 3, 31), - }, - ) - ) - - apply_cases.append( - ( - -CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2007, 12, 31), - datetime(2008, 2, 8): datetime(2008, 1, 31), - }, - ) - ) - - apply_cases.append( - ( - -2 * CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2007, 11, 30), - datetime(2008, 2, 9): datetime(2007, 12, 31), - }, - ) - ) - - apply_cases.append( - ( - CBMonthEnd(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 2, 7): datetime(2008, 2, 29), - }, - ) - ) - - @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 + CBMonthEnd(10) - assert result == datetime(2013, 7, 31) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CBMonthEnd() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 7, 29) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - xp = datetime(2012, 5, 31) - assert rs == xp - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] - bm_offset = CBMonthEnd(holidays=holidays) - dt = datetime(2012, 1, 1) - assert dt + bm_offset == datetime(2012, 1, 30) - assert dt + 2 * bm_offset == datetime(2012, 2, 27) - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_datetimeindex(self): - from pandas.tseries.holiday import USFederalHolidayCalendar - - hcal = USFederalHolidayCalendar() - freq = CBMonthEnd(calendar=hcal) - - assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ - 0 - ] == datetime(2012, 1, 31) - - -class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): - _offset = CBMonthBegin - - 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 * CustomBusinessMonthBegins>" - - def testCall(self): - assert self.offset2(self.d) == datetime(2008, 3, 3) - - def testRollback1(self): - assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - - def testRollback2(self): - assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) - - def testRollforward1(self): - assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) - - def test_roll_date_object(self): - offset = CBMonthBegin() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 9, 3) - - result = offset.rollforward(dt) - assert result == datetime(2012, 10, 1) - - 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 = [ - (CBMonthBegin(), datetime(2008, 1, 1), True), - (CBMonthBegin(), datetime(2008, 1, 31), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, dt, expected = case - assert_onOffset(offset, dt, expected) - - apply_cases = [] # type: _ApplyCases - apply_cases.append( - ( - CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 2, 1), - datetime(2008, 2, 7): datetime(2008, 3, 3), - }, - ) - ) - - apply_cases.append( - ( - 2 * CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 3, 3), - datetime(2008, 2, 7): datetime(2008, 4, 1), - }, - ) - ) - - apply_cases.append( - ( - -CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2007, 12, 3), - datetime(2008, 2, 8): datetime(2008, 2, 1), - }, - ) - ) - - apply_cases.append( - ( - -2 * CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2007, 11, 1), - datetime(2008, 2, 9): datetime(2008, 1, 1), - }, - ) - ) - - apply_cases.append( - ( - CBMonthBegin(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 7): datetime(2008, 2, 1), - }, - ) - ) - - @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 + CBMonthBegin(10) - assert result == datetime(2013, 8, 1) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CBMonthBegin() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 7, 1) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - - xp = datetime(2012, 6, 1) - assert rs == xp - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] - bm_offset = CBMonthBegin(holidays=holidays) - dt = datetime(2012, 1, 1) - - assert dt + bm_offset == datetime(2012, 1, 2) - assert dt + 2 * bm_offset == datetime(2012, 2, 3) - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_datetimeindex(self): - hcal = USFederalHolidayCalendar() - cbmb = CBMonthBegin(calendar=hcal) - assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ - 0 - ] == datetime(2012, 1, 3) +# class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): +# _offset = CBMonthEnd +# +# 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 * CustomBusinessMonthEnds>" +# +# def testCall(self): +# assert self.offset2(self.d) == datetime(2008, 2, 29) +# +# def testRollback1(self): +# assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) +# +# def testRollback2(self): +# assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) +# +# def testRollforward1(self): +# assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) +# +# def test_roll_date_object(self): +# offset = CBMonthEnd() +# +# dt = date(2012, 9, 15) +# +# result = offset.rollback(dt) +# assert result == datetime(2012, 8, 31) +# +# result = offset.rollforward(dt) +# assert result == datetime(2012, 9, 28) +# +# 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 = [ +# (CBMonthEnd(), datetime(2008, 1, 31), True), +# (CBMonthEnd(), datetime(2008, 1, 1), False), +# ] +# +# @pytest.mark.parametrize("case", on_offset_cases) +# def test_onOffset(self, case): +# offset, d, expected = case +# assert_onOffset(offset, d, expected) +# +# apply_cases = [] # type: _ApplyCases +# apply_cases.append( +# ( +# CBMonthEnd(), +# { +# datetime(2008, 1, 1): datetime(2008, 1, 31), +# datetime(2008, 2, 7): datetime(2008, 2, 29), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# 2 * CBMonthEnd(), +# { +# datetime(2008, 1, 1): datetime(2008, 2, 29), +# datetime(2008, 2, 7): datetime(2008, 3, 31), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -CBMonthEnd(), +# { +# datetime(2008, 1, 1): datetime(2007, 12, 31), +# datetime(2008, 2, 8): datetime(2008, 1, 31), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -2 * CBMonthEnd(), +# { +# datetime(2008, 1, 1): datetime(2007, 11, 30), +# datetime(2008, 2, 9): datetime(2007, 12, 31), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# CBMonthEnd(0), +# { +# datetime(2008, 1, 1): datetime(2008, 1, 31), +# datetime(2008, 2, 7): datetime(2008, 2, 29), +# }, +# ) +# ) +# +# @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 + CBMonthEnd(10) +# assert result == datetime(2013, 7, 31) +# +# result = dt + CDay(100) - CDay(100) +# assert result == dt +# +# off = CBMonthEnd() * 6 +# rs = datetime(2012, 1, 1) - off +# xp = datetime(2011, 7, 29) +# assert rs == xp +# +# st = datetime(2011, 12, 18) +# rs = st + off +# xp = datetime(2012, 5, 31) +# assert rs == xp +# +# def test_holidays(self): +# # Define a TradingDay offset +# holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] +# bm_offset = CBMonthEnd(holidays=holidays) +# dt = datetime(2012, 1, 1) +# assert dt + bm_offset == datetime(2012, 1, 30) +# assert dt + 2 * bm_offset == datetime(2012, 2, 27) +# +# @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") +# def test_datetimeindex(self): +# from pandas.tseries.holiday import USFederalHolidayCalendar +# +# hcal = USFederalHolidayCalendar() +# freq = CBMonthEnd(calendar=hcal) +# +# assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ +# 0 +# ] == datetime(2012, 1, 31) + + +# class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): +# _offset = CBMonthBegin +# +# 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 * CustomBusinessMonthBegins>" +# +# def testCall(self): +# assert self.offset2(self.d) == datetime(2008, 3, 3) +# +# def testRollback1(self): +# assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) +# +# def testRollback2(self): +# assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) +# +# def testRollforward1(self): +# assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) +# +# def test_roll_date_object(self): +# offset = CBMonthBegin() +# +# dt = date(2012, 9, 15) +# +# result = offset.rollback(dt) +# assert result == datetime(2012, 9, 3) +# +# result = offset.rollforward(dt) +# assert result == datetime(2012, 10, 1) +# +# 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 = [ +# (CBMonthBegin(), datetime(2008, 1, 1), True), +# (CBMonthBegin(), datetime(2008, 1, 31), False), +# ] +# +# @pytest.mark.parametrize("case", on_offset_cases) +# def test_onOffset(self, case): +# offset, dt, expected = case +# assert_onOffset(offset, dt, expected) +# +# apply_cases = [] # type: _ApplyCases +# apply_cases.append( +# ( +# CBMonthBegin(), +# { +# datetime(2008, 1, 1): datetime(2008, 2, 1), +# datetime(2008, 2, 7): datetime(2008, 3, 3), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# 2 * CBMonthBegin(), +# { +# datetime(2008, 1, 1): datetime(2008, 3, 3), +# datetime(2008, 2, 7): datetime(2008, 4, 1), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -CBMonthBegin(), +# { +# datetime(2008, 1, 1): datetime(2007, 12, 3), +# datetime(2008, 2, 8): datetime(2008, 2, 1), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# -2 * CBMonthBegin(), +# { +# datetime(2008, 1, 1): datetime(2007, 11, 1), +# datetime(2008, 2, 9): datetime(2008, 1, 1), +# }, +# ) +# ) +# +# apply_cases.append( +# ( +# CBMonthBegin(0), +# { +# datetime(2008, 1, 1): datetime(2008, 1, 1), +# datetime(2008, 1, 7): datetime(2008, 2, 1), +# }, +# ) +# ) +# +# @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 + CBMonthBegin(10) +# assert result == datetime(2013, 8, 1) +# +# result = dt + CDay(100) - CDay(100) +# assert result == dt +# +# off = CBMonthBegin() * 6 +# rs = datetime(2012, 1, 1) - off +# xp = datetime(2011, 7, 1) +# assert rs == xp +# +# st = datetime(2011, 12, 18) +# rs = st + off +# +# xp = datetime(2012, 6, 1) +# assert rs == xp +# +# def test_holidays(self): +# # Define a TradingDay offset +# holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] +# bm_offset = CBMonthBegin(holidays=holidays) +# dt = datetime(2012, 1, 1) +# +# assert dt + bm_offset == datetime(2012, 1, 2) +# assert dt + 2 * bm_offset == datetime(2012, 2, 3) +# +# @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") +# def test_datetimeindex(self): +# hcal = USFederalHolidayCalendar() +# cbmb = CBMonthBegin(calendar=hcal) +# assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ +# 0 +# ] == datetime(2012, 1, 3) class TestOffsetNames: @@ -3096,11 +3097,11 @@ def test_get_offset(): ) -def test_get_offset_legacy(): - pairs = [("w@Sat", Week(weekday=5))] - for name, expected in pairs: - with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): - get_offset(name) +# def test_get_offset_legacy(): +# pairs = [("w@Sat", Week(weekday=5))] +# for name, expected in pairs: +# with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): +# get_offset(name) class TestOffsetAliases: @@ -3210,160 +3211,160 @@ def get_utc_offset_hours(ts): return (o.days * 24 * 3600 + o.seconds) / 3600.0 -class TestDST: - """ - test DateOffset additions over Daylight Savings Time - """ - - # one microsecond before the DST transition - ts_pre_fallback = "2013-11-03 01:59:59.999999" - ts_pre_springfwd = "2013-03-10 01:59:59.999999" - - # test both basic names and dateutil timezones - timezone_utc_offsets = { - "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), - "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), - } - valid_date_offsets_singular = [ - "weekday", - "day", - "hour", - "minute", - "second", - "microsecond", - ] - valid_date_offsets_plural = [ - "weeks", - "days", - "hours", - "minutes", - "seconds", - "milliseconds", - "microseconds", - ] - - def _test_all_offsets(self, n, **kwds): - valid_offsets = ( - self.valid_date_offsets_plural - if n > 1 - else self.valid_date_offsets_singular - ) - - for name in valid_offsets: - self._test_offset(offset_name=name, offset_n=n, **kwds) - - def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): - offset = DateOffset(**{offset_name: offset_n}) - - t = tstart + offset - if expected_utc_offset is not None: - assert get_utc_offset_hours(t) == expected_utc_offset - - if offset_name == "weeks": - # dates should match - assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() - # expect the same day of week, hour of day, minute, second, ... - assert ( - t.dayofweek == tstart.dayofweek - and t.hour == tstart.hour - and t.minute == tstart.minute - and t.second == tstart.second - ) - elif offset_name == "days": - # dates should match - assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() - # expect the same hour of day, minute, second, ... - assert ( - t.hour == tstart.hour - and t.minute == tstart.minute - and t.second == tstart.second - ) - elif offset_name in self.valid_date_offsets_singular: - # expect the singular offset value to match between tstart and t - datepart_offset = getattr( - t, offset_name if offset_name != "weekday" else "dayofweek" - ) - assert datepart_offset == offset.kwds[offset_name] - else: - # the offset should be the same as if it was done in UTC - assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") - - def _make_timestamp(self, string, hrs_offset, tz): - if hrs_offset >= 0: - offset_string = "{hrs:02d}00".format(hrs=hrs_offset) - else: - offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) - return Timestamp(string + offset_string).tz_convert(tz) - - def test_springforward_plural(self): - # test moving from standard to daylight savings - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - hrs_post = utc_offsets["utc_offset_daylight"] - self._test_all_offsets( - n=3, - tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), - expected_utc_offset=hrs_post, - ) - - def test_fallback_singular(self): - # in the case of singular offsets, we don't necessarily know which utc - # offset the new Timestamp will wind up in (the tz for 1 month may be - # different from 1 second) so we don't specify an expected_utc_offset - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - self._test_all_offsets( - n=1, - tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), - expected_utc_offset=None, - ) - - def test_springforward_singular(self): - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - self._test_all_offsets( - n=1, - tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), - expected_utc_offset=None, - ) - - offset_classes = { - MonthBegin: ["11/2/2012", "12/1/2012"], - MonthEnd: ["11/2/2012", "11/30/2012"], - BMonthBegin: ["11/2/2012", "12/3/2012"], - BMonthEnd: ["11/2/2012", "11/30/2012"], - CBMonthBegin: ["11/2/2012", "12/3/2012"], - CBMonthEnd: ["11/2/2012", "11/30/2012"], - SemiMonthBegin: ["11/2/2012", "11/15/2012"], - SemiMonthEnd: ["11/2/2012", "11/15/2012"], - Week: ["11/2/2012", "11/9/2012"], - YearBegin: ["11/2/2012", "1/1/2013"], - YearEnd: ["11/2/2012", "12/31/2012"], - BYearBegin: ["11/2/2012", "1/1/2013"], - BYearEnd: ["11/2/2012", "12/31/2012"], - QuarterBegin: ["11/2/2012", "12/1/2012"], - QuarterEnd: ["11/2/2012", "12/31/2012"], - BQuarterBegin: ["11/2/2012", "12/3/2012"], - BQuarterEnd: ["11/2/2012", "12/31/2012"], - Day: ["11/4/2012", "11/4/2012 23:00"], - }.items() - - @pytest.mark.parametrize("tup", offset_classes) - def test_all_offset_classes(self, tup): - offset, test_values = tup - - first = Timestamp(test_values[0], tz="US/Eastern") + offset() - second = Timestamp(test_values[1], tz="US/Eastern") - assert first == second +# class TestDST: +# """ +# test DateOffset additions over Daylight Savings Time +# """ +# +# # one microsecond before the DST transition +# ts_pre_fallback = "2013-11-03 01:59:59.999999" +# ts_pre_springfwd = "2013-03-10 01:59:59.999999" +# +# # test both basic names and dateutil timezones +# timezone_utc_offsets = { +# "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), +# "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), +# } +# valid_date_offsets_singular = [ +# "weekday", +# "day", +# "hour", +# "minute", +# "second", +# "microsecond", +# ] +# valid_date_offsets_plural = [ +# "weeks", +# "days", +# "hours", +# "minutes", +# "seconds", +# "milliseconds", +# "microseconds", +# ] +# +# def _test_all_offsets(self, n, **kwds): +# valid_offsets = ( +# self.valid_date_offsets_plural +# if n > 1 +# else self.valid_date_offsets_singular +# ) +# +# for name in valid_offsets: +# self._test_offset(offset_name=name, offset_n=n, **kwds) +# +# def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): +# offset = DateOffset(**{offset_name: offset_n}) +# +# t = tstart + offset +# if expected_utc_offset is not None: +# assert get_utc_offset_hours(t) == expected_utc_offset +# +# if offset_name == "weeks": +# # dates should match +# assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() +# # expect the same day of week, hour of day, minute, second, ... +# assert ( +# t.dayofweek == tstart.dayofweek +# and t.hour == tstart.hour +# and t.minute == tstart.minute +# and t.second == tstart.second +# ) +# elif offset_name == "days": +# # dates should match +# assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() +# # expect the same hour of day, minute, second, ... +# assert ( +# t.hour == tstart.hour +# and t.minute == tstart.minute +# and t.second == tstart.second +# ) +# elif offset_name in self.valid_date_offsets_singular: +# # expect the singular offset value to match between tstart and t +# datepart_offset = getattr( +# t, offset_name if offset_name != "weekday" else "dayofweek" +# ) +# assert datepart_offset == offset.kwds[offset_name] +# else: +# # the offset should be the same as if it was done in UTC +# assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") +# +# def _make_timestamp(self, string, hrs_offset, tz): +# if hrs_offset >= 0: +# offset_string = "{hrs:02d}00".format(hrs=hrs_offset) +# else: +# offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) +# return Timestamp(string + offset_string).tz_convert(tz) +# +# def test_springforward_plural(self): +# # test moving from standard to daylight savings +# for tz, utc_offsets in self.timezone_utc_offsets.items(): +# hrs_pre = utc_offsets["utc_offset_standard"] +# hrs_post = utc_offsets["utc_offset_daylight"] +# self._test_all_offsets( +# n=3, +# tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), +# expected_utc_offset=hrs_post, +# ) +# +# def test_fallback_singular(self): +# # in the case of singular offsets, we don't necessarily know which utc +# # offset the new Timestamp will wind up in (the tz for 1 month may be +# # different from 1 second) so we don't specify an expected_utc_offset +# for tz, utc_offsets in self.timezone_utc_offsets.items(): +# hrs_pre = utc_offsets["utc_offset_standard"] +# self._test_all_offsets( +# n=1, +# tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), +# expected_utc_offset=None, +# ) +# +# def test_springforward_singular(self): +# for tz, utc_offsets in self.timezone_utc_offsets.items(): +# hrs_pre = utc_offsets["utc_offset_standard"] +# self._test_all_offsets( +# n=1, +# tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), +# expected_utc_offset=None, +# ) +# +# offset_classes = { +# MonthBegin: ["11/2/2012", "12/1/2012"], +# MonthEnd: ["11/2/2012", "11/30/2012"], +# BMonthBegin: ["11/2/2012", "12/3/2012"], +# BMonthEnd: ["11/2/2012", "11/30/2012"], +# CBMonthBegin: ["11/2/2012", "12/3/2012"], +# CBMonthEnd: ["11/2/2012", "11/30/2012"], +# SemiMonthBegin: ["11/2/2012", "11/15/2012"], +# SemiMonthEnd: ["11/2/2012", "11/15/2012"], +# Week: ["11/2/2012", "11/9/2012"], +# YearBegin: ["11/2/2012", "1/1/2013"], +# YearEnd: ["11/2/2012", "12/31/2012"], +# BYearBegin: ["11/2/2012", "1/1/2013"], +# BYearEnd: ["11/2/2012", "12/31/2012"], +# QuarterBegin: ["11/2/2012", "12/1/2012"], +# QuarterEnd: ["11/2/2012", "12/31/2012"], +# BQuarterBegin: ["11/2/2012", "12/3/2012"], +# BQuarterEnd: ["11/2/2012", "12/31/2012"], +# Day: ["11/4/2012", "11/4/2012 23:00"], +# }.items() +# +# @pytest.mark.parametrize("tup", offset_classes) +# def test_all_offset_classes(self, tup): +# offset, test_values = tup +# +# first = Timestamp(test_values[0], tz="US/Eastern") + offset() +# second = Timestamp(test_values[1], tz="US/Eastern") +# assert first == second # --------------------------------------------------------------------- -def test_get_offset_day_error(): - # subclass of _BaseOffset must override _day_opt attribute, or we should - # get a NotImplementedError - - with pytest.raises(NotImplementedError): - DateOffset()._get_offset_day(datetime.now()) +# def test_get_offset_day_error(): +# # subclass of _BaseOffset must override _day_opt attribute, or we should +# # get a NotImplementedError +# +# with pytest.raises(NotImplementedError): +# DateOffset()._get_offset_day(datetime.now()) def test_valid_default_arguments(offset_types): @@ -3382,11 +3383,11 @@ def test_valid_month_attributes(kwd, month_classes): cls(**{kwd: 3}) -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -def test_valid_relativedelta_kwargs(kwd): - # Check that all the arguments specified in liboffsets.relativedelta_kwds - # are in fact valid relativedelta keyword args - DateOffset(**{kwd: 1}) +# @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +# def test_valid_relativedelta_kwargs(kwd): +# # Check that all the arguments specified in liboffsets.relativedelta_kwds +# # are in fact valid relativedelta keyword args +# DateOffset(**{kwd: 1}) @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) @@ -3398,15 +3399,15 @@ def test_valid_tick_attributes(kwd, tick_classes): cls(**{kwd: 3}) -def test_validate_n_error(): - with pytest.raises(TypeError): - DateOffset(n="Doh!") - - with pytest.raises(TypeError): - MonthBegin(n=timedelta(1)) - - with pytest.raises(TypeError): - BDay(n=np.array([1, 2], dtype=np.int64)) +# def test_validate_n_error(): +# with pytest.raises(TypeError): +# DateOffset(n="Doh!") +# +# with pytest.raises(TypeError): +# MonthBegin(n=timedelta(1)) +# +# with pytest.raises(TypeError): +# BDay(n=np.array([1, 2], dtype=np.int64)) def test_require_integers(offset_types): @@ -3423,60 +3424,60 @@ def test_tick_normalize_raises(tick_classes): cls(n=3, normalize=True) -def test_weeks_onoffset(): - # GH#18510 Week with weekday = None, normalize = False should always - # be onOffset - offset = Week(n=2, weekday=None) - ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - # negative n - offset = Week(n=2, weekday=None) - ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - -def test_weekofmonth_onoffset(): - # GH#18864 - # Make sure that nanoseconds don't trip up onOffset (and with it apply) - offset = WeekOfMonth(n=2, week=2, weekday=0) - ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - # negative n - offset = WeekOfMonth(n=-3, week=1, weekday=0) - ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - -def test_last_week_of_month_on_offset(): - # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth - offset = LastWeekOfMonth(n=4, weekday=6) - ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") - slow = (ts + offset) - offset == ts - fast = offset.onOffset(ts) - assert fast == slow - - # negative n - offset = LastWeekOfMonth(n=-4, weekday=5) - ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") - slow = (ts + offset) - offset == ts - fast = offset.onOffset(ts) - assert fast == slow - - -def test_week_add_invalid(): - # Week with weekday should raise TypeError and _not_ AttributeError - # when adding invalid offset - offset = Week(weekday=1) - other = Day() - with pytest.raises(TypeError, match="Cannot add"): - offset + other +# def test_weeks_onoffset(): +# # GH#18510 Week with weekday = None, normalize = False should always +# # be onOffset +# offset = Week(n=2, weekday=None) +# ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") +# fast = offset.onOffset(ts) +# slow = (ts + offset) - offset == ts +# assert fast == slow +# +# # negative n +# offset = Week(n=2, weekday=None) +# ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") +# fast = offset.onOffset(ts) +# slow = (ts + offset) - offset == ts +# assert fast == slow + + +# def test_weekofmonth_onoffset(): +# # GH#18864 +# # Make sure that nanoseconds don't trip up onOffset (and with it apply) +# offset = WeekOfMonth(n=2, week=2, weekday=0) +# ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") +# fast = offset.onOffset(ts) +# slow = (ts + offset) - offset == ts +# assert fast == slow +# +# # negative n +# offset = WeekOfMonth(n=-3, week=1, weekday=0) +# ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") +# fast = offset.onOffset(ts) +# slow = (ts + offset) - offset == ts +# assert fast == slow + + +# def test_last_week_of_month_on_offset(): +# # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth +# offset = LastWeekOfMonth(n=4, weekday=6) +# ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") +# slow = (ts + offset) - offset == ts +# fast = offset.onOffset(ts) +# assert fast == slow +# +# # negative n +# offset = LastWeekOfMonth(n=-4, weekday=5) +# ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") +# slow = (ts + offset) - offset == ts +# fast = offset.onOffset(ts) +# assert fast == slow + + +# def test_week_add_invalid(): +# # Week with weekday should raise TypeError and _not_ AttributeError +# # when adding invalid offset +# offset = Week(weekday=1) +# other = Day() +# with pytest.raises(TypeError, match="Cannot add"): +# offset + other diff --git a/pandas/tests/tseries/offsets/test_date_offsets.py b/pandas/tests/tseries/offsets/test_date_offsets.py index 9955c4b587308..8518e916a275b 100644 --- a/pandas/tests/tseries/offsets/test_date_offsets.py +++ b/pandas/tests/tseries/offsets/test_date_offsets.py @@ -94,25 +94,9 @@ class Base: ] def _get_offset(self, klass, value=1, normalize=False): + print(klass) # create instance from offset class - if klass is FY5253: - klass = klass( - n=value, - startingMonth=1, - weekday=1, - variation="last", - normalize=normalize, - ) - elif klass is FY5253Quarter: - klass = klass( - n=value, - startingMonth=1, - weekday=1, - qtr_with_extra_week=1, - variation="last", - normalize=normalize, - ) - elif klass is LastWeekOfMonth: + if klass is LastWeekOfMonth: klass = klass(n=value, weekday=5, normalize=normalize) elif klass is WeekOfMonth: klass = klass(n=value, week=1, weekday=5, normalize=normalize) @@ -132,12 +116,7 @@ def test_apply_out_of_range(self, tz_naive_fixture): # try to create an out-of-bounds result timestamp; if we can't create # the offset skip try: - if self._offset in (BusinessHour, CustomBusinessHour): - # Using 10000 in BusinessHour fails in tz check because of DST - # difference - offset = self._get_offset(self._offset, value=100000) - else: - offset = self._get_offset(self._offset, value=10000) + offset = self._get_offset(self._offset, value=10000) result = Timestamp("20080101") + offset assert isinstance(result, datetime) @@ -228,30 +207,16 @@ class TestCommon(Base): expecteds = { "Day": Timestamp("2011-01-02 09:00:00"), "DateOffset": Timestamp("2011-01-02 09:00:00"), - "BusinessDay": Timestamp("2011-01-03 09:00:00"), - "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), - "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), - "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), "MonthBegin": Timestamp("2011-02-01 09:00:00"), - "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), "MonthEnd": Timestamp("2011-01-31 09:00:00"), "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), - "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), "YearBegin": Timestamp("2012-01-01 09:00:00"), - "BYearBegin": Timestamp("2011-01-03 09:00:00"), "YearEnd": Timestamp("2011-12-31 09:00:00"), - "BYearEnd": Timestamp("2011-12-30 09:00:00"), "QuarterBegin": Timestamp("2011-03-01 09:00:00"), - "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), "QuarterEnd": Timestamp("2011-03-31 09:00:00"), - "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), - "BusinessHour": Timestamp("2011-01-03 10:00:00"), - "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), - "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), - "FY5253": Timestamp("2011-01-25 09:00:00"), "Week": Timestamp("2011-01-08 09:00:00"), "Easter": Timestamp("2011-04-24 09:00:00"), "Hour": Timestamp("2011-01-01 10:00:00"), @@ -430,9 +395,6 @@ def test_rollforward(self, offset_types): for n in no_changes: expecteds[n] = Timestamp("2011/01/01 09:00") - expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") - expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") - # but be changed when normalize=True norm_expected = expecteds.copy() for k in norm_expected: @@ -466,27 +428,13 @@ def test_rollforward(self, offset_types): def test_rollback(self, offset_types): expecteds = { - "BusinessDay": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), - "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), "MonthEnd": Timestamp("2010-12-31 09:00:00"), "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), - "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), - "BYearBegin": Timestamp("2010-01-01 09:00:00"), "YearEnd": Timestamp("2010-12-31 09:00:00"), - "BYearEnd": Timestamp("2010-12-31 09:00:00"), "QuarterBegin": Timestamp("2010-12-01 09:00:00"), - "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), "QuarterEnd": Timestamp("2010-12-31 09:00:00"), - "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), - "BusinessHour": Timestamp("2010-12-31 17:00:00"), - "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), - "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), - "FY5253": Timestamp("2010-01-26 09:00:00"), "Easter": Timestamp("2010-04-04 09:00:00"), } @@ -551,10 +499,6 @@ def test_onOffset(self, offset_types): offset_n = self._get_offset(offset_types, normalize=True) assert not offset_n.onOffset(dt) - if offset_types in (BusinessHour, CustomBusinessHour): - # In default BusinessHour (9:00-17:00), normalized time - # cannot be in business hour range - return date = datetime(dt.year, dt.month, dt.day) assert offset_n.onOffset(date) @@ -1720,21 +1664,13 @@ def test_springforward_singular(self): offset_classes = { MonthBegin: ["11/2/2012", "12/1/2012"], MonthEnd: ["11/2/2012", "11/30/2012"], - BMonthBegin: ["11/2/2012", "12/3/2012"], - BMonthEnd: ["11/2/2012", "11/30/2012"], - CBMonthBegin: ["11/2/2012", "12/3/2012"], - CBMonthEnd: ["11/2/2012", "11/30/2012"], SemiMonthBegin: ["11/2/2012", "11/15/2012"], SemiMonthEnd: ["11/2/2012", "11/15/2012"], Week: ["11/2/2012", "11/9/2012"], YearBegin: ["11/2/2012", "1/1/2013"], YearEnd: ["11/2/2012", "12/31/2012"], - BYearBegin: ["11/2/2012", "1/1/2013"], - BYearEnd: ["11/2/2012", "12/31/2012"], QuarterBegin: ["11/2/2012", "12/1/2012"], QuarterEnd: ["11/2/2012", "12/31/2012"], - BQuarterBegin: ["11/2/2012", "12/3/2012"], - BQuarterEnd: ["11/2/2012", "12/31/2012"], Day: ["11/4/2012", "11/4/2012 23:00"], }.items() @@ -1795,9 +1731,6 @@ def test_validate_n_error(): with pytest.raises(TypeError): MonthBegin(n=timedelta(1)) - with pytest.raises(TypeError): - BDay(n=np.array([1, 2], dtype=np.int64)) - def test_require_integers(offset_types): cls = offset_types From 464a6acc252f9769e420be0c3fff43cb56d9606a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Tue, 10 Dec 2019 15:47:29 +0100 Subject: [PATCH 04/12] Test_date_offsets moved to specific fixtures --- pandas/tests/tseries/offsets/conftest.py | 70 +- .../tseries/offsets/test_business_offsets.py | 6371 ++++++++--------- .../tseries/offsets/test_date_offsets.py | 98 +- 3 files changed, 3299 insertions(+), 3240 deletions(-) diff --git a/pandas/tests/tseries/offsets/conftest.py b/pandas/tests/tseries/offsets/conftest.py index 2e764123b5e84..b93a526e4c98e 100644 --- a/pandas/tests/tseries/offsets/conftest.py +++ b/pandas/tests/tseries/offsets/conftest.py @@ -2,8 +2,50 @@ import pandas.tseries.offsets as offsets +DATE_OFFSETS = { + "Day", + "MonthBegin", + "MonthEnd", + "SemiMonthBegin", + "SemiMonthEnd", + "YearBegin", + "YearEnd", + "QuarterBegin", + "QuarterEnd", + "LastWeekOfMonth", + "Week", + "WeekOfMonth", + "Easter", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", +} -@pytest.fixture(params=[getattr(offsets, o) for o in offsets.__all__]) +# BUSINESS_OFFSETS = { +# "BusinessDay", +# "BDay", +# "CustomBusinessDay", +# "CBMonthBegin", +# "CBMonthEnd", +# "BMonthBegin", +# "BMonthEnd", +# "BusinessHour", +# "CustomBusinessHour", +# "BYearBegin", +# "BYearEnd", +# "CDay", +# "BQuarterBegin", +# "BQuarterEnd", +# "FY5253Quarter", +# "FY5253", +# } + + +@pytest.fixture(params=[getattr(offsets, o) for o in DATE_OFFSETS]) def date_offset_types(request): """ Fixture for all the datetime offsets available for a time series. @@ -11,15 +53,37 @@ def date_offset_types(request): return request.param +# @pytest.fixture(params=[getattr(offsets, o) for o in BUSINESS_OFFSETS]) +# def business_offset_types(request): +# """ +# Fixture for all the datetime offsets available for a time series. +# """ +# return request.param + + @pytest.fixture( params=[ getattr(offsets, o) - for o in offsets.__all__ + for o in DATE_OFFSETS if issubclass(getattr(offsets, o), offsets.MonthOffset) and o != "MonthOffset" ] ) -def month_classes(request): +def date_month_classes(request): """ Fixture for month based datetime offsets available for a time series. """ return request.param + + +# @pytest.fixture( +# params=[ +# getattr(offsets, o) +# for o in BUSINESS_OFFSETS +# if issubclass(getattr(offsets, o), offsets.MonthOffset) and o != "MonthOffset" +# ] +# ) +# def business_month_classes(request): +# """ +# Fixture for month based datetime offsets available for a time series. +# """ +# return request.param \ No newline at end of file diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index 1fc3fb5089596..4da423f8edfd8 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -22,7 +22,6 @@ from pandas.compat.numpy import np_datetime64_compat from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range -from pandas.core.series import Series import pandas.util.testing as tm from pandas.io.pickle import read_pickle @@ -78,2665 +77,2665 @@ def test_to_M8(): _ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]] -# class Base: -# _offset = None # type: Type[DateOffset] -# d = Timestamp(datetime(2008, 1, 2)) -# -# timezones = [ -# None, -# "UTC", -# "Asia/Tokyo", -# "US/Eastern", -# "dateutil/Asia/Tokyo", -# "dateutil/US/Pacific", -# ] -# -# def _get_offset(self, klass, value=1, normalize=False): -# # create instance from offset class -# if klass is FY5253: -# klass = klass( -# n=value, -# startingMonth=1, -# weekday=1, -# variation="last", -# normalize=normalize, -# ) -# elif klass is FY5253Quarter: -# klass = klass( -# n=value, -# startingMonth=1, -# weekday=1, -# qtr_with_extra_week=1, -# variation="last", -# normalize=normalize, -# ) -# elif klass is LastWeekOfMonth: -# klass = klass(n=value, weekday=5, normalize=normalize) -# elif klass is WeekOfMonth: -# klass = klass(n=value, week=1, weekday=5, normalize=normalize) -# elif klass is Week: -# klass = klass(n=value, weekday=5, normalize=normalize) -# elif klass is DateOffset: -# klass = klass(days=value, normalize=normalize) -# else: -# klass = klass(value, normalize=normalize) -# return klass -# -# def test_apply_out_of_range(self, tz_naive_fixture): -# tz = tz_naive_fixture -# if self._offset is None: -# return -# -# # try to create an out-of-bounds result timestamp; if we can't create -# # the offset skip -# try: -# if self._offset in (BusinessHour, CustomBusinessHour): -# # Using 10000 in BusinessHour fails in tz check because of DST -# # difference -# offset = self._get_offset(self._offset, value=100000) -# else: -# offset = self._get_offset(self._offset, value=10000) -# -# result = Timestamp("20080101") + offset -# assert isinstance(result, datetime) -# assert result.tzinfo is None -# -# # Check tz is preserved -# t = Timestamp("20080101", tz=tz) -# result = t + offset -# assert isinstance(result, datetime) -# assert t.tzinfo == result.tzinfo -# -# except OutOfBoundsDatetime: -# pass -# except (ValueError, KeyError): -# # we are creating an invalid offset -# # so ignore -# pass -# -# def test_offsets_compare_equal(self): -# # root cause of GH#456: __ne__ was not implemented -# if self._offset is None: -# return -# offset1 = self._offset() -# offset2 = self._offset() -# assert not offset1 != offset2 -# assert offset1 == offset2 -# -# def test_rsub(self): -# if self._offset is None or not hasattr(self, "offset2"): -# # i.e. skip for TestCommon and YQM subclasses that do not have -# # offset2 attr -# return -# assert self.d - self.offset2 == (-self.offset2).apply(self.d) -# -# def test_radd(self): -# if self._offset is None or not hasattr(self, "offset2"): -# # i.e. skip for TestCommon and YQM subclasses that do not have -# # offset2 attr -# return -# assert self.d + self.offset2 == self.offset2 + self.d -# -# def test_sub(self): -# if self._offset is None or not hasattr(self, "offset2"): -# # i.e. skip for TestCommon and YQM subclasses that do not have -# # offset2 attr -# return -# off = self.offset2 -# msg = "Cannot subtract datetime from offset" -# with pytest.raises(TypeError, match=msg): -# off - self.d -# -# assert 2 * off - off == off -# assert self.d - self.offset2 == self.d + self._offset(-2) -# assert self.d - self.offset2 == self.d - (2 * off - off) -# -# def testMult1(self): -# if self._offset is None or not hasattr(self, "offset1"): -# # i.e. skip for TestCommon and YQM subclasses that do not have -# # offset1 attr -# return -# assert self.d + 10 * self.offset1 == self.d + self._offset(10) -# assert self.d + 5 * self.offset1 == self.d + self._offset(5) -# -# def testMult2(self): -# if self._offset is None: -# return -# assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) -# assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) -# -# def test_compare_str(self): -# # GH#23524 -# # comparing to strings that cannot be cast to DateOffsets should -# # not raise for __eq__ or __ne__ -# if self._offset is None: -# return -# off = self._get_offset(self._offset) -# -# assert not off == "infer" -# assert off != "foo" -# # Note: inequalities are only implemented for Tick subclasses; -# # tests for this are in test_ticks - - -# class TestCommon(Base): -# # exected value created by Base._get_offset -# # are applied to 2011/01/01 09:00 (Saturday) -# # used for .apply and .rollforward -# expecteds = { -# "Day": Timestamp("2011-01-02 09:00:00"), -# "DateOffset": Timestamp("2011-01-02 09:00:00"), -# "BusinessDay": Timestamp("2011-01-03 09:00:00"), -# "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), -# "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), -# "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), -# "MonthBegin": Timestamp("2011-02-01 09:00:00"), -# "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), -# "MonthEnd": Timestamp("2011-01-31 09:00:00"), -# "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), -# "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), -# "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), -# "YearBegin": Timestamp("2012-01-01 09:00:00"), -# "BYearBegin": Timestamp("2011-01-03 09:00:00"), -# "YearEnd": Timestamp("2011-12-31 09:00:00"), -# "BYearEnd": Timestamp("2011-12-30 09:00:00"), -# "QuarterBegin": Timestamp("2011-03-01 09:00:00"), -# "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), -# "QuarterEnd": Timestamp("2011-03-31 09:00:00"), -# "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), -# "BusinessHour": Timestamp("2011-01-03 10:00:00"), -# "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), -# "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), -# "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), -# "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), -# "FY5253": Timestamp("2011-01-25 09:00:00"), -# "Week": Timestamp("2011-01-08 09:00:00"), -# "Easter": Timestamp("2011-04-24 09:00:00"), -# "Hour": Timestamp("2011-01-01 10:00:00"), -# "Minute": Timestamp("2011-01-01 09:01:00"), -# "Second": Timestamp("2011-01-01 09:00:01"), -# "Milli": Timestamp("2011-01-01 09:00:00.001000"), -# "Micro": Timestamp("2011-01-01 09:00:00.000001"), -# "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), -# } -# -# def test_immutable(self, offset_types): -# # GH#21341 check that __setattr__ raises -# offset = self._get_offset(offset_types) -# with pytest.raises(AttributeError): -# offset.normalize = True -# with pytest.raises(AttributeError): -# offset.n = 91 -# -# def test_return_type(self, offset_types): -# offset = self._get_offset(offset_types) -# -# # make sure that we are returning a Timestamp -# result = Timestamp("20080101") + offset -# assert isinstance(result, Timestamp) -# -# # make sure that we are returning NaT -# assert NaT + offset is NaT -# assert offset + NaT is NaT -# -# assert NaT - offset is NaT -# assert (-offset).apply(NaT) is NaT -# -# def test_offset_n(self, offset_types): -# offset = self._get_offset(offset_types) -# assert offset.n == 1 -# -# neg_offset = offset * -1 -# assert neg_offset.n == -1 -# -# mul_offset = offset * 3 -# assert mul_offset.n == 3 -# -# def test_offset_timedelta64_arg(self, offset_types): -# # check that offset._validate_n raises TypeError on a timedelt64 -# # object -# off = self._get_offset(offset_types) -# -# td64 = np.timedelta64(4567, "s") -# with pytest.raises(TypeError, match="argument must be an integer"): -# type(off)(n=td64, **off.kwds) -# -# def test_offset_mul_ndarray(self, offset_types): -# off = self._get_offset(offset_types) -# -# expected = np.array([[off, off * 2], [off * 3, off * 4]]) -# -# result = np.array([[1, 2], [3, 4]]) * off -# tm.assert_numpy_array_equal(result, expected) -# -# result = off * np.array([[1, 2], [3, 4]]) -# tm.assert_numpy_array_equal(result, expected) -# -# def test_offset_freqstr(self, offset_types): -# offset = self._get_offset(offset_types) -# -# freqstr = offset.freqstr -# if freqstr not in ("", "", "LWOM-SAT"): -# code = get_offset(freqstr) -# assert offset.rule_code == code -# -# def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): -# -# if normalize and issubclass(offset, Tick): -# # normalize=True disallowed for Tick subclasses GH#21427 -# return -# -# offset_s = self._get_offset(offset, normalize=normalize) -# func = getattr(offset_s, funcname) -# -# result = func(dt) -# assert isinstance(result, Timestamp) -# assert result == expected -# -# result = func(Timestamp(dt)) -# assert isinstance(result, Timestamp) -# assert result == expected -# -# # see gh-14101 -# exp_warning = None -# ts = Timestamp(dt) + Nano(5) -# -# if ( -# offset_s.__class__.__name__ == "DateOffset" -# and (funcname == "apply" or normalize) -# and ts.nanosecond > 0 -# ): -# exp_warning = UserWarning -# -# # test nanosecond is preserved -# with tm.assert_produces_warning(exp_warning, check_stacklevel=False): -# result = func(ts) -# assert isinstance(result, Timestamp) -# if normalize is False: -# assert result == expected + Nano(5) -# else: -# assert result == expected -# -# if isinstance(dt, np.datetime64): -# # test tz when input is datetime or Timestamp -# return -# -# for tz in self.timezones: -# expected_localize = expected.tz_localize(tz) -# tz_obj = timezones.maybe_get_tz(tz) -# dt_tz = conversion.localize_pydatetime(dt, tz_obj) -# -# result = func(dt_tz) -# assert isinstance(result, Timestamp) -# assert result == expected_localize -# -# result = func(Timestamp(dt, tz=tz)) -# assert isinstance(result, Timestamp) -# assert result == expected_localize -# -# # see gh-14101 -# exp_warning = None -# ts = Timestamp(dt, tz=tz) + Nano(5) -# -# if ( -# offset_s.__class__.__name__ == "DateOffset" -# and (funcname == "apply" or normalize) -# and ts.nanosecond > 0 -# ): -# exp_warning = UserWarning -# -# # test nanosecond is preserved -# with tm.assert_produces_warning(exp_warning, check_stacklevel=False): -# result = func(ts) -# assert isinstance(result, Timestamp) -# if normalize is False: -# assert result == expected_localize + Nano(5) -# else: -# assert result == expected_localize -# -# def test_apply(self, offset_types): -# sdt = datetime(2011, 1, 1, 9, 0) -# ndt = np_datetime64_compat("2011-01-01 09:00Z") -# -# for dt in [sdt, ndt]: -# expected = self.expecteds[offset_types.__name__] -# self._check_offsetfunc_works(offset_types, "apply", dt, expected) -# -# expected = Timestamp(expected.date()) -# self._check_offsetfunc_works( -# offset_types, "apply", dt, expected, normalize=True -# ) -# -# def test_rollforward(self, offset_types): -# expecteds = self.expecteds.copy() -# -# # result will not be changed if the target is on the offset -# no_changes = [ -# "Day", -# "MonthBegin", -# "SemiMonthBegin", -# "YearBegin", -# "Week", -# "Hour", -# "Minute", -# "Second", -# "Milli", -# "Micro", -# "Nano", -# "DateOffset", -# ] -# for n in no_changes: -# expecteds[n] = Timestamp("2011/01/01 09:00") -# -# expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") -# expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") -# -# # but be changed when normalize=True -# norm_expected = expecteds.copy() -# for k in norm_expected: -# norm_expected[k] = Timestamp(norm_expected[k].date()) -# -# normalized = { -# "Day": Timestamp("2011-01-02 00:00:00"), -# "DateOffset": Timestamp("2011-01-02 00:00:00"), -# "MonthBegin": Timestamp("2011-02-01 00:00:00"), -# "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), -# "YearBegin": Timestamp("2012-01-01 00:00:00"), -# "Week": Timestamp("2011-01-08 00:00:00"), -# "Hour": Timestamp("2011-01-01 00:00:00"), -# "Minute": Timestamp("2011-01-01 00:00:00"), -# "Second": Timestamp("2011-01-01 00:00:00"), -# "Milli": Timestamp("2011-01-01 00:00:00"), -# "Micro": Timestamp("2011-01-01 00:00:00"), -# } -# norm_expected.update(normalized) -# -# sdt = datetime(2011, 1, 1, 9, 0) -# ndt = np_datetime64_compat("2011-01-01 09:00Z") -# -# for dt in [sdt, ndt]: -# expected = expecteds[offset_types.__name__] -# self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) -# expected = norm_expected[offset_types.__name__] -# self._check_offsetfunc_works( -# offset_types, "rollforward", dt, expected, normalize=True -# ) -# -# def test_rollback(self, offset_types): -# expecteds = { -# "BusinessDay": Timestamp("2010-12-31 09:00:00"), -# "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), -# "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), -# "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), -# "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), -# "MonthEnd": Timestamp("2010-12-31 09:00:00"), -# "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), -# "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), -# "BYearBegin": Timestamp("2010-01-01 09:00:00"), -# "YearEnd": Timestamp("2010-12-31 09:00:00"), -# "BYearEnd": Timestamp("2010-12-31 09:00:00"), -# "QuarterBegin": Timestamp("2010-12-01 09:00:00"), -# "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), -# "QuarterEnd": Timestamp("2010-12-31 09:00:00"), -# "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), -# "BusinessHour": Timestamp("2010-12-31 17:00:00"), -# "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), -# "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), -# "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), -# "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), -# "FY5253": Timestamp("2010-01-26 09:00:00"), -# "Easter": Timestamp("2010-04-04 09:00:00"), -# } -# -# # result will not be changed if the target is on the offset -# for n in [ -# "Day", -# "MonthBegin", -# "SemiMonthBegin", -# "YearBegin", -# "Week", -# "Hour", -# "Minute", -# "Second", -# "Milli", -# "Micro", -# "Nano", -# "DateOffset", -# ]: -# expecteds[n] = Timestamp("2011/01/01 09:00") -# -# # but be changed when normalize=True -# norm_expected = expecteds.copy() -# for k in norm_expected: -# norm_expected[k] = Timestamp(norm_expected[k].date()) -# -# normalized = { -# "Day": Timestamp("2010-12-31 00:00:00"), -# "DateOffset": Timestamp("2010-12-31 00:00:00"), -# "MonthBegin": Timestamp("2010-12-01 00:00:00"), -# "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), -# "YearBegin": Timestamp("2010-01-01 00:00:00"), -# "Week": Timestamp("2010-12-25 00:00:00"), -# "Hour": Timestamp("2011-01-01 00:00:00"), -# "Minute": Timestamp("2011-01-01 00:00:00"), -# "Second": Timestamp("2011-01-01 00:00:00"), -# "Milli": Timestamp("2011-01-01 00:00:00"), -# "Micro": Timestamp("2011-01-01 00:00:00"), -# } -# norm_expected.update(normalized) -# -# sdt = datetime(2011, 1, 1, 9, 0) -# ndt = np_datetime64_compat("2011-01-01 09:00Z") -# -# for dt in [sdt, ndt]: -# expected = expecteds[offset_types.__name__] -# self._check_offsetfunc_works(offset_types, "rollback", dt, expected) -# -# expected = norm_expected[offset_types.__name__] -# self._check_offsetfunc_works( -# offset_types, "rollback", dt, expected, normalize=True -# ) -# -# def test_onOffset(self, offset_types): -# dt = self.expecteds[offset_types.__name__] -# offset_s = self._get_offset(offset_types) -# assert offset_s.onOffset(dt) -# -# # when normalize=True, onOffset checks time is 00:00:00 -# if issubclass(offset_types, Tick): -# # normalize=True disallowed for Tick subclasses GH#21427 -# return -# offset_n = self._get_offset(offset_types, normalize=True) -# assert not offset_n.onOffset(dt) -# -# if offset_types in (BusinessHour, CustomBusinessHour): -# # In default BusinessHour (9:00-17:00), normalized time -# # cannot be in business hour range -# return -# date = datetime(dt.year, dt.month, dt.day) -# assert offset_n.onOffset(date) -# -# def test_add(self, offset_types, tz_naive_fixture): -# tz = tz_naive_fixture -# dt = datetime(2011, 1, 1, 9, 0) -# -# offset_s = self._get_offset(offset_types) -# expected = self.expecteds[offset_types.__name__] -# -# result_dt = dt + offset_s -# result_ts = Timestamp(dt) + offset_s -# for result in [result_dt, result_ts]: -# assert isinstance(result, Timestamp) -# assert result == expected -# -# expected_localize = expected.tz_localize(tz) -# result = Timestamp(dt, tz=tz) + offset_s -# assert isinstance(result, Timestamp) -# assert result == expected_localize -# -# # normalize=True, disallowed for Tick subclasses GH#21427 -# if issubclass(offset_types, Tick): -# return -# offset_s = self._get_offset(offset_types, normalize=True) -# expected = Timestamp(expected.date()) -# -# result_dt = dt + offset_s -# result_ts = Timestamp(dt) + offset_s -# for result in [result_dt, result_ts]: -# assert isinstance(result, Timestamp) -# assert result == expected -# -# expected_localize = expected.tz_localize(tz) -# result = Timestamp(dt, tz=tz) + offset_s -# assert isinstance(result, Timestamp) -# assert result == expected_localize -# -# def test_pickle_v0_15_2(self, datapath): -# offsets = { -# "DateOffset": DateOffset(years=1), -# "MonthBegin": MonthBegin(1), -# "Day": Day(1), -# "YearBegin": YearBegin(1), -# "Week": Week(1), -# } -# -# pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") -# # This code was executed once on v0.15.2 to generate the pickle: -# # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) -# # -# tm.assert_dict_equal(offsets, read_pickle(pickle_path)) - - -# class TestBusinessDay(Base): -# _offset = BDay -# -# def setup_method(self, method): -# self.d = datetime(2008, 1, 1) -# -# self.offset = BDay() -# self.offset1 = self.offset -# self.offset2 = BDay(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 * BusinessDays>" -# -# if compat.PY37: -# expected = "" -# else: -# 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_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): -# assert self.offset2(self.d) == datetime(2008, 1, 3) -# -# def testRollback1(self): -# assert BDay(10).rollback(self.d) == self.d -# -# def testRollback2(self): -# assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) -# -# def testRollforward1(self): -# assert BDay(10).rollforward(self.d) == self.d -# -# def testRollforward2(self): -# assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) -# -# def test_roll_date_object(self): -# offset = BDay() -# -# 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) -# -# def test_onOffset(self): -# tests = [ -# (BDay(), datetime(2008, 1, 1), True), -# (BDay(), datetime(2008, 1, 5), False), -# ] -# -# for offset, d, expected in tests: -# assert_onOffset(offset, d, expected) -# -# apply_cases = [] # type: _ApplyCases -# apply_cases.append( -# ( -# BDay(), -# { -# 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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# 2 * BDay(), -# { -# 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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -BDay(), -# { -# 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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -2 * BDay(), -# { -# 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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BDay(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 + BDay(10) -# assert result == datetime(2012, 11, 6) -# -# result = dt + BDay(100) - BDay(100) -# assert result == dt -# -# off = BDay() * 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 -# -# off = BDay() * 10 -# rs = datetime(2014, 1, 5) + off # see #5890 -# xp = datetime(2014, 1, 17) -# assert rs == xp -# -# 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 TestBusinessHour(Base): -# _offset = BusinessHour -# -# def setup_method(self, method): -# self.d = datetime(2014, 7, 1, 10, 00) -# -# self.offset1 = BusinessHour() -# self.offset2 = BusinessHour(n=3) -# -# self.offset3 = BusinessHour(n=-1) -# self.offset4 = BusinessHour(n=-4) -# -# from datetime import time as dt_time -# -# self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) -# self.offset6 = BusinessHour(start="20:00", end="05:00") -# self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) -# self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) -# self.offset9 = BusinessHour( -# n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] -# ) -# self.offset10 = BusinessHour( -# n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] -# ) -# -# @pytest.mark.parametrize( -# "start,end,match", -# [ -# ( -# dt_time(11, 0, 5), -# "17:00", -# "time data must be specified only with hour and minute", -# ), -# ("AAA", "17:00", "time data must match '%H:%M' format"), -# ("14:00:05", "17:00", "time data must match '%H:%M' format"), -# ([], "17:00", "Must include at least 1 start time"), -# ("09:00", [], "Must include at least 1 end time"), -# ( -# ["09:00", "11:00"], -# "17:00", -# "number of starting time and ending time must be the same", -# ), -# ( -# ["09:00", "11:00"], -# ["10:00"], -# "number of starting time and ending time must be the same", -# ), -# ( -# ["09:00", "11:00"], -# ["12:00", "20:00"], -# r"invalid starting and ending time\(s\): opening hours should not " -# "touch or overlap with one another", -# ), -# ( -# ["12:00", "20:00"], -# ["09:00", "11:00"], -# r"invalid starting and ending time\(s\): opening hours should not " -# "touch or overlap with one another", -# ), -# ], -# ) -# def test_constructor_errors(self, start, end, match): -# with pytest.raises(ValueError, match=match): -# BusinessHour(start=start, end=end) -# -# 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.offset1) == "" -# assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" -# assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" -# assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" -# -# assert repr(self.offset5) == "" -# assert repr(self.offset6) == "" -# assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" -# assert repr(self.offset8) == "" -# assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" -# assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" -# -# def test_with_offset(self): -# expected = Timestamp("2014-07-01 13:00") -# -# assert self.d + BusinessHour() * 3 == expected -# assert self.d + BusinessHour(n=3) == expected -# -# @pytest.mark.parametrize( -# "offset_name", -# ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], -# ) -# def test_eq_attribute(self, offset_name): -# offset = getattr(self, offset_name) -# assert offset == offset -# -# @pytest.mark.parametrize( -# "offset1,offset2", -# [ -# (BusinessHour(start="09:00"), BusinessHour()), -# ( -# BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), -# BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), -# ), -# ], -# ) -# def test_eq(self, offset1, offset2): -# assert offset1 == offset2 -# -# @pytest.mark.parametrize( -# "offset1,offset2", -# [ -# (BusinessHour(), BusinessHour(-1)), -# (BusinessHour(start="09:00"), BusinessHour(start="09:01")), -# ( -# BusinessHour(start="09:00", end="17:00"), -# BusinessHour(start="17:00", end="09:01"), -# ), -# ( -# BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), -# BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), -# ), -# ], -# ) -# def test_neq(self, offset1, offset2): -# assert offset1 != offset2 -# -# @pytest.mark.parametrize( -# "offset_name", -# ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], -# ) -# def test_hash(self, offset_name): -# offset = getattr(self, offset_name) -# assert offset == offset -# -# def test_call(self): -# assert self.offset1(self.d) == datetime(2014, 7, 1, 11) -# assert self.offset2(self.d) == datetime(2014, 7, 1, 13) -# assert self.offset3(self.d) == datetime(2014, 6, 30, 17) -# assert self.offset4(self.d) == datetime(2014, 6, 30, 14) -# assert self.offset8(self.d) == datetime(2014, 7, 1, 11) -# assert self.offset9(self.d) == datetime(2014, 7, 1, 22) -# assert self.offset10(self.d) == datetime(2014, 7, 1, 1) -# -# def test_sub(self): -# # we have to override test_sub here because self.offset2 is not -# # defined as self._offset(2) -# off = self.offset2 -# msg = "Cannot subtract datetime from offset" -# with pytest.raises(TypeError, match=msg): -# off - self.d -# assert 2 * off - off == off -# -# assert self.d - self.offset2 == self.d + self._offset(-3) -# -# def testRollback1(self): -# assert self.offset1.rollback(self.d) == self.d -# assert self.offset2.rollback(self.d) == self.d -# assert self.offset3.rollback(self.d) == self.d -# assert self.offset4.rollback(self.d) == self.d -# assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) -# assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) -# assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) -# assert self.offset8.rollback(self.d) == self.d -# assert self.offset9.rollback(self.d) == self.d -# assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) -# -# d = datetime(2014, 7, 1, 0) -# assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) -# assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) -# assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) -# assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) -# assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) -# assert self.offset6.rollback(d) == d -# assert self.offset7.rollback(d) == d -# assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) -# assert self.offset9.rollback(d) == d -# assert self.offset10.rollback(d) == d -# -# assert self._offset(5).rollback(self.d) == self.d -# -# def testRollback2(self): -# assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( -# 2014, 7, 4, 17, 0 -# ) -# -# def testRollforward1(self): -# assert self.offset1.rollforward(self.d) == self.d -# assert self.offset2.rollforward(self.d) == self.d -# assert self.offset3.rollforward(self.d) == self.d -# assert self.offset4.rollforward(self.d) == self.d -# assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) -# assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) -# assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) -# assert self.offset8.rollforward(self.d) == self.d -# assert self.offset9.rollforward(self.d) == self.d -# assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) -# -# d = datetime(2014, 7, 1, 0) -# assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) -# assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) -# assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) -# assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) -# assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) -# assert self.offset6.rollforward(d) == d -# assert self.offset7.rollforward(d) == d -# assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) -# assert self.offset9.rollforward(d) == d -# assert self.offset10.rollforward(d) == d -# -# assert self._offset(5).rollforward(self.d) == self.d -# -# def testRollforward2(self): -# assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( -# 2014, 7, 7, 9 -# ) -# -# def test_roll_date_object(self): -# offset = BusinessHour() -# -# dt = datetime(2014, 7, 6, 15, 0) -# -# result = offset.rollback(dt) -# assert result == datetime(2014, 7, 4, 17) -# -# result = offset.rollforward(dt) -# assert result == datetime(2014, 7, 7, 9) -# -# normalize_cases = [] -# normalize_cases.append( -# ( -# BusinessHour(normalize=True), -# { -# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 2), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 2), -# datetime(2014, 7, 1, 23): datetime(2014, 7, 2), -# datetime(2014, 7, 1, 0): datetime(2014, 7, 1), -# datetime(2014, 7, 4, 15): datetime(2014, 7, 4), -# datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), -# datetime(2014, 7, 5, 23): datetime(2014, 7, 7), -# datetime(2014, 7, 6, 10): datetime(2014, 7, 7), -# }, -# ) -# ) -# -# normalize_cases.append( -# ( -# BusinessHour(-1, normalize=True), -# { -# datetime(2014, 7, 1, 8): datetime(2014, 6, 30), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 10): datetime(2014, 6, 30), -# datetime(2014, 7, 1, 0): datetime(2014, 6, 30), -# datetime(2014, 7, 7, 10): datetime(2014, 7, 4), -# datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), -# datetime(2014, 7, 5, 23): datetime(2014, 7, 4), -# datetime(2014, 7, 6, 10): datetime(2014, 7, 4), -# }, -# ) -# ) -# -# normalize_cases.append( -# ( -# BusinessHour(1, normalize=True, start="17:00", end="04:00"), -# { -# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 23): datetime(2014, 7, 2), -# datetime(2014, 7, 2, 2): datetime(2014, 7, 2), -# datetime(2014, 7, 2, 3): datetime(2014, 7, 2), -# datetime(2014, 7, 4, 23): datetime(2014, 7, 5), -# datetime(2014, 7, 5, 2): datetime(2014, 7, 5), -# datetime(2014, 7, 7, 2): datetime(2014, 7, 7), -# datetime(2014, 7, 7, 17): datetime(2014, 7, 7), -# }, -# ) -# ) -# -# @pytest.mark.parametrize("case", normalize_cases) -# def test_normalize(self, case): -# offset, cases = case -# for dt, expected in cases.items(): -# assert offset.apply(dt) == expected -# -# on_offset_cases = [] -# on_offset_cases.append( -# ( -# BusinessHour(), -# { -# datetime(2014, 7, 1, 9): True, -# datetime(2014, 7, 1, 8, 59): False, -# datetime(2014, 7, 1, 8): False, -# datetime(2014, 7, 1, 17): True, -# datetime(2014, 7, 1, 17, 1): False, -# datetime(2014, 7, 1, 18): False, -# datetime(2014, 7, 5, 9): False, -# datetime(2014, 7, 6, 12): False, -# }, -# ) -# ) -# -# on_offset_cases.append( -# ( -# BusinessHour(start="10:00", end="15:00"), -# { -# datetime(2014, 7, 1, 9): False, -# datetime(2014, 7, 1, 10): True, -# datetime(2014, 7, 1, 15): True, -# datetime(2014, 7, 1, 15, 1): False, -# datetime(2014, 7, 5, 12): False, -# datetime(2014, 7, 6, 12): False, -# }, -# ) -# ) -# -# on_offset_cases.append( -# ( -# BusinessHour(start="19:00", end="05:00"), -# { -# datetime(2014, 7, 1, 9, 0): False, -# datetime(2014, 7, 1, 10, 0): False, -# datetime(2014, 7, 1, 15): False, -# datetime(2014, 7, 1, 15, 1): False, -# datetime(2014, 7, 5, 12, 0): False, -# datetime(2014, 7, 6, 12, 0): False, -# datetime(2014, 7, 1, 19, 0): True, -# datetime(2014, 7, 2, 0, 0): True, -# datetime(2014, 7, 4, 23): True, -# datetime(2014, 7, 5, 1): True, -# datetime(2014, 7, 5, 5, 0): True, -# datetime(2014, 7, 6, 23, 0): False, -# datetime(2014, 7, 7, 3, 0): False, -# }, -# ) -# ) -# -# on_offset_cases.append( -# ( -# BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), -# { -# datetime(2014, 7, 1, 9): True, -# datetime(2014, 7, 1, 8, 59): False, -# datetime(2014, 7, 1, 8): False, -# datetime(2014, 7, 1, 17): True, -# datetime(2014, 7, 1, 17, 1): False, -# datetime(2014, 7, 1, 18): False, -# datetime(2014, 7, 5, 9): False, -# datetime(2014, 7, 6, 12): False, -# datetime(2014, 7, 1, 12, 30): False, -# }, -# ) -# ) -# -# on_offset_cases.append( -# ( -# BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), -# { -# datetime(2014, 7, 1, 9, 0): False, -# datetime(2014, 7, 1, 10, 0): False, -# datetime(2014, 7, 1, 15): False, -# datetime(2014, 7, 1, 15, 1): False, -# datetime(2014, 7, 5, 12, 0): False, -# datetime(2014, 7, 6, 12, 0): False, -# datetime(2014, 7, 1, 19, 0): True, -# datetime(2014, 7, 2, 0, 0): True, -# datetime(2014, 7, 4, 23): True, -# datetime(2014, 7, 5, 1): True, -# datetime(2014, 7, 5, 5, 0): True, -# datetime(2014, 7, 6, 23, 0): False, -# datetime(2014, 7, 7, 3, 0): False, -# datetime(2014, 7, 4, 22): False, -# }, -# ) -# ) -# -# @pytest.mark.parametrize("case", on_offset_cases) -# def test_onOffset(self, case): -# offset, cases = case -# for dt, expected in cases.items(): -# assert offset.onOffset(dt) == expected -# -# opening_time_cases = [] -# # opening time should be affected by sign of n, not by n's value and -# # end -# opening_time_cases.append( -# ( -# [ -# BusinessHour(), -# BusinessHour(n=2), -# BusinessHour(n=4), -# BusinessHour(end="10:00"), -# BusinessHour(n=2, end="4:00"), -# BusinessHour(n=4, end="15:00"), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 9), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 9), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 9), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 9), -# ), -# # if timestamp is on opening time, next opening time is -# # as it is -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 2, 9), -# ), -# datetime(2014, 7, 2, 10): ( -# datetime(2014, 7, 3, 9), -# datetime(2014, 7, 2, 9), -# ), -# # 2014-07-05 is saturday -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 4, 9), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 4, 9), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 4, 9), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 4, 9), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 4, 9), -# ), -# datetime(2014, 7, 7, 9, 1): ( -# datetime(2014, 7, 8, 9), -# datetime(2014, 7, 7, 9), -# ), -# }, -# ) -# ) -# -# opening_time_cases.append( -# ( -# [ -# BusinessHour(start="11:15"), -# BusinessHour(n=2, start="11:15"), -# BusinessHour(n=3, start="11:15"), -# BusinessHour(start="11:15", end="10:00"), -# BusinessHour(n=2, start="11:15", end="4:00"), -# BusinessHour(n=3, start="11:15", end="15:00"), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 7, 1, 11, 15), -# datetime(2014, 6, 30, 11, 15), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 11, 15), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 11, 15), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 11, 15), -# ), -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 11, 15), -# ), -# datetime(2014, 7, 2, 10): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 11, 15), -# ), -# datetime(2014, 7, 2, 11, 15): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 2, 11, 15), -# ), -# datetime(2014, 7, 2, 11, 15, 1): ( -# datetime(2014, 7, 3, 11, 15), -# datetime(2014, 7, 2, 11, 15), -# ), -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 11, 15), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 4, 11, 15), -# datetime(2014, 7, 3, 11, 15), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 11, 15), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 11, 15), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 11, 15), -# ), -# datetime(2014, 7, 7, 9, 1): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 11, 15), -# ), -# }, -# ) -# ) -# -# opening_time_cases.append( -# ( -# [ -# BusinessHour(-1), -# BusinessHour(n=-2), -# BusinessHour(n=-4), -# BusinessHour(n=-1, end="10:00"), -# BusinessHour(n=-2, end="4:00"), -# BusinessHour(n=-4, end="15:00"), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 7, 1, 9), -# datetime(2014, 7, 2, 9), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 1, 9), -# datetime(2014, 7, 2, 9), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 1, 9), -# datetime(2014, 7, 2, 9), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 1, 9), -# datetime(2014, 7, 2, 9), -# ), -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 2, 9), -# ), -# datetime(2014, 7, 2, 10): ( -# datetime(2014, 7, 2, 9), -# datetime(2014, 7, 3, 9), -# ), -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 4, 9), -# datetime(2014, 7, 7, 9), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 4, 9), -# datetime(2014, 7, 7, 9), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 4, 9), -# datetime(2014, 7, 7, 9), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 4, 9), -# datetime(2014, 7, 7, 9), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 4, 9), -# datetime(2014, 7, 7, 9), -# ), -# datetime(2014, 7, 7, 9): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 7, 9), -# ), -# datetime(2014, 7, 7, 9, 1): ( -# datetime(2014, 7, 7, 9), -# datetime(2014, 7, 8, 9), -# ), -# }, -# ) -# ) -# -# opening_time_cases.append( -# ( -# [ -# BusinessHour(start="17:00", end="05:00"), -# BusinessHour(n=3, start="17:00", end="03:00"), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 6, 30, 17), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 2, 17), -# datetime(2014, 7, 1, 17), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 2, 17), -# datetime(2014, 7, 1, 17), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 2, 17), -# datetime(2014, 7, 1, 17), -# ), -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 2, 17), -# datetime(2014, 7, 1, 17), -# ), -# datetime(2014, 7, 4, 17): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 7, 17), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 3, 17), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 7, 17), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 7, 17), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 7, 17), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 7, 17, 1): ( -# datetime(2014, 7, 8, 17), -# datetime(2014, 7, 7, 17), -# ), -# }, -# ) -# ) -# -# opening_time_cases.append( -# ( -# [ -# BusinessHour(-1, start="17:00", end="05:00"), -# BusinessHour(n=-2, start="17:00", end="03:00"), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 6, 30, 17), -# datetime(2014, 7, 1, 17), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 2, 16, 59): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 17), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 3, 17), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 17), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 17), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 17), -# ), -# datetime(2014, 7, 7, 18): ( -# datetime(2014, 7, 7, 17), -# datetime(2014, 7, 8, 17), -# ), -# }, -# ) -# ) -# -# opening_time_cases.append( -# ( -# [ -# BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), -# BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), -# BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), -# BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), -# BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 7, 1, 11, 15), -# datetime(2014, 6, 30, 15), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 15), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 15), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 15), -# ), -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 15), -# ), -# datetime(2014, 7, 2, 10): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 1, 15), -# ), -# datetime(2014, 7, 2, 11, 15): ( -# datetime(2014, 7, 2, 11, 15), -# datetime(2014, 7, 2, 11, 15), -# ), -# datetime(2014, 7, 2, 11, 15, 1): ( -# datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 11, 15), -# ), -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 15), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 4, 11, 15), -# datetime(2014, 7, 3, 15), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 15), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 15), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 15), -# ), -# datetime(2014, 7, 7, 9, 1): ( -# datetime(2014, 7, 7, 11, 15), -# datetime(2014, 7, 4, 15), -# ), -# datetime(2014, 7, 7, 12): ( -# datetime(2014, 7, 7, 15), -# datetime(2014, 7, 7, 11, 15), -# ), -# }, -# ) -# ) -# -# opening_time_cases.append( -# ( -# [ -# BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), -# BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), -# ], -# { -# datetime(2014, 7, 1, 11): ( -# datetime(2014, 7, 1, 8), -# datetime(2014, 7, 1, 17), -# ), -# datetime(2014, 7, 1, 18): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 8), -# ), -# datetime(2014, 7, 1, 23): ( -# datetime(2014, 7, 1, 17), -# datetime(2014, 7, 2, 8), -# ), -# datetime(2014, 7, 2, 8): ( -# datetime(2014, 7, 2, 8), -# datetime(2014, 7, 2, 8), -# ), -# datetime(2014, 7, 2, 9): ( -# datetime(2014, 7, 2, 8), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 2, 16, 59): ( -# datetime(2014, 7, 2, 8), -# datetime(2014, 7, 2, 17), -# ), -# datetime(2014, 7, 5, 10): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 8), -# ), -# datetime(2014, 7, 4, 10): ( -# datetime(2014, 7, 4, 8), -# datetime(2014, 7, 4, 17), -# ), -# datetime(2014, 7, 4, 23): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 8), -# ), -# datetime(2014, 7, 6, 10): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 8), -# ), -# datetime(2014, 7, 7, 5): ( -# datetime(2014, 7, 4, 17), -# datetime(2014, 7, 7, 8), -# ), -# datetime(2014, 7, 7, 18): ( -# datetime(2014, 7, 7, 17), -# datetime(2014, 7, 8, 8), -# ), -# }, -# ) -# ) -# -# @pytest.mark.parametrize("case", opening_time_cases) -# def test_opening_time(self, case): -# _offsets, cases = case -# for offset in _offsets: -# for dt, (exp_next, exp_prev) in cases.items(): -# assert offset._next_opening_time(dt) == exp_next -# assert offset._prev_opening_time(dt) == exp_prev -# -# apply_cases = [] -# apply_cases.append( -# ( -# BusinessHour(), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), -# # out of business hours -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), -# # saturday -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), -# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(4), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), -# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(-1), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), -# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), -# datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), -# # out of business hours -# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), -# # saturday -# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), -# datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), -# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), -# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(-4), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), -# datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), -# datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), -# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), -# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(start="13:00", end="16:00"), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), -# datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=2, start="13:00", end="16:00"), -# { -# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), -# datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), -# datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), -# datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=-1, start="13:00", end="16:00"), -# { -# datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), -# datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=-3, start="10:00", end="16:00"), -# { -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), -# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), -# datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), -# datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), -# datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), -# datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), -# datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(start="19:00", end="05:00"), -# { -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), -# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), -# datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), -# datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), -# datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), -# datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), -# datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), -# datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), -# datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), -# datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=-1, start="19:00", end="05:00"), -# { -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), -# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), -# datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), -# datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), -# datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), -# datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), -# datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), -# datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), -# }, -# ) -# ) -# -# # long business hours (see gh-26381) -# apply_cases.append( -# ( -# BusinessHour(n=4, start="00:00", end="23:00"), -# { -# datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), -# datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), -# datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), -# datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), -# datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), -# datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=-4, start="00:00", end="23:00"), -# { -# datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), -# datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), -# datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), -# datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), -# datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), -# datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), -# }, -# ) -# ) -# -# # multiple business hours -# apply_cases.append( -# ( -# BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), -# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), -# # out of business hours -# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), -# # saturday -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), -# datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), -# datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), -# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), -# datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), -# datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), -# datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), -# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), -# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), -# { -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), -# datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), -# datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), -# datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), -# datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), -# datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), -# datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), -# datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), -# datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), -# datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), -# datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), -# }, -# ) -# ) -# -# @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) -# -# apply_large_n_cases = [] -# # A week later -# apply_large_n_cases.append( -# ( -# BusinessHour(40), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), -# datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), -# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), -# datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), -# }, -# ) -# ) -# -# # 3 days and 1 hour before -# apply_large_n_cases.append( -# ( -# BusinessHour(-25), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), -# datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), -# datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), -# datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), -# datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), -# datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), -# datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), -# datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), -# datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), -# datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), -# }, -# ) -# ) -# -# # 5 days and 3 hours later -# apply_large_n_cases.append( -# ( -# BusinessHour(28, start="21:00", end="02:00"), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), -# datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), -# datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), -# datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), -# datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), -# datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), -# datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), -# datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), -# datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), -# datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), -# datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), -# datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), -# }, -# ) -# ) -# -# # large n for multiple opening hours (3 days and 1 hour before) -# apply_large_n_cases.append( -# ( -# BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), -# datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), -# datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), -# datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), -# datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), -# datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), -# datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), -# datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), -# datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), -# datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), -# datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), -# datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), -# }, -# ) -# ) -# -# # 5 days and 3 hours later -# apply_large_n_cases.append( -# ( -# BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), -# datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), -# datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), -# datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), -# datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), -# datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), -# datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), -# datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), -# datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), -# datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), -# datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), -# datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), -# datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), -# datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), -# }, -# ) -# ) -# -# @pytest.mark.parametrize("case", apply_large_n_cases) -# def test_apply_large_n(self, case): -# offset, cases = case -# for base, expected in cases.items(): -# assert_offset_equal(offset, base, expected) -# -# def test_apply_nanoseconds(self): -# tests = [] -# -# tests.append( -# ( -# BusinessHour(), -# { -# Timestamp("2014-07-04 15:00") -# + Nano(5): Timestamp("2014-07-04 16:00") -# + Nano(5), -# Timestamp("2014-07-04 16:00") -# + Nano(5): Timestamp("2014-07-07 09:00") -# + Nano(5), -# Timestamp("2014-07-04 16:00") -# - Nano(5): Timestamp("2014-07-04 17:00") -# - Nano(5), -# }, -# ) -# ) -# -# tests.append( -# ( -# BusinessHour(-1), -# { -# Timestamp("2014-07-04 15:00") -# + Nano(5): Timestamp("2014-07-04 14:00") -# + Nano(5), -# Timestamp("2014-07-04 10:00") -# + Nano(5): Timestamp("2014-07-04 09:00") -# + Nano(5), -# Timestamp("2014-07-04 10:00") -# - Nano(5): Timestamp("2014-07-03 17:00") -# - Nano(5), -# }, -# ) -# ) -# -# for offset, cases in tests: -# for base, expected in cases.items(): -# assert_offset_equal(offset, base, expected) -# -# def test_datetimeindex(self): -# idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") -# idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") -# idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") -# expected = DatetimeIndex( -# [ -# "2014-07-04 15:00", -# "2014-07-04 16:00", -# "2014-07-07 09:00", -# "2014-07-07 10:00", -# "2014-07-07 11:00", -# "2014-07-07 12:00", -# "2014-07-07 13:00", -# "2014-07-07 14:00", -# "2014-07-07 15:00", -# "2014-07-07 16:00", -# "2014-07-08 09:00", -# "2014-07-08 10:00", -# ], -# freq="BH", -# ) -# for idx in [idx1, idx2, idx3]: -# tm.assert_index_equal(idx, expected) -# -# idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") -# idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") -# idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") -# -# expected = DatetimeIndex( -# [ -# "2014-07-04 15:45", -# "2014-07-04 16:45", -# "2014-07-07 09:45", -# "2014-07-07 10:45", -# "2014-07-07 11:45", -# "2014-07-07 12:45", -# "2014-07-07 13:45", -# "2014-07-07 14:45", -# "2014-07-07 15:45", -# "2014-07-07 16:45", -# "2014-07-08 09:45", -# "2014-07-08 10:45", -# ], -# freq="BH", -# ) -# expected = idx1 -# for idx in [idx1, idx2, idx3]: -# tm.assert_index_equal(idx, expected) - - -# class TestCustomBusinessHour(Base): -# _offset = CustomBusinessHour -# holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] -# -# def setup_method(self, method): -# # 2014 Calendar to check custom holidays -# # Sun Mon Tue Wed Thu Fri Sat -# # 6/22 23 24 25 26 27 28 -# # 29 30 7/1 2 3 4 5 -# # 6 7 8 9 10 11 12 -# self.d = datetime(2014, 7, 1, 10, 00) -# self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") -# -# self.offset2 = CustomBusinessHour(holidays=self.holidays) -# -# def test_constructor_errors(self): -# from datetime import time as dt_time -# -# with pytest.raises(ValueError): -# CustomBusinessHour(start=dt_time(11, 0, 5)) -# with pytest.raises(ValueError): -# CustomBusinessHour(start="AAA") -# with pytest.raises(ValueError): -# CustomBusinessHour(start="14:00:05") -# -# 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.offset1) == "" -# assert repr(self.offset2) == "" -# -# def test_with_offset(self): -# expected = Timestamp("2014-07-01 13:00") -# -# assert self.d + CustomBusinessHour() * 3 == expected -# assert self.d + CustomBusinessHour(n=3) == expected -# -# def test_eq(self): -# for offset in [self.offset1, self.offset2]: -# assert offset == offset -# -# assert CustomBusinessHour() != CustomBusinessHour(-1) -# assert CustomBusinessHour(start="09:00") == CustomBusinessHour() -# assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") -# assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( -# start="17:00", end="09:01" -# ) -# -# assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( -# weekmask="Mon Tue Wed Thu Fri" -# ) -# assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( -# holidays=["2014-06-28"] -# ) -# -# def test_sub(self): -# # override the Base.test_sub implementation because self.offset2 is -# # defined differently in this class than the test expects -# pass -# -# def test_hash(self): -# assert hash(self.offset1) == hash(self.offset1) -# assert hash(self.offset2) == hash(self.offset2) -# -# def test_call(self): -# assert self.offset1(self.d) == datetime(2014, 7, 1, 11) -# assert self.offset2(self.d) == datetime(2014, 7, 1, 11) -# -# def testRollback1(self): -# assert self.offset1.rollback(self.d) == self.d -# assert self.offset2.rollback(self.d) == self.d -# -# d = datetime(2014, 7, 1, 0) -# -# # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) -# assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) -# -# # 2014/6/30 and 2014/6/27 are holidays -# assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) -# -# def testRollback2(self): -# assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( -# 2014, 7, 4, 17, 0 -# ) -# -# def testRollforward1(self): -# assert self.offset1.rollforward(self.d) == self.d -# assert self.offset2.rollforward(self.d) == self.d -# -# d = datetime(2014, 7, 1, 0) -# assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) -# assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) -# -# def testRollforward2(self): -# assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( -# 2014, 7, 7, 9 -# ) -# -# def test_roll_date_object(self): -# offset = BusinessHour() -# -# dt = datetime(2014, 7, 6, 15, 0) -# -# result = offset.rollback(dt) -# assert result == datetime(2014, 7, 4, 17) -# -# result = offset.rollforward(dt) -# assert result == datetime(2014, 7, 7, 9) -# -# normalize_cases = [] -# normalize_cases.append( -# ( -# CustomBusinessHour(normalize=True, holidays=holidays), -# { -# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 3), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 3), -# datetime(2014, 7, 1, 23): datetime(2014, 7, 3), -# datetime(2014, 7, 1, 0): datetime(2014, 7, 1), -# datetime(2014, 7, 4, 15): datetime(2014, 7, 4), -# datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), -# datetime(2014, 7, 5, 23): datetime(2014, 7, 7), -# datetime(2014, 7, 6, 10): datetime(2014, 7, 7), -# }, -# ) -# ) -# -# normalize_cases.append( -# ( -# CustomBusinessHour(-1, normalize=True, holidays=holidays), -# { -# datetime(2014, 7, 1, 8): datetime(2014, 6, 26), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 10): datetime(2014, 6, 26), -# datetime(2014, 7, 1, 0): datetime(2014, 6, 26), -# datetime(2014, 7, 7, 10): datetime(2014, 7, 4), -# datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), -# datetime(2014, 7, 5, 23): datetime(2014, 7, 4), -# datetime(2014, 7, 6, 10): datetime(2014, 7, 4), -# }, -# ) -# ) -# -# normalize_cases.append( -# ( -# CustomBusinessHour( -# 1, normalize=True, start="17:00", end="04:00", holidays=holidays -# ), -# { -# datetime(2014, 7, 1, 8): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 1), -# datetime(2014, 7, 1, 23): datetime(2014, 7, 2), -# datetime(2014, 7, 2, 2): datetime(2014, 7, 2), -# datetime(2014, 7, 2, 3): datetime(2014, 7, 3), -# datetime(2014, 7, 4, 23): datetime(2014, 7, 5), -# datetime(2014, 7, 5, 2): datetime(2014, 7, 5), -# datetime(2014, 7, 7, 2): datetime(2014, 7, 7), -# datetime(2014, 7, 7, 17): datetime(2014, 7, 7), -# }, -# ) -# ) -# -# @pytest.mark.parametrize("norm_cases", normalize_cases) -# def test_normalize(self, norm_cases): -# offset, cases = norm_cases -# for dt, expected in cases.items(): -# assert offset.apply(dt) == expected -# -# def test_onOffset(self): -# tests = [] -# -# tests.append( -# ( -# CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), -# { -# datetime(2014, 7, 1, 9): False, -# datetime(2014, 7, 1, 10): True, -# datetime(2014, 7, 1, 15): True, -# datetime(2014, 7, 1, 15, 1): False, -# datetime(2014, 7, 5, 12): False, -# datetime(2014, 7, 6, 12): False, -# }, -# ) -# ) -# -# for offset, cases in tests: -# for dt, expected in cases.items(): -# assert offset.onOffset(dt) == expected -# -# apply_cases = [] -# apply_cases.append( -# ( -# CustomBusinessHour(holidays=holidays), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), -# datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), -# datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), -# # out of business hours -# datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), -# # saturday -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), -# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# CustomBusinessHour(4, holidays=holidays), -# { -# datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), -# datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), -# datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), -# datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), -# datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), -# datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), -# datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), -# datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), -# datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), -# }, -# ) -# ) -# -# @pytest.mark.parametrize("apply_case", apply_cases) -# def test_apply(self, apply_case): -# offset, cases = apply_case -# for base, expected in cases.items(): -# assert_offset_equal(offset, base, expected) -# -# nano_cases = [] -# nano_cases.append( -# ( -# CustomBusinessHour(holidays=holidays), -# { -# Timestamp("2014-07-01 15:00") -# + Nano(5): Timestamp("2014-07-01 16:00") -# + Nano(5), -# Timestamp("2014-07-01 16:00") -# + Nano(5): Timestamp("2014-07-03 09:00") -# + Nano(5), -# Timestamp("2014-07-01 16:00") -# - Nano(5): Timestamp("2014-07-01 17:00") -# - Nano(5), -# }, -# ) -# ) -# -# nano_cases.append( -# ( -# CustomBusinessHour(-1, holidays=holidays), -# { -# Timestamp("2014-07-01 15:00") -# + Nano(5): Timestamp("2014-07-01 14:00") -# + Nano(5), -# Timestamp("2014-07-01 10:00") -# + Nano(5): Timestamp("2014-07-01 09:00") -# + Nano(5), -# Timestamp("2014-07-01 10:00") -# - Nano(5): Timestamp("2014-06-26 17:00") -# - Nano(5), -# }, -# ) -# ) -# -# @pytest.mark.parametrize("nano_case", nano_cases) -# def test_apply_nanoseconds(self, nano_case): -# offset, cases = nano_case -# for base, expected in cases.items(): -# assert_offset_equal(offset, base, expected) - - -# 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>" -# -# if compat.PY37: -# expected = "" -# else: -# 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_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): -# 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_onOffset(self, case): -# offset, d, expected = case -# assert_onOffset(offset, d, expected) -# -# apply_cases = [] # type: _ApplyCases -# apply_cases.append( -# ( -# 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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# 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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -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), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# 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 +class Base: + _offset = None # type: Type[DateOffset] + d = Timestamp(datetime(2008, 1, 2)) + + timezones = [ + None, + "UTC", + "Asia/Tokyo", + "US/Eastern", + "dateutil/Asia/Tokyo", + "dateutil/US/Pacific", + ] + + def _get_offset(self, klass, value=1, normalize=False): + # create instance from offset class + if klass is FY5253: + klass = klass( + n=value, + startingMonth=1, + weekday=1, + variation="last", + normalize=normalize, + ) + elif klass is FY5253Quarter: + klass = klass( + n=value, + startingMonth=1, + weekday=1, + qtr_with_extra_week=1, + variation="last", + normalize=normalize, + ) + elif klass is LastWeekOfMonth: + klass = klass(n=value, weekday=5, normalize=normalize) + elif klass is WeekOfMonth: + klass = klass(n=value, week=1, weekday=5, normalize=normalize) + elif klass is Week: + klass = klass(n=value, weekday=5, normalize=normalize) + elif klass is DateOffset: + klass = klass(days=value, normalize=normalize) + else: + klass = klass(value, normalize=normalize) + return klass + + def test_apply_out_of_range(self, tz_naive_fixture): + tz = tz_naive_fixture + if self._offset is None: + return + + # try to create an out-of-bounds result timestamp; if we can't create + # the offset skip + try: + if self._offset in (BusinessHour, CustomBusinessHour): + # Using 10000 in BusinessHour fails in tz check because of DST + # difference + offset = self._get_offset(self._offset, value=100000) + else: + offset = self._get_offset(self._offset, value=10000) + + result = Timestamp("20080101") + offset + assert isinstance(result, datetime) + assert result.tzinfo is None + + # Check tz is preserved + t = Timestamp("20080101", tz=tz) + result = t + offset + assert isinstance(result, datetime) + assert t.tzinfo == result.tzinfo + + except OutOfBoundsDatetime: + pass + except (ValueError, KeyError): + # we are creating an invalid offset + # so ignore + pass + + def test_offsets_compare_equal(self): + # root cause of GH#456: __ne__ was not implemented + if self._offset is None: + return + offset1 = self._offset() + offset2 = self._offset() + assert not offset1 != offset2 + assert offset1 == offset2 + + def test_rsub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert self.d - self.offset2 == (-self.offset2).apply(self.d) + + def test_radd(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert self.d + self.offset2 == self.offset2 + self.d + + def test_sub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + off = self.offset2 + msg = "Cannot subtract datetime from offset" + with pytest.raises(TypeError, match=msg): + off - self.d + + assert 2 * off - off == off + assert self.d - self.offset2 == self.d + self._offset(-2) + assert self.d - self.offset2 == self.d - (2 * off - off) + + def testMult1(self): + if self._offset is None or not hasattr(self, "offset1"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset1 attr + return + assert self.d + 10 * self.offset1 == self.d + self._offset(10) + assert self.d + 5 * self.offset1 == self.d + self._offset(5) + + def testMult2(self): + if self._offset is None: + return + assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) + assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) + + def test_compare_str(self): + # GH#23524 + # comparing to strings that cannot be cast to DateOffsets should + # not raise for __eq__ or __ne__ + if self._offset is None: + return + off = self._get_offset(self._offset) + + assert not off == "infer" + assert off != "foo" + # Note: inequalities are only implemented for Tick subclasses; + # tests for this are in test_ticks + + +class TestCommon(Base): + # exected value created by Base._get_offset + # are applied to 2011/01/01 09:00 (Saturday) + # used for .apply and .rollforward + expecteds = { + "Day": Timestamp("2011-01-02 09:00:00"), + "DateOffset": Timestamp("2011-01-02 09:00:00"), + "BusinessDay": Timestamp("2011-01-03 09:00:00"), + "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), + "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), + "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), + "MonthBegin": Timestamp("2011-02-01 09:00:00"), + "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), + "MonthEnd": Timestamp("2011-01-31 09:00:00"), + "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), + "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), + "YearBegin": Timestamp("2012-01-01 09:00:00"), + "BYearBegin": Timestamp("2011-01-03 09:00:00"), + "YearEnd": Timestamp("2011-12-31 09:00:00"), + "BYearEnd": Timestamp("2011-12-30 09:00:00"), + "QuarterBegin": Timestamp("2011-03-01 09:00:00"), + "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), + "QuarterEnd": Timestamp("2011-03-31 09:00:00"), + "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), + "BusinessHour": Timestamp("2011-01-03 10:00:00"), + "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), + "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), + "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), + "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), + "FY5253": Timestamp("2011-01-25 09:00:00"), + "Week": Timestamp("2011-01-08 09:00:00"), + "Easter": Timestamp("2011-04-24 09:00:00"), + "Hour": Timestamp("2011-01-01 10:00:00"), + "Minute": Timestamp("2011-01-01 09:01:00"), + "Second": Timestamp("2011-01-01 09:00:01"), + "Milli": Timestamp("2011-01-01 09:00:00.001000"), + "Micro": Timestamp("2011-01-01 09:00:00.000001"), + "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), + } + + def test_immutable(self, business_offset_types): + # GH#21341 check that __setattr__ raises + offset = self._get_offset(business_offset_types) + with pytest.raises(AttributeError): + offset.normalize = True + with pytest.raises(AttributeError): + offset.n = 91 + + def test_return_type(self, business_offset_types): + offset = self._get_offset(business_offset_types) + + # make sure that we are returning a Timestamp + result = Timestamp("20080101") + offset + assert isinstance(result, Timestamp) + + # make sure that we are returning NaT + assert NaT + offset is NaT + assert offset + NaT is NaT + + assert NaT - offset is NaT + assert (-offset).apply(NaT) is NaT + + def test_offset_n(self, business_offset_types): + offset = self._get_offset(business_offset_types) + assert offset.n == 1 + + neg_offset = offset * -1 + assert neg_offset.n == -1 + + mul_offset = offset * 3 + assert mul_offset.n == 3 + + def test_offset_timedelta64_arg(self, business_offset_types): + # check that offset._validate_n raises TypeError on a timedelt64 + # object + off = self._get_offset(business_offset_types) + + td64 = np.timedelta64(4567, "s") + with pytest.raises(TypeError, match="argument must be an integer"): + type(off)(n=td64, **off.kwds) + + def test_offset_mul_ndarray(self, business_offset_types): + off = self._get_offset(business_offset_types) + + expected = np.array([[off, off * 2], [off * 3, off * 4]]) + + result = np.array([[1, 2], [3, 4]]) * off + tm.assert_numpy_array_equal(result, expected) + + result = off * np.array([[1, 2], [3, 4]]) + tm.assert_numpy_array_equal(result, expected) + + def test_offset_freqstr(self, business_offset_types): + offset = self._get_offset(business_offset_types) + + freqstr = offset.freqstr + if freqstr not in ("", "", "LWOM-SAT"): + code = get_offset(freqstr) + assert offset.rule_code == code + + def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): + + if normalize and issubclass(offset, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + + offset_s = self._get_offset(offset, normalize=normalize) + func = getattr(offset_s, funcname) + + result = func(dt) + assert isinstance(result, Timestamp) + assert result == expected + + result = func(Timestamp(dt)) + assert isinstance(result, Timestamp) + assert result == expected + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected + Nano(5) + else: + assert result == expected + + if isinstance(dt, np.datetime64): + # test tz when input is datetime or Timestamp + return + + for tz in self.timezones: + expected_localize = expected.tz_localize(tz) + tz_obj = timezones.maybe_get_tz(tz) + dt_tz = conversion.localize_pydatetime(dt, tz_obj) + + result = func(dt_tz) + assert isinstance(result, Timestamp) + assert result == expected_localize + + result = func(Timestamp(dt, tz=tz)) + assert isinstance(result, Timestamp) + assert result == expected_localize + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt, tz=tz) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected_localize + Nano(5) + else: + assert result == expected_localize + + def test_apply(self, business_offset_types): + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = self.expecteds[business_offset_types.__name__] + self._check_offsetfunc_works(business_offset_types, "apply", dt, expected) + + expected = Timestamp(expected.date()) + self._check_offsetfunc_works( + business_offset_types, "apply", dt, expected, normalize=True + ) + + def test_rollforward(self, business_offset_types): + expecteds = self.expecteds.copy() + + # result will not be changed if the target is on the offset + no_changes = [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ] + for n in no_changes: + expecteds[n] = Timestamp("2011/01/01 09:00") + + expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") + expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2011-01-02 00:00:00"), + "DateOffset": Timestamp("2011-01-02 00:00:00"), + "MonthBegin": Timestamp("2011-02-01 00:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), + "YearBegin": Timestamp("2012-01-01 00:00:00"), + "Week": Timestamp("2011-01-08 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[business_offset_types.__name__] + self._check_offsetfunc_works(business_offset_types, "rollforward", dt, expected) + expected = norm_expected[business_offset_types.__name__] + self._check_offsetfunc_works( + business_offset_types, "rollforward", dt, expected, normalize=True + ) + + def test_rollback(self, business_offset_types): + expecteds = { + "BusinessDay": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), + "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), + "MonthEnd": Timestamp("2010-12-31 09:00:00"), + "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), + "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), + "BYearBegin": Timestamp("2010-01-01 09:00:00"), + "YearEnd": Timestamp("2010-12-31 09:00:00"), + "BYearEnd": Timestamp("2010-12-31 09:00:00"), + "QuarterBegin": Timestamp("2010-12-01 09:00:00"), + "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), + "QuarterEnd": Timestamp("2010-12-31 09:00:00"), + "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), + "BusinessHour": Timestamp("2010-12-31 17:00:00"), + "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), + "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), + "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), + "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), + "FY5253": Timestamp("2010-01-26 09:00:00"), + "Easter": Timestamp("2010-04-04 09:00:00"), + } + + # result will not be changed if the target is on the offset + for n in [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ]: + expecteds[n] = Timestamp("2011/01/01 09:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2010-12-31 00:00:00"), + "DateOffset": Timestamp("2010-12-31 00:00:00"), + "MonthBegin": Timestamp("2010-12-01 00:00:00"), + "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), + "YearBegin": Timestamp("2010-01-01 00:00:00"), + "Week": Timestamp("2010-12-25 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[business_offset_types.__name__] + self._check_offsetfunc_works(business_offset_types, "rollback", dt, expected) + + expected = norm_expected[business_offset_types.__name__] + self._check_offsetfunc_works( + business_offset_types, "rollback", dt, expected, normalize=True + ) + + def test_onOffset(self, business_offset_types): + dt = self.expecteds[business_offset_types.__name__] + offset_s = self._get_offset(business_offset_types) + assert offset_s.onOffset(dt) + + # when normalize=True, onOffset checks time is 00:00:00 + if issubclass(business_offset_types, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + offset_n = self._get_offset(business_offset_types, normalize=True) + assert not offset_n.onOffset(dt) + + if business_offset_types in (BusinessHour, CustomBusinessHour): + # In default BusinessHour (9:00-17:00), normalized time + # cannot be in business hour range + return + date = datetime(dt.year, dt.month, dt.day) + assert offset_n.onOffset(date) + + def test_add(self, business_offset_types, tz_naive_fixture): + tz = tz_naive_fixture + dt = datetime(2011, 1, 1, 9, 0) + + offset_s = self._get_offset(business_offset_types) + expected = self.expecteds[business_offset_types.__name__] + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + # normalize=True, disallowed for Tick subclasses GH#21427 + if issubclass(business_offset_types, Tick): + return + offset_s = self._get_offset(business_offset_types, normalize=True) + expected = Timestamp(expected.date()) + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + def test_pickle_v0_15_2(self, datapath): + offsets = { + "DateOffset": DateOffset(years=1), + "MonthBegin": MonthBegin(1), + "Day": Day(1), + "YearBegin": YearBegin(1), + "Week": Week(1), + } + + pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") + # This code was executed once on v0.15.2 to generate the pickle: + # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) + # + tm.assert_dict_equal(offsets, read_pickle(pickle_path)) + + +class TestBusinessDay(Base): + _offset = BDay + + def setup_method(self, method): + self.d = datetime(2008, 1, 1) + + self.offset = BDay() + self.offset1 = self.offset + self.offset2 = BDay(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 * BusinessDays>" + + if compat.PY37: + expected = "" + else: + 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_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): + assert self.offset2(self.d) == datetime(2008, 1, 3) + + def testRollback1(self): + assert BDay(10).rollback(self.d) == self.d + + def testRollback2(self): + assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) + + def testRollforward1(self): + assert BDay(10).rollforward(self.d) == self.d + + def testRollforward2(self): + assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) + + def test_roll_date_object(self): + offset = BDay() + + 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) + + def test_onOffset(self): + tests = [ + (BDay(), datetime(2008, 1, 1), True), + (BDay(), datetime(2008, 1, 5), False), + ] + + for offset, d, expected in tests: + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + 2 * BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + -BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + -2 * BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + BDay(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 + BDay(10) + assert result == datetime(2012, 11, 6) + + result = dt + BDay(100) - BDay(100) + assert result == dt + + off = BDay() * 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 + + off = BDay() * 10 + rs = datetime(2014, 1, 5) + off # see #5890 + xp = datetime(2014, 1, 17) + assert rs == xp + + 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 TestBusinessHour(Base): + _offset = BusinessHour + + def setup_method(self, method): + self.d = datetime(2014, 7, 1, 10, 00) + + self.offset1 = BusinessHour() + self.offset2 = BusinessHour(n=3) + + self.offset3 = BusinessHour(n=-1) + self.offset4 = BusinessHour(n=-4) + + from datetime import time as dt_time + + self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) + self.offset6 = BusinessHour(start="20:00", end="05:00") + self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) + self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) + self.offset9 = BusinessHour( + n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] + ) + self.offset10 = BusinessHour( + n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] + ) + + @pytest.mark.parametrize( + "start,end,match", + [ + ( + dt_time(11, 0, 5), + "17:00", + "time data must be specified only with hour and minute", + ), + ("AAA", "17:00", "time data must match '%H:%M' format"), + ("14:00:05", "17:00", "time data must match '%H:%M' format"), + ([], "17:00", "Must include at least 1 start time"), + ("09:00", [], "Must include at least 1 end time"), + ( + ["09:00", "11:00"], + "17:00", + "number of starting time and ending time must be the same", + ), + ( + ["09:00", "11:00"], + ["10:00"], + "number of starting time and ending time must be the same", + ), + ( + ["09:00", "11:00"], + ["12:00", "20:00"], + r"invalid starting and ending time\(s\): opening hours should not " + "touch or overlap with one another", + ), + ( + ["12:00", "20:00"], + ["09:00", "11:00"], + r"invalid starting and ending time\(s\): opening hours should not " + "touch or overlap with one another", + ), + ], + ) + def test_constructor_errors(self, start, end, match): + with pytest.raises(ValueError, match=match): + BusinessHour(start=start, end=end) + + 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.offset1) == "" + assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" + assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" + assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" + + assert repr(self.offset5) == "" + assert repr(self.offset6) == "" + assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" + assert repr(self.offset8) == "" + assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" + assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" + + def test_with_offset(self): + expected = Timestamp("2014-07-01 13:00") + + assert self.d + BusinessHour() * 3 == expected + assert self.d + BusinessHour(n=3) == expected + + @pytest.mark.parametrize( + "offset_name", + ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], + ) + def test_eq_attribute(self, offset_name): + offset = getattr(self, offset_name) + assert offset == offset + + @pytest.mark.parametrize( + "offset1,offset2", + [ + (BusinessHour(start="09:00"), BusinessHour()), + ( + BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), + BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), + ), + ], + ) + def test_eq(self, offset1, offset2): + assert offset1 == offset2 + + @pytest.mark.parametrize( + "offset1,offset2", + [ + (BusinessHour(), BusinessHour(-1)), + (BusinessHour(start="09:00"), BusinessHour(start="09:01")), + ( + BusinessHour(start="09:00", end="17:00"), + BusinessHour(start="17:00", end="09:01"), + ), + ( + BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), + BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), + ), + ], + ) + def test_neq(self, offset1, offset2): + assert offset1 != offset2 + + @pytest.mark.parametrize( + "offset_name", + ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], + ) + def test_hash(self, offset_name): + offset = getattr(self, offset_name) + assert offset == offset + + def test_call(self): + assert self.offset1(self.d) == datetime(2014, 7, 1, 11) + assert self.offset2(self.d) == datetime(2014, 7, 1, 13) + assert self.offset3(self.d) == datetime(2014, 6, 30, 17) + assert self.offset4(self.d) == datetime(2014, 6, 30, 14) + assert self.offset8(self.d) == datetime(2014, 7, 1, 11) + assert self.offset9(self.d) == datetime(2014, 7, 1, 22) + assert self.offset10(self.d) == datetime(2014, 7, 1, 1) + + def test_sub(self): + # we have to override test_sub here because self.offset2 is not + # defined as self._offset(2) + off = self.offset2 + msg = "Cannot subtract datetime from offset" + with pytest.raises(TypeError, match=msg): + off - self.d + assert 2 * off - off == off + + assert self.d - self.offset2 == self.d + self._offset(-3) + + def testRollback1(self): + assert self.offset1.rollback(self.d) == self.d + assert self.offset2.rollback(self.d) == self.d + assert self.offset3.rollback(self.d) == self.d + assert self.offset4.rollback(self.d) == self.d + assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) + assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) + assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) + assert self.offset8.rollback(self.d) == self.d + assert self.offset9.rollback(self.d) == self.d + assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) + assert self.offset6.rollback(d) == d + assert self.offset7.rollback(d) == d + assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset9.rollback(d) == d + assert self.offset10.rollback(d) == d + + assert self._offset(5).rollback(self.d) == self.d + + def testRollback2(self): + assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( + 2014, 7, 4, 17, 0 + ) + + def testRollforward1(self): + assert self.offset1.rollforward(self.d) == self.d + assert self.offset2.rollforward(self.d) == self.d + assert self.offset3.rollforward(self.d) == self.d + assert self.offset4.rollforward(self.d) == self.d + assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) + assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) + assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) + assert self.offset8.rollforward(self.d) == self.d + assert self.offset9.rollforward(self.d) == self.d + assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) + assert self.offset6.rollforward(d) == d + assert self.offset7.rollforward(d) == d + assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset9.rollforward(d) == d + assert self.offset10.rollforward(d) == d + + assert self._offset(5).rollforward(self.d) == self.d + + def testRollforward2(self): + assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( + 2014, 7, 7, 9 + ) + + def test_roll_date_object(self): + offset = BusinessHour() + + dt = datetime(2014, 7, 6, 15, 0) + + result = offset.rollback(dt) + assert result == datetime(2014, 7, 4, 17) + + result = offset.rollforward(dt) + assert result == datetime(2014, 7, 7, 9) + + normalize_cases = [] + normalize_cases.append( + ( + BusinessHour(normalize=True), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 1, 0): datetime(2014, 7, 1), + datetime(2014, 7, 4, 15): datetime(2014, 7, 4), + datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 7), + datetime(2014, 7, 6, 10): datetime(2014, 7, 7), + }, + ) + ) + + normalize_cases.append( + ( + BusinessHour(-1, normalize=True), + { + datetime(2014, 7, 1, 8): datetime(2014, 6, 30), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1), + datetime(2014, 7, 1, 10): datetime(2014, 6, 30), + datetime(2014, 7, 1, 0): datetime(2014, 6, 30), + datetime(2014, 7, 7, 10): datetime(2014, 7, 4), + datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 4), + datetime(2014, 7, 6, 10): datetime(2014, 7, 4), + }, + ) + ) + + normalize_cases.append( + ( + BusinessHour(1, normalize=True, start="17:00", end="04:00"), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 2, 2): datetime(2014, 7, 2), + datetime(2014, 7, 2, 3): datetime(2014, 7, 2), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5), + datetime(2014, 7, 5, 2): datetime(2014, 7, 5), + datetime(2014, 7, 7, 2): datetime(2014, 7, 7), + datetime(2014, 7, 7, 17): datetime(2014, 7, 7), + }, + ) + ) + + @pytest.mark.parametrize("case", normalize_cases) + def test_normalize(self, case): + offset, cases = case + for dt, expected in cases.items(): + assert offset.apply(dt) == expected + + on_offset_cases = [] + on_offset_cases.append( + ( + BusinessHour(), + { + datetime(2014, 7, 1, 9): True, + datetime(2014, 7, 1, 8, 59): False, + datetime(2014, 7, 1, 8): False, + datetime(2014, 7, 1, 17): True, + datetime(2014, 7, 1, 17, 1): False, + datetime(2014, 7, 1, 18): False, + datetime(2014, 7, 5, 9): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start="10:00", end="15:00"), + { + datetime(2014, 7, 1, 9): False, + datetime(2014, 7, 1, 10): True, + datetime(2014, 7, 1, 15): True, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 9, 0): False, + datetime(2014, 7, 1, 10, 0): False, + datetime(2014, 7, 1, 15): False, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12, 0): False, + datetime(2014, 7, 6, 12, 0): False, + datetime(2014, 7, 1, 19, 0): True, + datetime(2014, 7, 2, 0, 0): True, + datetime(2014, 7, 4, 23): True, + datetime(2014, 7, 5, 1): True, + datetime(2014, 7, 5, 5, 0): True, + datetime(2014, 7, 6, 23, 0): False, + datetime(2014, 7, 7, 3, 0): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), + { + datetime(2014, 7, 1, 9): True, + datetime(2014, 7, 1, 8, 59): False, + datetime(2014, 7, 1, 8): False, + datetime(2014, 7, 1, 17): True, + datetime(2014, 7, 1, 17, 1): False, + datetime(2014, 7, 1, 18): False, + datetime(2014, 7, 5, 9): False, + datetime(2014, 7, 6, 12): False, + datetime(2014, 7, 1, 12, 30): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), + { + datetime(2014, 7, 1, 9, 0): False, + datetime(2014, 7, 1, 10, 0): False, + datetime(2014, 7, 1, 15): False, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12, 0): False, + datetime(2014, 7, 6, 12, 0): False, + datetime(2014, 7, 1, 19, 0): True, + datetime(2014, 7, 2, 0, 0): True, + datetime(2014, 7, 4, 23): True, + datetime(2014, 7, 5, 1): True, + datetime(2014, 7, 5, 5, 0): True, + datetime(2014, 7, 6, 23, 0): False, + datetime(2014, 7, 7, 3, 0): False, + datetime(2014, 7, 4, 22): False, + }, + ) + ) + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, cases = case + for dt, expected in cases.items(): + assert offset.onOffset(dt) == expected + + opening_time_cases = [] + # opening time should be affected by sign of n, not by n's value and + # end + opening_time_cases.append( + ( + [ + BusinessHour(), + BusinessHour(n=2), + BusinessHour(n=4), + BusinessHour(end="10:00"), + BusinessHour(n=2, end="4:00"), + BusinessHour(n=4, end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + # if timestamp is on opening time, next opening time is + # as it is + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 3, 9), + datetime(2014, 7, 2, 9), + ), + # 2014-07-05 is saturday + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 8, 9), + datetime(2014, 7, 7, 9), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start="11:15"), + BusinessHour(n=2, start="11:15"), + BusinessHour(n=3, start="11:15"), + BusinessHour(start="11:15", end="10:00"), + BusinessHour(n=2, start="11:15", end="4:00"), + BusinessHour(n=3, start="11:15", end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 11, 15), + datetime(2014, 6, 30, 11, 15), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 11, 15): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 2, 11, 15, 1): ( + datetime(2014, 7, 3, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 11, 15), + datetime(2014, 7, 3, 11, 15), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(-1), + BusinessHour(n=-2), + BusinessHour(n=-4), + BusinessHour(n=-1, end="10:00"), + BusinessHour(n=-2, end="4:00"), + BusinessHour(n=-4, end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 3, 9), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 9): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 8, 9), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start="17:00", end="05:00"), + BusinessHour(n=3, start="17:00", end="03:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 17), + datetime(2014, 6, 30, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 4, 17): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 3, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 7, 17, 1): ( + datetime(2014, 7, 8, 17), + datetime(2014, 7, 7, 17), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(-1, start="17:00", end="05:00"), + BusinessHour(n=-2, start="17:00", end="03:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 16, 59): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 3, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 7, 18): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 8, 17), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), + BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), + BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), + BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), + BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 11, 15), + datetime(2014, 6, 30, 15), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 11, 15): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 2, 11, 15, 1): ( + datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 11, 15), + datetime(2014, 7, 3, 15), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 12): ( + datetime(2014, 7, 7, 15), + datetime(2014, 7, 7, 11, 15), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), + BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 8), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 16, 59): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 8), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 7, 18): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 8, 8), + ), + }, + ) + ) + + @pytest.mark.parametrize("case", opening_time_cases) + def test_opening_time(self, case): + _offsets, cases = case + for offset in _offsets: + for dt, (exp_next, exp_prev) in cases.items(): + assert offset._next_opening_time(dt) == exp_next + assert offset._prev_opening_time(dt) == exp_prev + + apply_cases = [] + apply_cases.append( + ( + BusinessHour(), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(4), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(-1), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), + datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), + datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(-4), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), + datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(start="13:00", end="16:00"), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), + datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=2, start="13:00", end="16:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), + datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), + datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start="13:00", end="16:00"), + { + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), + datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-3, start="10:00", end="16:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), + datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), + datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), + datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), + datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), + datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), + datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), + datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), + datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), + datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), + datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), + datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), + datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), + datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), + }, + ) + ) + + # long business hours (see gh-26381) + apply_cases.append( + ( + BusinessHour(n=4, start="00:00", end="23:00"), + { + datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), + datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), + datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), + datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), + datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), + datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-4, start="00:00", end="23:00"), + { + datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), + datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), + datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), + datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), + datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), + datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), + }, + ) + ) + + # multiple business hours + apply_cases.append( + ( + BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), + # out of business hours + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), + datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), + datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), + datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), + datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), + datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), + datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), + datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), + datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), + datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), + datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), + datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), + }, + ) + ) + + @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) + + apply_large_n_cases = [] + # A week later + apply_large_n_cases.append( + ( + BusinessHour(40), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), + datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), + datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), + datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), + datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), + datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), + datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), + datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), + datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), + datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), + datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), + datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), + }, + ) + ) + + # 3 days and 1 hour before + apply_large_n_cases.append( + ( + BusinessHour(-25), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), + datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), + datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), + datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), + datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), + datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), + datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), + datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), + datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), + datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), + datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), + }, + ) + ) + + # 5 days and 3 hours later + apply_large_n_cases.append( + ( + BusinessHour(28, start="21:00", end="02:00"), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), + datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), + datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), + datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), + datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), + datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), + datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), + datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), + datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), + datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), + }, + ) + ) + + # large n for multiple opening hours (3 days and 1 hour before) + apply_large_n_cases.append( + ( + BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), + datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), + datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), + datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), + datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), + datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), + datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), + datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), + datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), + datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), + datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), + datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), + }, + ) + ) + + # 5 days and 3 hours later + apply_large_n_cases.append( + ( + BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), + datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), + datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), + datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), + datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), + datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), + datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), + datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), + datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), + datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), + }, + ) + ) + + @pytest.mark.parametrize("case", apply_large_n_cases) + def test_apply_large_n(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_apply_nanoseconds(self): + tests = [] + + tests.append( + ( + BusinessHour(), + { + Timestamp("2014-07-04 15:00") + + Nano(5): Timestamp("2014-07-04 16:00") + + Nano(5), + Timestamp("2014-07-04 16:00") + + Nano(5): Timestamp("2014-07-07 09:00") + + Nano(5), + Timestamp("2014-07-04 16:00") + - Nano(5): Timestamp("2014-07-04 17:00") + - Nano(5), + }, + ) + ) + + tests.append( + ( + BusinessHour(-1), + { + Timestamp("2014-07-04 15:00") + + Nano(5): Timestamp("2014-07-04 14:00") + + Nano(5), + Timestamp("2014-07-04 10:00") + + Nano(5): Timestamp("2014-07-04 09:00") + + Nano(5), + Timestamp("2014-07-04 10:00") + - Nano(5): Timestamp("2014-07-03 17:00") + - Nano(5), + }, + ) + ) + + for offset, cases in tests: + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_datetimeindex(self): + idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") + idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") + idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") + expected = DatetimeIndex( + [ + "2014-07-04 15:00", + "2014-07-04 16:00", + "2014-07-07 09:00", + "2014-07-07 10:00", + "2014-07-07 11:00", + "2014-07-07 12:00", + "2014-07-07 13:00", + "2014-07-07 14:00", + "2014-07-07 15:00", + "2014-07-07 16:00", + "2014-07-08 09:00", + "2014-07-08 10:00", + ], + freq="BH", + ) + for idx in [idx1, idx2, idx3]: + tm.assert_index_equal(idx, expected) + + idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") + idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") + idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") + + expected = DatetimeIndex( + [ + "2014-07-04 15:45", + "2014-07-04 16:45", + "2014-07-07 09:45", + "2014-07-07 10:45", + "2014-07-07 11:45", + "2014-07-07 12:45", + "2014-07-07 13:45", + "2014-07-07 14:45", + "2014-07-07 15:45", + "2014-07-07 16:45", + "2014-07-08 09:45", + "2014-07-08 10:45", + ], + freq="BH", + ) + expected = idx1 + for idx in [idx1, idx2, idx3]: + tm.assert_index_equal(idx, expected) + + +class TestCustomBusinessHour(Base): + _offset = CustomBusinessHour + holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] + + def setup_method(self, method): + # 2014 Calendar to check custom holidays + # Sun Mon Tue Wed Thu Fri Sat + # 6/22 23 24 25 26 27 28 + # 29 30 7/1 2 3 4 5 + # 6 7 8 9 10 11 12 + self.d = datetime(2014, 7, 1, 10, 00) + self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") + + self.offset2 = CustomBusinessHour(holidays=self.holidays) + + def test_constructor_errors(self): + from datetime import time as dt_time + + with pytest.raises(ValueError): + CustomBusinessHour(start=dt_time(11, 0, 5)) + with pytest.raises(ValueError): + CustomBusinessHour(start="AAA") + with pytest.raises(ValueError): + CustomBusinessHour(start="14:00:05") + + 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.offset1) == "" + assert repr(self.offset2) == "" + + def test_with_offset(self): + expected = Timestamp("2014-07-01 13:00") + + assert self.d + CustomBusinessHour() * 3 == expected + assert self.d + CustomBusinessHour(n=3) == expected + + def test_eq(self): + for offset in [self.offset1, self.offset2]: + assert offset == offset + + assert CustomBusinessHour() != CustomBusinessHour(-1) + assert CustomBusinessHour(start="09:00") == CustomBusinessHour() + assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") + assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( + start="17:00", end="09:01" + ) + + assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( + weekmask="Mon Tue Wed Thu Fri" + ) + assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( + holidays=["2014-06-28"] + ) + + def test_sub(self): + # override the Base.test_sub implementation because self.offset2 is + # defined differently in this class than the test expects + pass + + def test_hash(self): + assert hash(self.offset1) == hash(self.offset1) + assert hash(self.offset2) == hash(self.offset2) + + def test_call(self): + assert self.offset1(self.d) == datetime(2014, 7, 1, 11) + assert self.offset2(self.d) == datetime(2014, 7, 1, 11) + + def testRollback1(self): + assert self.offset1.rollback(self.d) == self.d + assert self.offset2.rollback(self.d) == self.d + + d = datetime(2014, 7, 1, 0) + + # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) + assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) + + # 2014/6/30 and 2014/6/27 are holidays + assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) + + def testRollback2(self): + assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( + 2014, 7, 4, 17, 0 + ) + + def testRollforward1(self): + assert self.offset1.rollforward(self.d) == self.d + assert self.offset2.rollforward(self.d) == self.d + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) + + def testRollforward2(self): + assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( + 2014, 7, 7, 9 + ) + + def test_roll_date_object(self): + offset = BusinessHour() + + dt = datetime(2014, 7, 6, 15, 0) + + result = offset.rollback(dt) + assert result == datetime(2014, 7, 4, 17) + + result = offset.rollforward(dt) + assert result == datetime(2014, 7, 7, 9) + + normalize_cases = [] + normalize_cases.append( + ( + CustomBusinessHour(normalize=True, holidays=holidays), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3), + datetime(2014, 7, 1, 23): datetime(2014, 7, 3), + datetime(2014, 7, 1, 0): datetime(2014, 7, 1), + datetime(2014, 7, 4, 15): datetime(2014, 7, 4), + datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 7), + datetime(2014, 7, 6, 10): datetime(2014, 7, 7), + }, + ) + ) + + normalize_cases.append( + ( + CustomBusinessHour(-1, normalize=True, holidays=holidays), + { + datetime(2014, 7, 1, 8): datetime(2014, 6, 26), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1), + datetime(2014, 7, 1, 10): datetime(2014, 6, 26), + datetime(2014, 7, 1, 0): datetime(2014, 6, 26), + datetime(2014, 7, 7, 10): datetime(2014, 7, 4), + datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 4), + datetime(2014, 7, 6, 10): datetime(2014, 7, 4), + }, + ) + ) + + normalize_cases.append( + ( + CustomBusinessHour( + 1, normalize=True, start="17:00", end="04:00", holidays=holidays + ), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 2, 2): datetime(2014, 7, 2), + datetime(2014, 7, 2, 3): datetime(2014, 7, 3), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5), + datetime(2014, 7, 5, 2): datetime(2014, 7, 5), + datetime(2014, 7, 7, 2): datetime(2014, 7, 7), + datetime(2014, 7, 7, 17): datetime(2014, 7, 7), + }, + ) + ) + + @pytest.mark.parametrize("norm_cases", normalize_cases) + def test_normalize(self, norm_cases): + offset, cases = norm_cases + for dt, expected in cases.items(): + assert offset.apply(dt) == expected + + def test_onOffset(self): + tests = [] + + tests.append( + ( + CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), + { + datetime(2014, 7, 1, 9): False, + datetime(2014, 7, 1, 10): True, + datetime(2014, 7, 1, 15): True, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + for offset, cases in tests: + for dt, expected in cases.items(): + assert offset.onOffset(dt) == expected + + apply_cases = [] + apply_cases.append( + ( + CustomBusinessHour(holidays=holidays), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + CustomBusinessHour(4, holidays=holidays), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), + }, + ) + ) + + @pytest.mark.parametrize("apply_case", apply_cases) + def test_apply(self, apply_case): + offset, cases = apply_case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + nano_cases = [] + nano_cases.append( + ( + CustomBusinessHour(holidays=holidays), + { + Timestamp("2014-07-01 15:00") + + Nano(5): Timestamp("2014-07-01 16:00") + + Nano(5), + Timestamp("2014-07-01 16:00") + + Nano(5): Timestamp("2014-07-03 09:00") + + Nano(5), + Timestamp("2014-07-01 16:00") + - Nano(5): Timestamp("2014-07-01 17:00") + - Nano(5), + }, + ) + ) + + nano_cases.append( + ( + CustomBusinessHour(-1, holidays=holidays), + { + Timestamp("2014-07-01 15:00") + + Nano(5): Timestamp("2014-07-01 14:00") + + Nano(5), + Timestamp("2014-07-01 10:00") + + Nano(5): Timestamp("2014-07-01 09:00") + + Nano(5), + Timestamp("2014-07-01 10:00") + - Nano(5): Timestamp("2014-06-26 17:00") + - Nano(5), + }, + ) + ) + + @pytest.mark.parametrize("nano_case", nano_cases) + def test_apply_nanoseconds(self, nano_case): + offset, cases = nano_case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + +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>" + + if compat.PY37: + expected = "" + else: + 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_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): + 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_onOffset(self, case): + offset, d, expected = case + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + 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), + }, + ) + ) + + apply_cases.append( + ( + 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), + }, + ) + ) + + apply_cases.append( + ( + -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), + }, + ) + ) + + apply_cases.append( + ( + -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), + }, + ) + ) + + apply_cases.append( + ( + 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 class CustomBusinessMonthBase: @@ -2771,301 +2770,301 @@ def test_copy(self): assert off == off.copy() -# class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): -# _offset = CBMonthEnd -# -# 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 * CustomBusinessMonthEnds>" -# -# def testCall(self): -# assert self.offset2(self.d) == datetime(2008, 2, 29) -# -# def testRollback1(self): -# assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) -# -# def testRollback2(self): -# assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) -# -# def testRollforward1(self): -# assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) -# -# def test_roll_date_object(self): -# offset = CBMonthEnd() -# -# dt = date(2012, 9, 15) -# -# result = offset.rollback(dt) -# assert result == datetime(2012, 8, 31) -# -# result = offset.rollforward(dt) -# assert result == datetime(2012, 9, 28) -# -# 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 = [ -# (CBMonthEnd(), datetime(2008, 1, 31), True), -# (CBMonthEnd(), datetime(2008, 1, 1), False), -# ] -# -# @pytest.mark.parametrize("case", on_offset_cases) -# def test_onOffset(self, case): -# offset, d, expected = case -# assert_onOffset(offset, d, expected) -# -# apply_cases = [] # type: _ApplyCases -# apply_cases.append( -# ( -# CBMonthEnd(), -# { -# datetime(2008, 1, 1): datetime(2008, 1, 31), -# datetime(2008, 2, 7): datetime(2008, 2, 29), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# 2 * CBMonthEnd(), -# { -# datetime(2008, 1, 1): datetime(2008, 2, 29), -# datetime(2008, 2, 7): datetime(2008, 3, 31), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -CBMonthEnd(), -# { -# datetime(2008, 1, 1): datetime(2007, 12, 31), -# datetime(2008, 2, 8): datetime(2008, 1, 31), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -2 * CBMonthEnd(), -# { -# datetime(2008, 1, 1): datetime(2007, 11, 30), -# datetime(2008, 2, 9): datetime(2007, 12, 31), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# CBMonthEnd(0), -# { -# datetime(2008, 1, 1): datetime(2008, 1, 31), -# datetime(2008, 2, 7): datetime(2008, 2, 29), -# }, -# ) -# ) -# -# @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 + CBMonthEnd(10) -# assert result == datetime(2013, 7, 31) -# -# result = dt + CDay(100) - CDay(100) -# assert result == dt -# -# off = CBMonthEnd() * 6 -# rs = datetime(2012, 1, 1) - off -# xp = datetime(2011, 7, 29) -# assert rs == xp -# -# st = datetime(2011, 12, 18) -# rs = st + off -# xp = datetime(2012, 5, 31) -# assert rs == xp -# -# def test_holidays(self): -# # Define a TradingDay offset -# holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] -# bm_offset = CBMonthEnd(holidays=holidays) -# dt = datetime(2012, 1, 1) -# assert dt + bm_offset == datetime(2012, 1, 30) -# assert dt + 2 * bm_offset == datetime(2012, 2, 27) -# -# @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") -# def test_datetimeindex(self): -# from pandas.tseries.holiday import USFederalHolidayCalendar -# -# hcal = USFederalHolidayCalendar() -# freq = CBMonthEnd(calendar=hcal) -# -# assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ -# 0 -# ] == datetime(2012, 1, 31) - - -# class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): -# _offset = CBMonthBegin -# -# 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 * CustomBusinessMonthBegins>" -# -# def testCall(self): -# assert self.offset2(self.d) == datetime(2008, 3, 3) -# -# def testRollback1(self): -# assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) -# -# def testRollback2(self): -# assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) -# -# def testRollforward1(self): -# assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) -# -# def test_roll_date_object(self): -# offset = CBMonthBegin() -# -# dt = date(2012, 9, 15) -# -# result = offset.rollback(dt) -# assert result == datetime(2012, 9, 3) -# -# result = offset.rollforward(dt) -# assert result == datetime(2012, 10, 1) -# -# 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 = [ -# (CBMonthBegin(), datetime(2008, 1, 1), True), -# (CBMonthBegin(), datetime(2008, 1, 31), False), -# ] -# -# @pytest.mark.parametrize("case", on_offset_cases) -# def test_onOffset(self, case): -# offset, dt, expected = case -# assert_onOffset(offset, dt, expected) -# -# apply_cases = [] # type: _ApplyCases -# apply_cases.append( -# ( -# CBMonthBegin(), -# { -# datetime(2008, 1, 1): datetime(2008, 2, 1), -# datetime(2008, 2, 7): datetime(2008, 3, 3), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# 2 * CBMonthBegin(), -# { -# datetime(2008, 1, 1): datetime(2008, 3, 3), -# datetime(2008, 2, 7): datetime(2008, 4, 1), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -CBMonthBegin(), -# { -# datetime(2008, 1, 1): datetime(2007, 12, 3), -# datetime(2008, 2, 8): datetime(2008, 2, 1), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# -2 * CBMonthBegin(), -# { -# datetime(2008, 1, 1): datetime(2007, 11, 1), -# datetime(2008, 2, 9): datetime(2008, 1, 1), -# }, -# ) -# ) -# -# apply_cases.append( -# ( -# CBMonthBegin(0), -# { -# datetime(2008, 1, 1): datetime(2008, 1, 1), -# datetime(2008, 1, 7): datetime(2008, 2, 1), -# }, -# ) -# ) -# -# @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 + CBMonthBegin(10) -# assert result == datetime(2013, 8, 1) -# -# result = dt + CDay(100) - CDay(100) -# assert result == dt -# -# off = CBMonthBegin() * 6 -# rs = datetime(2012, 1, 1) - off -# xp = datetime(2011, 7, 1) -# assert rs == xp -# -# st = datetime(2011, 12, 18) -# rs = st + off -# -# xp = datetime(2012, 6, 1) -# assert rs == xp -# -# def test_holidays(self): -# # Define a TradingDay offset -# holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] -# bm_offset = CBMonthBegin(holidays=holidays) -# dt = datetime(2012, 1, 1) -# -# assert dt + bm_offset == datetime(2012, 1, 2) -# assert dt + 2 * bm_offset == datetime(2012, 2, 3) -# -# @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") -# def test_datetimeindex(self): -# hcal = USFederalHolidayCalendar() -# cbmb = CBMonthBegin(calendar=hcal) -# assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ -# 0 -# ] == datetime(2012, 1, 3) +class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): + _offset = CBMonthEnd + + 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 * CustomBusinessMonthEnds>" + + def testCall(self): + assert self.offset2(self.d) == datetime(2008, 2, 29) + + def testRollback1(self): + assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) + + def testRollback2(self): + assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) + + def testRollforward1(self): + assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) + + def test_roll_date_object(self): + offset = CBMonthEnd() + + dt = date(2012, 9, 15) + + result = offset.rollback(dt) + assert result == datetime(2012, 8, 31) + + result = offset.rollforward(dt) + assert result == datetime(2012, 9, 28) + + 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 = [ + (CBMonthEnd(), datetime(2008, 1, 31), True), + (CBMonthEnd(), datetime(2008, 1, 1), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, d, expected = case + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 2, 7): datetime(2008, 2, 29), + }, + ) + ) + + apply_cases.append( + ( + 2 * CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 2, 29), + datetime(2008, 2, 7): datetime(2008, 3, 31), + }, + ) + ) + + apply_cases.append( + ( + -CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2007, 12, 31), + datetime(2008, 2, 8): datetime(2008, 1, 31), + }, + ) + ) + + apply_cases.append( + ( + -2 * CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2007, 11, 30), + datetime(2008, 2, 9): datetime(2007, 12, 31), + }, + ) + ) + + apply_cases.append( + ( + CBMonthEnd(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 2, 7): datetime(2008, 2, 29), + }, + ) + ) + + @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 + CBMonthEnd(10) + assert result == datetime(2013, 7, 31) + + result = dt + CDay(100) - CDay(100) + assert result == dt + + off = CBMonthEnd() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 7, 29) + assert rs == xp + + st = datetime(2011, 12, 18) + rs = st + off + xp = datetime(2012, 5, 31) + assert rs == xp + + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] + bm_offset = CBMonthEnd(holidays=holidays) + dt = datetime(2012, 1, 1) + assert dt + bm_offset == datetime(2012, 1, 30) + assert dt + 2 * bm_offset == datetime(2012, 2, 27) + + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_datetimeindex(self): + from pandas.tseries.holiday import USFederalHolidayCalendar + + hcal = USFederalHolidayCalendar() + freq = CBMonthEnd(calendar=hcal) + + assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ + 0 + ] == datetime(2012, 1, 31) + + +class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): + _offset = CBMonthBegin + + 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 * CustomBusinessMonthBegins>" + + def testCall(self): + assert self.offset2(self.d) == datetime(2008, 3, 3) + + def testRollback1(self): + assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) + + def testRollback2(self): + assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) + + def testRollforward1(self): + assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) + + def test_roll_date_object(self): + offset = CBMonthBegin() + + dt = date(2012, 9, 15) + + result = offset.rollback(dt) + assert result == datetime(2012, 9, 3) + + result = offset.rollforward(dt) + assert result == datetime(2012, 10, 1) + + 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 = [ + (CBMonthBegin(), datetime(2008, 1, 1), True), + (CBMonthBegin(), datetime(2008, 1, 31), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, dt, expected = case + assert_onOffset(offset, dt, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 2, 1), + datetime(2008, 2, 7): datetime(2008, 3, 3), + }, + ) + ) + + apply_cases.append( + ( + 2 * CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 3, 3), + datetime(2008, 2, 7): datetime(2008, 4, 1), + }, + ) + ) + + apply_cases.append( + ( + -CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2007, 12, 3), + datetime(2008, 2, 8): datetime(2008, 2, 1), + }, + ) + ) + + apply_cases.append( + ( + -2 * CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2007, 11, 1), + datetime(2008, 2, 9): datetime(2008, 1, 1), + }, + ) + ) + + apply_cases.append( + ( + CBMonthBegin(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 7): datetime(2008, 2, 1), + }, + ) + ) + + @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 + CBMonthBegin(10) + assert result == datetime(2013, 8, 1) + + result = dt + CDay(100) - CDay(100) + assert result == dt + + off = CBMonthBegin() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 7, 1) + assert rs == xp + + st = datetime(2011, 12, 18) + rs = st + off + + xp = datetime(2012, 6, 1) + assert rs == xp + + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] + bm_offset = CBMonthBegin(holidays=holidays) + dt = datetime(2012, 1, 1) + + assert dt + bm_offset == datetime(2012, 1, 2) + assert dt + 2 * bm_offset == datetime(2012, 2, 3) + + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_datetimeindex(self): + hcal = USFederalHolidayCalendar() + cbmb = CBMonthBegin(calendar=hcal) + assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ + 0 + ] == datetime(2012, 1, 3) class TestOffsetNames: @@ -3097,11 +3096,11 @@ def test_get_offset(): ) -# def test_get_offset_legacy(): -# pairs = [("w@Sat", Week(weekday=5))] -# for name, expected in pairs: -# with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): -# get_offset(name) +def test_get_offset_legacy(): + pairs = [("w@Sat", Week(weekday=5))] + for name, expected in pairs: + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset(name) class TestOffsetAliases: @@ -3211,166 +3210,166 @@ def get_utc_offset_hours(ts): return (o.days * 24 * 3600 + o.seconds) / 3600.0 -# class TestDST: -# """ -# test DateOffset additions over Daylight Savings Time -# """ -# -# # one microsecond before the DST transition -# ts_pre_fallback = "2013-11-03 01:59:59.999999" -# ts_pre_springfwd = "2013-03-10 01:59:59.999999" -# -# # test both basic names and dateutil timezones -# timezone_utc_offsets = { -# "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), -# "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), -# } -# valid_date_offsets_singular = [ -# "weekday", -# "day", -# "hour", -# "minute", -# "second", -# "microsecond", -# ] -# valid_date_offsets_plural = [ -# "weeks", -# "days", -# "hours", -# "minutes", -# "seconds", -# "milliseconds", -# "microseconds", -# ] -# -# def _test_all_offsets(self, n, **kwds): -# valid_offsets = ( -# self.valid_date_offsets_plural -# if n > 1 -# else self.valid_date_offsets_singular -# ) -# -# for name in valid_offsets: -# self._test_offset(offset_name=name, offset_n=n, **kwds) -# -# def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): -# offset = DateOffset(**{offset_name: offset_n}) -# -# t = tstart + offset -# if expected_utc_offset is not None: -# assert get_utc_offset_hours(t) == expected_utc_offset -# -# if offset_name == "weeks": -# # dates should match -# assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() -# # expect the same day of week, hour of day, minute, second, ... -# assert ( -# t.dayofweek == tstart.dayofweek -# and t.hour == tstart.hour -# and t.minute == tstart.minute -# and t.second == tstart.second -# ) -# elif offset_name == "days": -# # dates should match -# assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() -# # expect the same hour of day, minute, second, ... -# assert ( -# t.hour == tstart.hour -# and t.minute == tstart.minute -# and t.second == tstart.second -# ) -# elif offset_name in self.valid_date_offsets_singular: -# # expect the singular offset value to match between tstart and t -# datepart_offset = getattr( -# t, offset_name if offset_name != "weekday" else "dayofweek" -# ) -# assert datepart_offset == offset.kwds[offset_name] -# else: -# # the offset should be the same as if it was done in UTC -# assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") -# -# def _make_timestamp(self, string, hrs_offset, tz): -# if hrs_offset >= 0: -# offset_string = "{hrs:02d}00".format(hrs=hrs_offset) -# else: -# offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) -# return Timestamp(string + offset_string).tz_convert(tz) -# -# def test_springforward_plural(self): -# # test moving from standard to daylight savings -# for tz, utc_offsets in self.timezone_utc_offsets.items(): -# hrs_pre = utc_offsets["utc_offset_standard"] -# hrs_post = utc_offsets["utc_offset_daylight"] -# self._test_all_offsets( -# n=3, -# tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), -# expected_utc_offset=hrs_post, -# ) -# -# def test_fallback_singular(self): -# # in the case of singular offsets, we don't necessarily know which utc -# # offset the new Timestamp will wind up in (the tz for 1 month may be -# # different from 1 second) so we don't specify an expected_utc_offset -# for tz, utc_offsets in self.timezone_utc_offsets.items(): -# hrs_pre = utc_offsets["utc_offset_standard"] -# self._test_all_offsets( -# n=1, -# tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), -# expected_utc_offset=None, -# ) -# -# def test_springforward_singular(self): -# for tz, utc_offsets in self.timezone_utc_offsets.items(): -# hrs_pre = utc_offsets["utc_offset_standard"] -# self._test_all_offsets( -# n=1, -# tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), -# expected_utc_offset=None, -# ) -# -# offset_classes = { -# MonthBegin: ["11/2/2012", "12/1/2012"], -# MonthEnd: ["11/2/2012", "11/30/2012"], -# BMonthBegin: ["11/2/2012", "12/3/2012"], -# BMonthEnd: ["11/2/2012", "11/30/2012"], -# CBMonthBegin: ["11/2/2012", "12/3/2012"], -# CBMonthEnd: ["11/2/2012", "11/30/2012"], -# SemiMonthBegin: ["11/2/2012", "11/15/2012"], -# SemiMonthEnd: ["11/2/2012", "11/15/2012"], -# Week: ["11/2/2012", "11/9/2012"], -# YearBegin: ["11/2/2012", "1/1/2013"], -# YearEnd: ["11/2/2012", "12/31/2012"], -# BYearBegin: ["11/2/2012", "1/1/2013"], -# BYearEnd: ["11/2/2012", "12/31/2012"], -# QuarterBegin: ["11/2/2012", "12/1/2012"], -# QuarterEnd: ["11/2/2012", "12/31/2012"], -# BQuarterBegin: ["11/2/2012", "12/3/2012"], -# BQuarterEnd: ["11/2/2012", "12/31/2012"], -# Day: ["11/4/2012", "11/4/2012 23:00"], -# }.items() -# -# @pytest.mark.parametrize("tup", offset_classes) -# def test_all_offset_classes(self, tup): -# offset, test_values = tup -# -# first = Timestamp(test_values[0], tz="US/Eastern") + offset() -# second = Timestamp(test_values[1], tz="US/Eastern") -# assert first == second +class TestDST: + """ + test DateOffset additions over Daylight Savings Time + """ + + # one microsecond before the DST transition + ts_pre_fallback = "2013-11-03 01:59:59.999999" + ts_pre_springfwd = "2013-03-10 01:59:59.999999" + + # test both basic names and dateutil timezones + timezone_utc_offsets = { + "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), + "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), + } + valid_date_offsets_singular = [ + "weekday", + "day", + "hour", + "minute", + "second", + "microsecond", + ] + valid_date_offsets_plural = [ + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + ] + + def _test_all_offsets(self, n, **kwds): + valid_offsets = ( + self.valid_date_offsets_plural + if n > 1 + else self.valid_date_offsets_singular + ) + + for name in valid_offsets: + self._test_offset(offset_name=name, offset_n=n, **kwds) + + def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): + offset = DateOffset(**{offset_name: offset_n}) + + t = tstart + offset + if expected_utc_offset is not None: + assert get_utc_offset_hours(t) == expected_utc_offset + + if offset_name == "weeks": + # dates should match + assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() + # expect the same day of week, hour of day, minute, second, ... + assert ( + t.dayofweek == tstart.dayofweek + and t.hour == tstart.hour + and t.minute == tstart.minute + and t.second == tstart.second + ) + elif offset_name == "days": + # dates should match + assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() + # expect the same hour of day, minute, second, ... + assert ( + t.hour == tstart.hour + and t.minute == tstart.minute + and t.second == tstart.second + ) + elif offset_name in self.valid_date_offsets_singular: + # expect the singular offset value to match between tstart and t + datepart_offset = getattr( + t, offset_name if offset_name != "weekday" else "dayofweek" + ) + assert datepart_offset == offset.kwds[offset_name] + else: + # the offset should be the same as if it was done in UTC + assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") + + def _make_timestamp(self, string, hrs_offset, tz): + if hrs_offset >= 0: + offset_string = "{hrs:02d}00".format(hrs=hrs_offset) + else: + offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) + return Timestamp(string + offset_string).tz_convert(tz) + + def test_springforward_plural(self): + # test moving from standard to daylight savings + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + hrs_post = utc_offsets["utc_offset_daylight"] + self._test_all_offsets( + n=3, + tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), + expected_utc_offset=hrs_post, + ) + + def test_fallback_singular(self): + # in the case of singular offsets, we don't necessarily know which utc + # offset the new Timestamp will wind up in (the tz for 1 month may be + # different from 1 second) so we don't specify an expected_utc_offset + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + self._test_all_offsets( + n=1, + tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), + expected_utc_offset=None, + ) + + def test_springforward_singular(self): + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + self._test_all_offsets( + n=1, + tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), + expected_utc_offset=None, + ) + + offset_classes = { + MonthBegin: ["11/2/2012", "12/1/2012"], + MonthEnd: ["11/2/2012", "11/30/2012"], + BMonthBegin: ["11/2/2012", "12/3/2012"], + BMonthEnd: ["11/2/2012", "11/30/2012"], + CBMonthBegin: ["11/2/2012", "12/3/2012"], + CBMonthEnd: ["11/2/2012", "11/30/2012"], + SemiMonthBegin: ["11/2/2012", "11/15/2012"], + SemiMonthEnd: ["11/2/2012", "11/15/2012"], + Week: ["11/2/2012", "11/9/2012"], + YearBegin: ["11/2/2012", "1/1/2013"], + YearEnd: ["11/2/2012", "12/31/2012"], + BYearBegin: ["11/2/2012", "1/1/2013"], + BYearEnd: ["11/2/2012", "12/31/2012"], + QuarterBegin: ["11/2/2012", "12/1/2012"], + QuarterEnd: ["11/2/2012", "12/31/2012"], + BQuarterBegin: ["11/2/2012", "12/3/2012"], + BQuarterEnd: ["11/2/2012", "12/31/2012"], + Day: ["11/4/2012", "11/4/2012 23:00"], + }.items() + + @pytest.mark.parametrize("tup", offset_classes) + def test_all_offset_classes(self, tup): + offset, test_values = tup + + first = Timestamp(test_values[0], tz="US/Eastern") + offset() + second = Timestamp(test_values[1], tz="US/Eastern") + assert first == second # --------------------------------------------------------------------- -# def test_get_offset_day_error(): -# # subclass of _BaseOffset must override _day_opt attribute, or we should -# # get a NotImplementedError -# -# with pytest.raises(NotImplementedError): -# DateOffset()._get_offset_day(datetime.now()) +def test_get_offset_day_error(): + # subclass of _BaseOffset must override _day_opt attribute, or we should + # get a NotImplementedError + + with pytest.raises(NotImplementedError): + DateOffset()._get_offset_day(datetime.now()) -def test_valid_default_arguments(offset_types): +def test_valid_default_arguments(business_offset_types): # GH#19142 check that the calling the constructors without passing # any keyword arguments produce valid offsets - cls = offset_types + cls = business_offset_types cls() @@ -3383,11 +3382,11 @@ def test_valid_month_attributes(kwd, month_classes): cls(**{kwd: 3}) -# @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -# def test_valid_relativedelta_kwargs(kwd): -# # Check that all the arguments specified in liboffsets.relativedelta_kwds -# # are in fact valid relativedelta keyword args -# DateOffset(**{kwd: 1}) +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_relativedelta_kwargs(kwd): + # Check that all the arguments specified in liboffsets.relativedelta_kwds + # are in fact valid relativedelta keyword args + DateOffset(**{kwd: 1}) @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) @@ -3399,19 +3398,19 @@ def test_valid_tick_attributes(kwd, tick_classes): cls(**{kwd: 3}) -# def test_validate_n_error(): -# with pytest.raises(TypeError): -# DateOffset(n="Doh!") -# -# with pytest.raises(TypeError): -# MonthBegin(n=timedelta(1)) -# -# with pytest.raises(TypeError): -# BDay(n=np.array([1, 2], dtype=np.int64)) +def test_validate_n_error(): + with pytest.raises(TypeError): + DateOffset(n="Doh!") + + with pytest.raises(TypeError): + MonthBegin(n=timedelta(1)) + + with pytest.raises(TypeError): + BDay(n=np.array([1, 2], dtype=np.int64)) -def test_require_integers(offset_types): - cls = offset_types +def test_require_integers(business_offset_types): + cls = business_offset_types with pytest.raises(ValueError): cls(n=1.5) @@ -3424,60 +3423,60 @@ def test_tick_normalize_raises(tick_classes): cls(n=3, normalize=True) -# def test_weeks_onoffset(): -# # GH#18510 Week with weekday = None, normalize = False should always -# # be onOffset -# offset = Week(n=2, weekday=None) -# ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") -# fast = offset.onOffset(ts) -# slow = (ts + offset) - offset == ts -# assert fast == slow -# -# # negative n -# offset = Week(n=2, weekday=None) -# ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") -# fast = offset.onOffset(ts) -# slow = (ts + offset) - offset == ts -# assert fast == slow - - -# def test_weekofmonth_onoffset(): -# # GH#18864 -# # Make sure that nanoseconds don't trip up onOffset (and with it apply) -# offset = WeekOfMonth(n=2, week=2, weekday=0) -# ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") -# fast = offset.onOffset(ts) -# slow = (ts + offset) - offset == ts -# assert fast == slow -# -# # negative n -# offset = WeekOfMonth(n=-3, week=1, weekday=0) -# ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") -# fast = offset.onOffset(ts) -# slow = (ts + offset) - offset == ts -# assert fast == slow - - -# def test_last_week_of_month_on_offset(): -# # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth -# offset = LastWeekOfMonth(n=4, weekday=6) -# ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") -# slow = (ts + offset) - offset == ts -# fast = offset.onOffset(ts) -# assert fast == slow -# -# # negative n -# offset = LastWeekOfMonth(n=-4, weekday=5) -# ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") -# slow = (ts + offset) - offset == ts -# fast = offset.onOffset(ts) -# assert fast == slow - - -# def test_week_add_invalid(): -# # Week with weekday should raise TypeError and _not_ AttributeError -# # when adding invalid offset -# offset = Week(weekday=1) -# other = Day() -# with pytest.raises(TypeError, match="Cannot add"): -# offset + other +def test_weeks_onoffset(): + # GH#18510 Week with weekday = None, normalize = False should always + # be onOffset + offset = Week(n=2, weekday=None) + ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + # negative n + offset = Week(n=2, weekday=None) + ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + +def test_weekofmonth_onoffset(): + # GH#18864 + # Make sure that nanoseconds don't trip up onOffset (and with it apply) + offset = WeekOfMonth(n=2, week=2, weekday=0) + ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + # negative n + offset = WeekOfMonth(n=-3, week=1, weekday=0) + ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + +def test_last_week_of_month_on_offset(): + # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth + offset = LastWeekOfMonth(n=4, weekday=6) + ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") + slow = (ts + offset) - offset == ts + fast = offset.onOffset(ts) + assert fast == slow + + # negative n + offset = LastWeekOfMonth(n=-4, weekday=5) + ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") + slow = (ts + offset) - offset == ts + fast = offset.onOffset(ts) + assert fast == slow + + +def test_week_add_invalid(): + # Week with weekday should raise TypeError and _not_ AttributeError + # when adding invalid offset + offset = Week(weekday=1) + other = Day() + with pytest.raises(TypeError, match="Cannot add"): + offset + other diff --git a/pandas/tests/tseries/offsets/test_date_offsets.py b/pandas/tests/tseries/offsets/test_date_offsets.py index 8518e916a275b..f3554931fd8fb 100644 --- a/pandas/tests/tseries/offsets/test_date_offsets.py +++ b/pandas/tests/tseries/offsets/test_date_offsets.py @@ -1,4 +1,4 @@ -from datetime import date, datetime, time as dt_time, timedelta +from datetime import datetime, timedelta from typing import Dict, List, Tuple, Type import numpy as np @@ -17,8 +17,6 @@ get_freq_str, ) import pandas._libs.tslibs.offsets as liboffsets -from pandas._libs.tslibs.offsets import ApplyTypeError -import pandas.compat as compat from pandas.compat.numpy import np_datetime64_compat from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range @@ -27,7 +25,6 @@ from pandas.io.pickle import read_pickle from pandas.tseries.frequencies import _offset_map, get_offset -from pandas.tseries.holiday import USFederalHolidayCalendar import pandas.tseries.offsets as offsets from pandas.tseries.offsets import ( BaseOffset, @@ -94,7 +91,6 @@ class Base: ] def _get_offset(self, klass, value=1, normalize=False): - print(klass) # create instance from offset class if klass is LastWeekOfMonth: klass = klass(n=value, weekday=5, normalize=normalize) @@ -227,16 +223,16 @@ class TestCommon(Base): "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), } - def test_immutable(self, offset_types): + def test_immutable(self, date_offset_types): # GH#21341 check that __setattr__ raises - offset = self._get_offset(offset_types) + offset = self._get_offset(date_offset_types) with pytest.raises(AttributeError): offset.normalize = True with pytest.raises(AttributeError): offset.n = 91 - def test_return_type(self, offset_types): - offset = self._get_offset(offset_types) + def test_return_type(self, date_offset_types): + offset = self._get_offset(date_offset_types) # make sure that we are returning a Timestamp result = Timestamp("20080101") + offset @@ -249,8 +245,8 @@ def test_return_type(self, offset_types): assert NaT - offset is NaT assert (-offset).apply(NaT) is NaT - def test_offset_n(self, offset_types): - offset = self._get_offset(offset_types) + def test_offset_n(self, date_offset_types): + offset = self._get_offset(date_offset_types) assert offset.n == 1 neg_offset = offset * -1 @@ -259,17 +255,17 @@ def test_offset_n(self, offset_types): mul_offset = offset * 3 assert mul_offset.n == 3 - def test_offset_timedelta64_arg(self, offset_types): + def test_offset_timedelta64_arg(self, date_offset_types): # check that offset._validate_n raises TypeError on a timedelt64 # object - off = self._get_offset(offset_types) + off = self._get_offset(date_offset_types) td64 = np.timedelta64(4567, "s") with pytest.raises(TypeError, match="argument must be an integer"): type(off)(n=td64, **off.kwds) - def test_offset_mul_ndarray(self, offset_types): - off = self._get_offset(offset_types) + def test_offset_mul_ndarray(self, date_offset_types): + off = self._get_offset(date_offset_types) expected = np.array([[off, off * 2], [off * 3, off * 4]]) @@ -279,8 +275,8 @@ def test_offset_mul_ndarray(self, offset_types): result = off * np.array([[1, 2], [3, 4]]) tm.assert_numpy_array_equal(result, expected) - def test_offset_freqstr(self, offset_types): - offset = self._get_offset(offset_types) + def test_offset_freqstr(self, date_offset_types): + offset = self._get_offset(date_offset_types) freqstr = offset.freqstr if freqstr not in ("", "", "LWOM-SAT"): @@ -361,20 +357,20 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals else: assert result == expected_localize - def test_apply(self, offset_types): + def test_apply(self, date_offset_types): sdt = datetime(2011, 1, 1, 9, 0) ndt = np_datetime64_compat("2011-01-01 09:00Z") for dt in [sdt, ndt]: - expected = self.expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "apply", dt, expected) + expected = self.expecteds[date_offset_types.__name__] + self._check_offsetfunc_works(date_offset_types, "apply", dt, expected) expected = Timestamp(expected.date()) self._check_offsetfunc_works( - offset_types, "apply", dt, expected, normalize=True + date_offset_types, "apply", dt, expected, normalize=True ) - def test_rollforward(self, offset_types): + def test_rollforward(self, date_offset_types): expecteds = self.expecteds.copy() # result will not be changed if the target is on the offset @@ -419,14 +415,14 @@ def test_rollforward(self, offset_types): ndt = np_datetime64_compat("2011-01-01 09:00Z") for dt in [sdt, ndt]: - expected = expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) - expected = norm_expected[offset_types.__name__] + expected = expecteds[date_offset_types.__name__] + self._check_offsetfunc_works(date_offset_types, "rollforward", dt, expected) + expected = norm_expected[date_offset_types.__name__] self._check_offsetfunc_works( - offset_types, "rollforward", dt, expected, normalize=True + date_offset_types, "rollforward", dt, expected, normalize=True ) - def test_rollback(self, offset_types): + def test_rollback(self, date_offset_types): expecteds = { "MonthEnd": Timestamp("2010-12-31 09:00:00"), "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), @@ -479,35 +475,35 @@ def test_rollback(self, offset_types): ndt = np_datetime64_compat("2011-01-01 09:00Z") for dt in [sdt, ndt]: - expected = expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "rollback", dt, expected) + expected = expecteds[date_offset_types.__name__] + self._check_offsetfunc_works(date_offset_types, "rollback", dt, expected) - expected = norm_expected[offset_types.__name__] + expected = norm_expected[date_offset_types.__name__] self._check_offsetfunc_works( - offset_types, "rollback", dt, expected, normalize=True + date_offset_types, "rollback", dt, expected, normalize=True ) - def test_onOffset(self, offset_types): - dt = self.expecteds[offset_types.__name__] - offset_s = self._get_offset(offset_types) + def test_onOffset(self, date_offset_types): + dt = self.expecteds[date_offset_types.__name__] + offset_s = self._get_offset(date_offset_types) assert offset_s.onOffset(dt) # when normalize=True, onOffset checks time is 00:00:00 - if issubclass(offset_types, Tick): + if issubclass(date_offset_types, Tick): # normalize=True disallowed for Tick subclasses GH#21427 return - offset_n = self._get_offset(offset_types, normalize=True) + offset_n = self._get_offset(date_offset_types, normalize=True) assert not offset_n.onOffset(dt) date = datetime(dt.year, dt.month, dt.day) assert offset_n.onOffset(date) - def test_add(self, offset_types, tz_naive_fixture): + def test_add(self, date_offset_types, tz_naive_fixture): tz = tz_naive_fixture dt = datetime(2011, 1, 1, 9, 0) - offset_s = self._get_offset(offset_types) - expected = self.expecteds[offset_types.__name__] + offset_s = self._get_offset(date_offset_types) + expected = self.expecteds[date_offset_types.__name__] result_dt = dt + offset_s result_ts = Timestamp(dt) + offset_s @@ -521,9 +517,9 @@ def test_add(self, offset_types, tz_naive_fixture): assert result == expected_localize # normalize=True, disallowed for Tick subclasses GH#21427 - if issubclass(offset_types, Tick): + if issubclass(date_offset_types, Tick): return - offset_s = self._get_offset(offset_types, normalize=True) + offset_s = self._get_offset(date_offset_types, normalize=True) expected = Timestamp(expected.date()) result_dt = dt + offset_s @@ -1456,7 +1452,7 @@ def test_alias_equality(self): assert k == v.copy() def test_rule_code(self): - lst = ["M", "MS", "BM", "BMS", "D", "B", "H", "T", "S", "L", "U"] + lst = ["M", "MS", "D", "H", "T", "S", "L", "U"] for k in lst: assert k == get_offset(k).rule_code # should be cached - this is kind of an internals test... @@ -1484,14 +1480,14 @@ def test_rule_code(self): "NOV", "DEC", ] - base_lst = ["A", "AS", "BA", "BAS", "Q", "QS", "BQ", "BQS"] + base_lst = ["A", "AS", "Q", "QS"] for base in base_lst: for v in suffix_lst: alias = "-".join([base, v]) assert alias == get_offset(alias).rule_code assert alias == (get_offset(alias) * 5).rule_code - lst = ["M", "D", "B", "H", "T", "S", "L", "U"] + lst = ["M", "D", "H", "T", "S", "L", "U"] for k in lst: code, stride = get_freq_code("3" + k) assert isinstance(code, int) @@ -1510,7 +1506,7 @@ def test_dateoffset_misc(): class TestReprNames: def test_str_for_named_is_name(self): # look at all the amazing combinations! - month_prefixes = ["A", "AS", "BA", "BAS", "Q", "BQ", "BQS", "QS"] + month_prefixes = ["A", "AS", "Q", "QS"] names = [ prefix + "-" + month for prefix in month_prefixes @@ -1692,17 +1688,17 @@ def test_get_offset_day_error(): DateOffset()._get_offset_day(datetime.now()) -def test_valid_default_arguments(offset_types): +def test_valid_default_arguments(date_offset_types): # GH#19142 check that the calling the constructors without passing # any keyword arguments produce valid offsets - cls = offset_types + cls = date_offset_types cls() @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -def test_valid_month_attributes(kwd, month_classes): +def test_valid_month_attributes(kwd, date_month_classes): # GH#18226 - cls = month_classes + cls = date_month_classes # check that we cannot create e.g. MonthEnd(weeks=3) with pytest.raises(TypeError): cls(**{kwd: 3}) @@ -1732,8 +1728,8 @@ def test_validate_n_error(): MonthBegin(n=timedelta(1)) -def test_require_integers(offset_types): - cls = offset_types +def test_require_integers(date_offset_types): + cls = date_offset_types with pytest.raises(ValueError): cls(n=1.5) From 3df390cc6223fdf05c200f956295eb651826b923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Tue, 10 Dec 2019 18:41:40 +0100 Subject: [PATCH 05/12] test_business_date refactored --- pandas/tests/tseries/offsets/conftest.py | 72 ++-- .../tseries/offsets/test_business_offsets.py | 376 +----------------- 2 files changed, 46 insertions(+), 402 deletions(-) diff --git a/pandas/tests/tseries/offsets/conftest.py b/pandas/tests/tseries/offsets/conftest.py index b93a526e4c98e..c9fb60b01e109 100644 --- a/pandas/tests/tseries/offsets/conftest.py +++ b/pandas/tests/tseries/offsets/conftest.py @@ -25,24 +25,24 @@ "DateOffset", } -# BUSINESS_OFFSETS = { -# "BusinessDay", -# "BDay", -# "CustomBusinessDay", -# "CBMonthBegin", -# "CBMonthEnd", -# "BMonthBegin", -# "BMonthEnd", -# "BusinessHour", -# "CustomBusinessHour", -# "BYearBegin", -# "BYearEnd", -# "CDay", -# "BQuarterBegin", -# "BQuarterEnd", -# "FY5253Quarter", -# "FY5253", -# } +BUSINESS_OFFSETS = { + "BusinessDay", + "BDay", + "CustomBusinessDay", + "CBMonthBegin", + "CBMonthEnd", + "BMonthBegin", + "BMonthEnd", + "BusinessHour", + "CustomBusinessHour", + "BYearBegin", + "BYearEnd", + "CDay", + "BQuarterBegin", + "BQuarterEnd", + "FY5253Quarter", + "FY5253", +} @pytest.fixture(params=[getattr(offsets, o) for o in DATE_OFFSETS]) @@ -53,12 +53,12 @@ def date_offset_types(request): return request.param -# @pytest.fixture(params=[getattr(offsets, o) for o in BUSINESS_OFFSETS]) -# def business_offset_types(request): -# """ -# Fixture for all the datetime offsets available for a time series. -# """ -# return request.param +@pytest.fixture(params=[getattr(offsets, o) for o in BUSINESS_OFFSETS]) +def business_offset_types(request): + """ + Fixture for all the datetime offsets available for a time series. + """ + return request.param @pytest.fixture( @@ -75,15 +75,15 @@ def date_month_classes(request): return request.param -# @pytest.fixture( -# params=[ -# getattr(offsets, o) -# for o in BUSINESS_OFFSETS -# if issubclass(getattr(offsets, o), offsets.MonthOffset) and o != "MonthOffset" -# ] -# ) -# def business_month_classes(request): -# """ -# Fixture for month based datetime offsets available for a time series. -# """ -# return request.param \ No newline at end of file +@pytest.fixture( + params=[ + getattr(offsets, o) + for o in BUSINESS_OFFSETS + if issubclass(getattr(offsets, o), offsets.MonthOffset) and o != "MonthOffset" + ] +) +def business_month_classes(request): + """ + Fixture for month based datetime offsets available for a time series. + """ + return request.param \ No newline at end of file diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index 4da423f8edfd8..6dfbd8a20956f 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -43,7 +43,10 @@ CBMonthEnd, CDay, CustomBusinessHour, - FY5253Quarter + FY5253Quarter, + DateOffset, + Nano, + Tick ) from .common import assert_offset_equal, assert_onOffset @@ -60,17 +63,6 @@ class WeekDay: SUN = 6 -#### -# Misc function tests -#### - - -def test_to_M8(): - valb = datetime(2007, 10, 1) - valu = _to_M8(valb) - assert isinstance(valu, np.datetime64) - - ##### # BusinessOffset Tests ##### @@ -109,12 +101,6 @@ def _get_offset(self, klass, value=1, normalize=False): variation="last", normalize=normalize, ) - elif klass is LastWeekOfMonth: - klass = klass(n=value, weekday=5, normalize=normalize) - elif klass is WeekOfMonth: - klass = klass(n=value, week=1, weekday=5, normalize=normalize) - elif klass is Week: - klass = klass(n=value, weekday=5, normalize=normalize) elif klass is DateOffset: klass = klass(days=value, normalize=normalize) else: @@ -223,40 +209,20 @@ class TestCommon(Base): # are applied to 2011/01/01 09:00 (Saturday) # used for .apply and .rollforward expecteds = { - "Day": Timestamp("2011-01-02 09:00:00"), - "DateOffset": Timestamp("2011-01-02 09:00:00"), "BusinessDay": Timestamp("2011-01-03 09:00:00"), "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), - "MonthBegin": Timestamp("2011-02-01 09:00:00"), "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), - "MonthEnd": Timestamp("2011-01-31 09:00:00"), - "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), - "YearBegin": Timestamp("2012-01-01 09:00:00"), "BYearBegin": Timestamp("2011-01-03 09:00:00"), - "YearEnd": Timestamp("2011-12-31 09:00:00"), "BYearEnd": Timestamp("2011-12-30 09:00:00"), - "QuarterBegin": Timestamp("2011-03-01 09:00:00"), "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), - "QuarterEnd": Timestamp("2011-03-31 09:00:00"), "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), "BusinessHour": Timestamp("2011-01-03 10:00:00"), "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), - "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), - "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), "FY5253": Timestamp("2011-01-25 09:00:00"), - "Week": Timestamp("2011-01-08 09:00:00"), - "Easter": Timestamp("2011-04-24 09:00:00"), - "Hour": Timestamp("2011-01-01 10:00:00"), - "Minute": Timestamp("2011-01-01 09:01:00"), - "Second": Timestamp("2011-01-01 09:00:01"), - "Milli": Timestamp("2011-01-01 09:00:00.001000"), - "Micro": Timestamp("2011-01-01 09:00:00.000001"), - "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), } def test_immutable(self, business_offset_types): @@ -409,24 +375,6 @@ def test_apply(self, business_offset_types): def test_rollforward(self, business_offset_types): expecteds = self.expecteds.copy() - # result will not be changed if the target is on the offset - no_changes = [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ] - for n in no_changes: - expecteds[n] = Timestamp("2011/01/01 09:00") - expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") @@ -435,21 +383,6 @@ def test_rollforward(self, business_offset_types): for k in norm_expected: norm_expected[k] = Timestamp(norm_expected[k].date()) - normalized = { - "Day": Timestamp("2011-01-02 00:00:00"), - "DateOffset": Timestamp("2011-01-02 00:00:00"), - "MonthBegin": Timestamp("2011-02-01 00:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), - "YearBegin": Timestamp("2012-01-01 00:00:00"), - "Week": Timestamp("2011-01-08 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - sdt = datetime(2011, 1, 1, 9, 0) ndt = np_datetime64_compat("2011-01-01 09:00Z") @@ -468,62 +401,22 @@ def test_rollback(self, business_offset_types): "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), - "MonthEnd": Timestamp("2010-12-31 09:00:00"), - "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), "BYearBegin": Timestamp("2010-01-01 09:00:00"), - "YearEnd": Timestamp("2010-12-31 09:00:00"), "BYearEnd": Timestamp("2010-12-31 09:00:00"), - "QuarterBegin": Timestamp("2010-12-01 09:00:00"), "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), - "QuarterEnd": Timestamp("2010-12-31 09:00:00"), "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), "BusinessHour": Timestamp("2010-12-31 17:00:00"), "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), - "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), - "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), "FY5253": Timestamp("2010-01-26 09:00:00"), - "Easter": Timestamp("2010-04-04 09:00:00"), } - # result will not be changed if the target is on the offset - for n in [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ]: - expecteds[n] = Timestamp("2011/01/01 09:00") - # but be changed when normalize=True norm_expected = expecteds.copy() for k in norm_expected: norm_expected[k] = Timestamp(norm_expected[k].date()) - normalized = { - "Day": Timestamp("2010-12-31 00:00:00"), - "DateOffset": Timestamp("2010-12-31 00:00:00"), - "MonthBegin": Timestamp("2010-12-01 00:00:00"), - "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), - "YearBegin": Timestamp("2010-01-01 00:00:00"), - "Week": Timestamp("2010-12-25 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - sdt = datetime(2011, 1, 1, 9, 0) ndt = np_datetime64_compat("2011-01-01 09:00Z") @@ -590,21 +483,6 @@ def test_add(self, business_offset_types, tz_naive_fixture): assert isinstance(result, Timestamp) assert result == expected_localize - def test_pickle_v0_15_2(self, datapath): - offsets = { - "DateOffset": DateOffset(years=1), - "MonthBegin": MonthBegin(1), - "Day": Day(1), - "YearBegin": YearBegin(1), - "Week": Week(1), - } - - pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") - # This code was executed once on v0.15.2 to generate the pickle: - # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) - # - tm.assert_dict_equal(offsets, read_pickle(pickle_path)) - class TestBusinessDay(Base): _offset = BDay @@ -3096,13 +2974,6 @@ def test_get_offset(): ) -def test_get_offset_legacy(): - pairs = [("w@Sat", Week(weekday=5))] - for name, expected in pairs: - with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): - get_offset(name) - - class TestOffsetAliases: def setup_method(self, method): _offset_map.clear() @@ -3114,7 +2985,7 @@ def test_alias_equality(self): assert k == v.copy() def test_rule_code(self): - lst = ["M", "MS", "BM", "BMS", "D", "B", "H", "T", "S", "L", "U"] + lst = ["BM", "BMS", "B"] for k in lst: assert k == get_offset(k).rule_code # should be cached - this is kind of an internals test... @@ -3142,14 +3013,14 @@ def test_rule_code(self): "NOV", "DEC", ] - base_lst = ["A", "AS", "BA", "BAS", "Q", "QS", "BQ", "BQS"] + base_lst = ["BA", "BAS", "BQ", "BQS"] for base in base_lst: for v in suffix_lst: alias = "-".join([base, v]) assert alias == get_offset(alias).rule_code assert alias == (get_offset(alias) * 5).rule_code - lst = ["M", "D", "B", "H", "T", "S", "L", "U"] + lst = ["B",] for k in lst: code, stride = get_freq_code("3" + k) assert isinstance(code, int) @@ -3157,14 +3028,6 @@ def test_rule_code(self): assert k == get_freq_str(code) -def test_dateoffset_misc(): - oset = offsets.DateOffset(months=2, days=4) - # it works - oset.freqstr - - assert not offsets.DateOffset(months=2) == 2 - - def test_freq_offsets(): off = BDay(1, offset=timedelta(0, 1800)) assert off.freqstr == "B+30Min" @@ -3176,7 +3039,7 @@ def test_freq_offsets(): class TestReprNames: def test_str_for_named_is_name(self): # look at all the amazing combinations! - month_prefixes = ["A", "AS", "BA", "BAS", "Q", "BQ", "BQS", "QS"] + month_prefixes = ["BA", "BAS", "BQ", "BQS"] names = [ prefix + "-" + month for prefix in month_prefixes @@ -3215,137 +3078,15 @@ class TestDST: test DateOffset additions over Daylight Savings Time """ - # one microsecond before the DST transition - ts_pre_fallback = "2013-11-03 01:59:59.999999" - ts_pre_springfwd = "2013-03-10 01:59:59.999999" - - # test both basic names and dateutil timezones - timezone_utc_offsets = { - "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), - "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), - } - valid_date_offsets_singular = [ - "weekday", - "day", - "hour", - "minute", - "second", - "microsecond", - ] - valid_date_offsets_plural = [ - "weeks", - "days", - "hours", - "minutes", - "seconds", - "milliseconds", - "microseconds", - ] - - def _test_all_offsets(self, n, **kwds): - valid_offsets = ( - self.valid_date_offsets_plural - if n > 1 - else self.valid_date_offsets_singular - ) - - for name in valid_offsets: - self._test_offset(offset_name=name, offset_n=n, **kwds) - - def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): - offset = DateOffset(**{offset_name: offset_n}) - - t = tstart + offset - if expected_utc_offset is not None: - assert get_utc_offset_hours(t) == expected_utc_offset - - if offset_name == "weeks": - # dates should match - assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() - # expect the same day of week, hour of day, minute, second, ... - assert ( - t.dayofweek == tstart.dayofweek - and t.hour == tstart.hour - and t.minute == tstart.minute - and t.second == tstart.second - ) - elif offset_name == "days": - # dates should match - assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() - # expect the same hour of day, minute, second, ... - assert ( - t.hour == tstart.hour - and t.minute == tstart.minute - and t.second == tstart.second - ) - elif offset_name in self.valid_date_offsets_singular: - # expect the singular offset value to match between tstart and t - datepart_offset = getattr( - t, offset_name if offset_name != "weekday" else "dayofweek" - ) - assert datepart_offset == offset.kwds[offset_name] - else: - # the offset should be the same as if it was done in UTC - assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") - - def _make_timestamp(self, string, hrs_offset, tz): - if hrs_offset >= 0: - offset_string = "{hrs:02d}00".format(hrs=hrs_offset) - else: - offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) - return Timestamp(string + offset_string).tz_convert(tz) - - def test_springforward_plural(self): - # test moving from standard to daylight savings - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - hrs_post = utc_offsets["utc_offset_daylight"] - self._test_all_offsets( - n=3, - tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), - expected_utc_offset=hrs_post, - ) - - def test_fallback_singular(self): - # in the case of singular offsets, we don't necessarily know which utc - # offset the new Timestamp will wind up in (the tz for 1 month may be - # different from 1 second) so we don't specify an expected_utc_offset - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - self._test_all_offsets( - n=1, - tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), - expected_utc_offset=None, - ) - - def test_springforward_singular(self): - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - self._test_all_offsets( - n=1, - tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), - expected_utc_offset=None, - ) - offset_classes = { - MonthBegin: ["11/2/2012", "12/1/2012"], - MonthEnd: ["11/2/2012", "11/30/2012"], BMonthBegin: ["11/2/2012", "12/3/2012"], BMonthEnd: ["11/2/2012", "11/30/2012"], CBMonthBegin: ["11/2/2012", "12/3/2012"], CBMonthEnd: ["11/2/2012", "11/30/2012"], - SemiMonthBegin: ["11/2/2012", "11/15/2012"], - SemiMonthEnd: ["11/2/2012", "11/15/2012"], - Week: ["11/2/2012", "11/9/2012"], - YearBegin: ["11/2/2012", "1/1/2013"], - YearEnd: ["11/2/2012", "12/31/2012"], BYearBegin: ["11/2/2012", "1/1/2013"], BYearEnd: ["11/2/2012", "12/31/2012"], - QuarterBegin: ["11/2/2012", "12/1/2012"], - QuarterEnd: ["11/2/2012", "12/31/2012"], BQuarterBegin: ["11/2/2012", "12/3/2012"], BQuarterEnd: ["11/2/2012", "12/31/2012"], - Day: ["11/4/2012", "11/4/2012 23:00"], }.items() @pytest.mark.parametrize("tup", offset_classes) @@ -3358,14 +3099,6 @@ def test_all_offset_classes(self, tup): # --------------------------------------------------------------------- -def test_get_offset_day_error(): - # subclass of _BaseOffset must override _day_opt attribute, or we should - # get a NotImplementedError - - with pytest.raises(NotImplementedError): - DateOffset()._get_offset_day(datetime.now()) - - def test_valid_default_arguments(business_offset_types): # GH#19142 check that the calling the constructors without passing # any keyword arguments produce valid offsets @@ -3374,37 +3107,15 @@ def test_valid_default_arguments(business_offset_types): @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -def test_valid_month_attributes(kwd, month_classes): +def test_valid_month_attributes(kwd, business_month_classes): # GH#18226 - cls = month_classes + cls = business_month_classes # check that we cannot create e.g. MonthEnd(weeks=3) with pytest.raises(TypeError): cls(**{kwd: 3}) -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -def test_valid_relativedelta_kwargs(kwd): - # Check that all the arguments specified in liboffsets.relativedelta_kwds - # are in fact valid relativedelta keyword args - DateOffset(**{kwd: 1}) - - -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -def test_valid_tick_attributes(kwd, tick_classes): - # GH#18226 - cls = tick_classes - # check that we cannot create e.g. Hour(weeks=3) - with pytest.raises(TypeError): - cls(**{kwd: 3}) - - def test_validate_n_error(): - with pytest.raises(TypeError): - DateOffset(n="Doh!") - - with pytest.raises(TypeError): - MonthBegin(n=timedelta(1)) - with pytest.raises(TypeError): BDay(n=np.array([1, 2], dtype=np.int64)) @@ -3413,70 +3124,3 @@ def test_require_integers(business_offset_types): cls = business_offset_types with pytest.raises(ValueError): cls(n=1.5) - - -def test_tick_normalize_raises(tick_classes): - # check that trying to create a Tick object with normalize=True raises - # GH#21427 - cls = tick_classes - with pytest.raises(ValueError): - cls(n=3, normalize=True) - - -def test_weeks_onoffset(): - # GH#18510 Week with weekday = None, normalize = False should always - # be onOffset - offset = Week(n=2, weekday=None) - ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - # negative n - offset = Week(n=2, weekday=None) - ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - -def test_weekofmonth_onoffset(): - # GH#18864 - # Make sure that nanoseconds don't trip up onOffset (and with it apply) - offset = WeekOfMonth(n=2, week=2, weekday=0) - ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - # negative n - offset = WeekOfMonth(n=-3, week=1, weekday=0) - ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - -def test_last_week_of_month_on_offset(): - # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth - offset = LastWeekOfMonth(n=4, weekday=6) - ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") - slow = (ts + offset) - offset == ts - fast = offset.onOffset(ts) - assert fast == slow - - # negative n - offset = LastWeekOfMonth(n=-4, weekday=5) - ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") - slow = (ts + offset) - offset == ts - fast = offset.onOffset(ts) - assert fast == slow - - -def test_week_add_invalid(): - # Week with weekday should raise TypeError and _not_ AttributeError - # when adding invalid offset - offset = Week(weekday=1) - other = Day() - with pytest.raises(TypeError, match="Cannot add"): - offset + other From 1ab35a37dbab6edbb1ca38a8f08fece048c936af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Tue, 10 Dec 2019 23:13:40 +0100 Subject: [PATCH 06/12] Working on rebasing --- pandas/tests/tseries/offsets/test_offsets.py | 1801 ++++++++++++++++++ 1 file changed, 1801 insertions(+) create mode 100644 pandas/tests/tseries/offsets/test_offsets.py diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_offsets.py new file mode 100644 index 0000000000000..f3554931fd8fb --- /dev/null +++ b/pandas/tests/tseries/offsets/test_offsets.py @@ -0,0 +1,1801 @@ +from datetime import datetime, timedelta +from typing import Dict, List, Tuple, Type + +import numpy as np +import pytest + +from pandas._libs.tslibs import ( + NaT, + OutOfBoundsDatetime, + Timestamp, + conversion, + timezones, +) +from pandas._libs.tslibs.frequencies import ( + INVALID_FREQ_ERR_MSG, + get_freq_code, + get_freq_str, +) +import pandas._libs.tslibs.offsets as liboffsets +from pandas.compat.numpy import np_datetime64_compat + +from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range +from pandas.core.series import Series +import pandas.util.testing as tm + +from pandas.io.pickle import read_pickle +from pandas.tseries.frequencies import _offset_map, get_offset +import pandas.tseries.offsets as offsets +from pandas.tseries.offsets import ( + BaseOffset, + DateOffset, + Day, + Easter, + LastWeekOfMonth, + MonthBegin, + MonthEnd, + Nano, + QuarterBegin, + QuarterEnd, + SemiMonthBegin, + SemiMonthEnd, + Tick, + Week, + WeekOfMonth, + YearBegin, + YearEnd, +) + +from .common import assert_offset_equal, assert_onOffset + + +class WeekDay: + # TODO: Remove: This is not used outside of tests + MON = 0 + TUE = 1 + WED = 2 + THU = 3 + FRI = 4 + SAT = 5 + SUN = 6 + + +#### +# Misc function tests +#### + + +def test_to_M8(): + valb = datetime(2007, 10, 1) + valu = _to_M8(valb) + assert isinstance(valu, np.datetime64) + + +##### +# DateOffset Tests +##### +_ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]] + + +class Base: + _offset = None # type: Type[DateOffset] + d = Timestamp(datetime(2008, 1, 2)) + + timezones = [ + None, + "UTC", + "Asia/Tokyo", + "US/Eastern", + "dateutil/Asia/Tokyo", + "dateutil/US/Pacific", + ] + + def _get_offset(self, klass, value=1, normalize=False): + # create instance from offset class + if klass is LastWeekOfMonth: + klass = klass(n=value, weekday=5, normalize=normalize) + elif klass is WeekOfMonth: + klass = klass(n=value, week=1, weekday=5, normalize=normalize) + elif klass is Week: + klass = klass(n=value, weekday=5, normalize=normalize) + elif klass is DateOffset: + klass = klass(days=value, normalize=normalize) + else: + klass = klass(value, normalize=normalize) + return klass + + def test_apply_out_of_range(self, tz_naive_fixture): + tz = tz_naive_fixture + if self._offset is None: + return + + # try to create an out-of-bounds result timestamp; if we can't create + # the offset skip + try: + offset = self._get_offset(self._offset, value=10000) + + result = Timestamp("20080101") + offset + assert isinstance(result, datetime) + assert result.tzinfo is None + + # Check tz is preserved + t = Timestamp("20080101", tz=tz) + result = t + offset + assert isinstance(result, datetime) + assert t.tzinfo == result.tzinfo + + except OutOfBoundsDatetime: + pass + except (ValueError, KeyError): + # we are creating an invalid offset + # so ignore + pass + + def test_offsets_compare_equal(self): + # root cause of GH#456: __ne__ was not implemented + if self._offset is None: + return + offset1 = self._offset() + offset2 = self._offset() + assert not offset1 != offset2 + assert offset1 == offset2 + + def test_rsub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert self.d - self.offset2 == (-self.offset2).apply(self.d) + + def test_radd(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + assert self.d + self.offset2 == self.offset2 + self.d + + def test_sub(self): + if self._offset is None or not hasattr(self, "offset2"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset2 attr + return + off = self.offset2 + msg = "Cannot subtract datetime from offset" + with pytest.raises(TypeError, match=msg): + off - self.d + + assert 2 * off - off == off + assert self.d - self.offset2 == self.d + self._offset(-2) + assert self.d - self.offset2 == self.d - (2 * off - off) + + def testMult1(self): + if self._offset is None or not hasattr(self, "offset1"): + # i.e. skip for TestCommon and YQM subclasses that do not have + # offset1 attr + return + assert self.d + 10 * self.offset1 == self.d + self._offset(10) + assert self.d + 5 * self.offset1 == self.d + self._offset(5) + + def testMult2(self): + if self._offset is None: + return + assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) + assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) + + def test_compare_str(self): + # GH#23524 + # comparing to strings that cannot be cast to DateOffsets should + # not raise for __eq__ or __ne__ + if self._offset is None: + return + off = self._get_offset(self._offset) + + assert not off == "infer" + assert off != "foo" + # Note: inequalities are only implemented for Tick subclasses; + # tests for this are in test_ticks + + +class TestCommon(Base): + # exected value created by Base._get_offset + # are applied to 2011/01/01 09:00 (Saturday) + # used for .apply and .rollforward + expecteds = { + "Day": Timestamp("2011-01-02 09:00:00"), + "DateOffset": Timestamp("2011-01-02 09:00:00"), + "MonthBegin": Timestamp("2011-02-01 09:00:00"), + "MonthEnd": Timestamp("2011-01-31 09:00:00"), + "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), + "YearBegin": Timestamp("2012-01-01 09:00:00"), + "YearEnd": Timestamp("2011-12-31 09:00:00"), + "QuarterBegin": Timestamp("2011-03-01 09:00:00"), + "QuarterEnd": Timestamp("2011-03-31 09:00:00"), + "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), + "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), + "Week": Timestamp("2011-01-08 09:00:00"), + "Easter": Timestamp("2011-04-24 09:00:00"), + "Hour": Timestamp("2011-01-01 10:00:00"), + "Minute": Timestamp("2011-01-01 09:01:00"), + "Second": Timestamp("2011-01-01 09:00:01"), + "Milli": Timestamp("2011-01-01 09:00:00.001000"), + "Micro": Timestamp("2011-01-01 09:00:00.000001"), + "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), + } + + def test_immutable(self, date_offset_types): + # GH#21341 check that __setattr__ raises + offset = self._get_offset(date_offset_types) + with pytest.raises(AttributeError): + offset.normalize = True + with pytest.raises(AttributeError): + offset.n = 91 + + def test_return_type(self, date_offset_types): + offset = self._get_offset(date_offset_types) + + # make sure that we are returning a Timestamp + result = Timestamp("20080101") + offset + assert isinstance(result, Timestamp) + + # make sure that we are returning NaT + assert NaT + offset is NaT + assert offset + NaT is NaT + + assert NaT - offset is NaT + assert (-offset).apply(NaT) is NaT + + def test_offset_n(self, date_offset_types): + offset = self._get_offset(date_offset_types) + assert offset.n == 1 + + neg_offset = offset * -1 + assert neg_offset.n == -1 + + mul_offset = offset * 3 + assert mul_offset.n == 3 + + def test_offset_timedelta64_arg(self, date_offset_types): + # check that offset._validate_n raises TypeError on a timedelt64 + # object + off = self._get_offset(date_offset_types) + + td64 = np.timedelta64(4567, "s") + with pytest.raises(TypeError, match="argument must be an integer"): + type(off)(n=td64, **off.kwds) + + def test_offset_mul_ndarray(self, date_offset_types): + off = self._get_offset(date_offset_types) + + expected = np.array([[off, off * 2], [off * 3, off * 4]]) + + result = np.array([[1, 2], [3, 4]]) * off + tm.assert_numpy_array_equal(result, expected) + + result = off * np.array([[1, 2], [3, 4]]) + tm.assert_numpy_array_equal(result, expected) + + def test_offset_freqstr(self, date_offset_types): + offset = self._get_offset(date_offset_types) + + freqstr = offset.freqstr + if freqstr not in ("", "", "LWOM-SAT"): + code = get_offset(freqstr) + assert offset.rule_code == code + + def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): + + if normalize and issubclass(offset, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + + offset_s = self._get_offset(offset, normalize=normalize) + func = getattr(offset_s, funcname) + + result = func(dt) + assert isinstance(result, Timestamp) + assert result == expected + + result = func(Timestamp(dt)) + assert isinstance(result, Timestamp) + assert result == expected + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected + Nano(5) + else: + assert result == expected + + if isinstance(dt, np.datetime64): + # test tz when input is datetime or Timestamp + return + + for tz in self.timezones: + expected_localize = expected.tz_localize(tz) + tz_obj = timezones.maybe_get_tz(tz) + dt_tz = conversion.localize_pydatetime(dt, tz_obj) + + result = func(dt_tz) + assert isinstance(result, Timestamp) + assert result == expected_localize + + result = func(Timestamp(dt, tz=tz)) + assert isinstance(result, Timestamp) + assert result == expected_localize + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt, tz=tz) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected_localize + Nano(5) + else: + assert result == expected_localize + + def test_apply(self, date_offset_types): + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = self.expecteds[date_offset_types.__name__] + self._check_offsetfunc_works(date_offset_types, "apply", dt, expected) + + expected = Timestamp(expected.date()) + self._check_offsetfunc_works( + date_offset_types, "apply", dt, expected, normalize=True + ) + + def test_rollforward(self, date_offset_types): + expecteds = self.expecteds.copy() + + # result will not be changed if the target is on the offset + no_changes = [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ] + for n in no_changes: + expecteds[n] = Timestamp("2011/01/01 09:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2011-01-02 00:00:00"), + "DateOffset": Timestamp("2011-01-02 00:00:00"), + "MonthBegin": Timestamp("2011-02-01 00:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), + "YearBegin": Timestamp("2012-01-01 00:00:00"), + "Week": Timestamp("2011-01-08 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[date_offset_types.__name__] + self._check_offsetfunc_works(date_offset_types, "rollforward", dt, expected) + expected = norm_expected[date_offset_types.__name__] + self._check_offsetfunc_works( + date_offset_types, "rollforward", dt, expected, normalize=True + ) + + def test_rollback(self, date_offset_types): + expecteds = { + "MonthEnd": Timestamp("2010-12-31 09:00:00"), + "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), + "YearEnd": Timestamp("2010-12-31 09:00:00"), + "QuarterBegin": Timestamp("2010-12-01 09:00:00"), + "QuarterEnd": Timestamp("2010-12-31 09:00:00"), + "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), + "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), + "Easter": Timestamp("2010-04-04 09:00:00"), + } + + # result will not be changed if the target is on the offset + for n in [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ]: + expecteds[n] = Timestamp("2011/01/01 09:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2010-12-31 00:00:00"), + "DateOffset": Timestamp("2010-12-31 00:00:00"), + "MonthBegin": Timestamp("2010-12-01 00:00:00"), + "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), + "YearBegin": Timestamp("2010-01-01 00:00:00"), + "Week": Timestamp("2010-12-25 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[date_offset_types.__name__] + self._check_offsetfunc_works(date_offset_types, "rollback", dt, expected) + + expected = norm_expected[date_offset_types.__name__] + self._check_offsetfunc_works( + date_offset_types, "rollback", dt, expected, normalize=True + ) + + def test_onOffset(self, date_offset_types): + dt = self.expecteds[date_offset_types.__name__] + offset_s = self._get_offset(date_offset_types) + assert offset_s.onOffset(dt) + + # when normalize=True, onOffset checks time is 00:00:00 + if issubclass(date_offset_types, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + offset_n = self._get_offset(date_offset_types, normalize=True) + assert not offset_n.onOffset(dt) + + date = datetime(dt.year, dt.month, dt.day) + assert offset_n.onOffset(date) + + def test_add(self, date_offset_types, tz_naive_fixture): + tz = tz_naive_fixture + dt = datetime(2011, 1, 1, 9, 0) + + offset_s = self._get_offset(date_offset_types) + expected = self.expecteds[date_offset_types.__name__] + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + # normalize=True, disallowed for Tick subclasses GH#21427 + if issubclass(date_offset_types, Tick): + return + offset_s = self._get_offset(date_offset_types, normalize=True) + expected = Timestamp(expected.date()) + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + def test_pickle_v0_15_2(self, datapath): + offsets = { + "DateOffset": DateOffset(years=1), + "MonthBegin": MonthBegin(1), + "Day": Day(1), + "YearBegin": YearBegin(1), + "Week": Week(1), + } + + pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") + # This code was executed once on v0.15.2 to generate the pickle: + # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) + # + tm.assert_dict_equal(offsets, read_pickle(pickle_path)) + + +class TestDateOffset(Base): + def setup_method(self, method): + self.d = Timestamp(datetime(2008, 1, 2)) + _offset_map.clear() + + def test_repr(self): + repr(DateOffset()) + repr(DateOffset(2)) + repr(2 * DateOffset()) + repr(2 * DateOffset(months=2)) + + def test_mul(self): + assert DateOffset(2) == 2 * DateOffset(1) + assert DateOffset(2) == DateOffset(1) * 2 + + def test_constructor(self): + + assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2) + assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2) + + assert (self.d + DateOffset(2)) == datetime(2008, 1, 4) + + assert not DateOffset(2).isAnchored() + assert DateOffset(1).isAnchored() + + d = datetime(2008, 1, 31) + assert (d + DateOffset(months=1)) == datetime(2008, 2, 29) + + def test_copy(self): + assert DateOffset(months=2).copy() == DateOffset(months=2) + + def test_eq(self): + offset1 = DateOffset(days=1) + offset2 = DateOffset(days=365) + + assert offset1 != offset2 + + +class TestWeek(Base): + _offset = Week + d = Timestamp(datetime(2008, 1, 2)) + offset1 = _offset() + offset2 = _offset(2) + + def test_repr(self): + assert repr(Week(weekday=0)) == "" + assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>" + assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>" + + def test_corner(self): + with pytest.raises(ValueError): + Week(weekday=7) + + with pytest.raises(ValueError, match="Day must be"): + Week(weekday=-1) + + def test_isAnchored(self): + assert Week(weekday=0).isAnchored() + assert not Week().isAnchored() + assert not Week(2, weekday=2).isAnchored() + assert not Week(2).isAnchored() + + offset_cases = [] + # not business week + offset_cases.append( + ( + Week(), + { + datetime(2008, 1, 1): datetime(2008, 1, 8), + datetime(2008, 1, 4): datetime(2008, 1, 11), + datetime(2008, 1, 5): datetime(2008, 1, 12), + datetime(2008, 1, 6): datetime(2008, 1, 13), + datetime(2008, 1, 7): datetime(2008, 1, 14), + }, + ) + ) + + # Mon + offset_cases.append( + ( + Week(weekday=0), + { + datetime(2007, 12, 31): datetime(2008, 1, 7), + 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, 14), + }, + ) + ) + + # n=0 -> roll forward. Mon + offset_cases.append( + ( + Week(0, weekday=0), + { + datetime(2007, 12, 31): datetime(2007, 12, 31), + 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, 7), + }, + ) + ) + + # n=0 -> roll forward. Mon + offset_cases.append( + ( + Week(-2, weekday=1), + { + datetime(2010, 4, 6): datetime(2010, 3, 23), + datetime(2010, 4, 8): datetime(2010, 3, 30), + datetime(2010, 4, 5): datetime(2010, 3, 23), + }, + ) + ) + + @pytest.mark.parametrize("case", offset_cases) + def test_offset(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + @pytest.mark.parametrize("weekday", range(7)) + def test_onOffset(self, weekday): + offset = Week(weekday=weekday) + + for day in range(1, 8): + date = datetime(2008, 1, day) + + if day % 7 == weekday: + expected = True + else: + expected = False + assert_onOffset(offset, date, expected) + + +class TestWeekOfMonth(Base): + _offset = WeekOfMonth + offset1 = _offset() + offset2 = _offset(2) + + def test_constructor(self): + with pytest.raises(ValueError, match="^Week"): + WeekOfMonth(n=1, week=4, weekday=0) + + with pytest.raises(ValueError, match="^Week"): + WeekOfMonth(n=1, week=-1, weekday=0) + + with pytest.raises(ValueError, match="^Day"): + WeekOfMonth(n=1, week=0, weekday=-1) + + with pytest.raises(ValueError, match="^Day"): + WeekOfMonth(n=1, week=0, weekday=-7) + + def test_repr(self): + assert ( + repr(WeekOfMonth(weekday=1, week=2)) == "" + ) + + def test_offset(self): + date1 = datetime(2011, 1, 4) # 1st Tuesday of Month + date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month + date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month + date4 = datetime(2011, 1, 25) # 4th Tuesday of Month + + # see for loop for structure + test_cases = [ + (-2, 2, 1, date1, datetime(2010, 11, 16)), + (-2, 2, 1, date2, datetime(2010, 11, 16)), + (-2, 2, 1, date3, datetime(2010, 11, 16)), + (-2, 2, 1, date4, datetime(2010, 12, 21)), + (-1, 2, 1, date1, datetime(2010, 12, 21)), + (-1, 2, 1, date2, datetime(2010, 12, 21)), + (-1, 2, 1, date3, datetime(2010, 12, 21)), + (-1, 2, 1, date4, datetime(2011, 1, 18)), + (0, 0, 1, date1, datetime(2011, 1, 4)), + (0, 0, 1, date2, datetime(2011, 2, 1)), + (0, 0, 1, date3, datetime(2011, 2, 1)), + (0, 0, 1, date4, datetime(2011, 2, 1)), + (0, 1, 1, date1, datetime(2011, 1, 11)), + (0, 1, 1, date2, datetime(2011, 1, 11)), + (0, 1, 1, date3, datetime(2011, 2, 8)), + (0, 1, 1, date4, datetime(2011, 2, 8)), + (0, 0, 1, date1, datetime(2011, 1, 4)), + (0, 1, 1, date2, datetime(2011, 1, 11)), + (0, 2, 1, date3, datetime(2011, 1, 18)), + (0, 3, 1, date4, datetime(2011, 1, 25)), + (1, 0, 0, date1, datetime(2011, 2, 7)), + (1, 0, 0, date2, datetime(2011, 2, 7)), + (1, 0, 0, date3, datetime(2011, 2, 7)), + (1, 0, 0, date4, datetime(2011, 2, 7)), + (1, 0, 1, date1, datetime(2011, 2, 1)), + (1, 0, 1, date2, datetime(2011, 2, 1)), + (1, 0, 1, date3, datetime(2011, 2, 1)), + (1, 0, 1, date4, datetime(2011, 2, 1)), + (1, 0, 2, date1, datetime(2011, 1, 5)), + (1, 0, 2, date2, datetime(2011, 2, 2)), + (1, 0, 2, date3, datetime(2011, 2, 2)), + (1, 0, 2, date4, datetime(2011, 2, 2)), + (1, 2, 1, date1, datetime(2011, 1, 18)), + (1, 2, 1, date2, datetime(2011, 1, 18)), + (1, 2, 1, date3, datetime(2011, 2, 15)), + (1, 2, 1, date4, datetime(2011, 2, 15)), + (2, 2, 1, date1, datetime(2011, 2, 15)), + (2, 2, 1, date2, datetime(2011, 2, 15)), + (2, 2, 1, date3, datetime(2011, 3, 15)), + (2, 2, 1, date4, datetime(2011, 3, 15)), + ] + + for n, week, weekday, dt, expected in test_cases: + offset = WeekOfMonth(n, week=week, weekday=weekday) + assert_offset_equal(offset, dt, expected) + + # try subtracting + result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2) + assert result == datetime(2011, 1, 12) + + result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2) + assert result == datetime(2011, 2, 2) + + on_offset_cases = [ + (0, 0, datetime(2011, 2, 7), True), + (0, 0, datetime(2011, 2, 6), False), + (0, 0, datetime(2011, 2, 14), False), + (1, 0, datetime(2011, 2, 14), True), + (0, 1, datetime(2011, 2, 1), True), + (0, 1, datetime(2011, 2, 8), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + week, weekday, dt, expected = case + offset = WeekOfMonth(week=week, weekday=weekday) + assert offset.onOffset(dt) == expected + + +class TestLastWeekOfMonth(Base): + _offset = LastWeekOfMonth + offset1 = _offset() + offset2 = _offset(2) + + def test_constructor(self): + with pytest.raises(ValueError, match="^N cannot be 0"): + LastWeekOfMonth(n=0, weekday=1) + + with pytest.raises(ValueError, match="^Day"): + LastWeekOfMonth(n=1, weekday=-1) + + with pytest.raises(ValueError, match="^Day"): + LastWeekOfMonth(n=1, weekday=7) + + def test_offset(self): + # Saturday + last_sat = datetime(2013, 8, 31) + next_sat = datetime(2013, 9, 28) + offset_sat = LastWeekOfMonth(n=1, weekday=5) + + one_day_before = last_sat + timedelta(days=-1) + assert one_day_before + offset_sat == last_sat + + one_day_after = last_sat + timedelta(days=+1) + assert one_day_after + offset_sat == next_sat + + # Test On that day + assert last_sat + offset_sat == next_sat + + # Thursday + + offset_thur = LastWeekOfMonth(n=1, weekday=3) + last_thurs = datetime(2013, 1, 31) + next_thurs = datetime(2013, 2, 28) + + one_day_before = last_thurs + timedelta(days=-1) + assert one_day_before + offset_thur == last_thurs + + one_day_after = last_thurs + timedelta(days=+1) + assert one_day_after + offset_thur == next_thurs + + # Test on that day + assert last_thurs + offset_thur == next_thurs + + three_before = last_thurs + timedelta(days=-3) + assert three_before + offset_thur == last_thurs + + two_after = last_thurs + timedelta(days=+2) + assert two_after + offset_thur == next_thurs + + offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN) + assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25) + + on_offset_cases = [ + (WeekDay.SUN, datetime(2013, 1, 27), True), + (WeekDay.SAT, datetime(2013, 3, 30), True), + (WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon + (WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN + (WeekDay.MON, datetime(2013, 2, 25), True), + (WeekDay.SAT, datetime(2013, 11, 30), True), + (WeekDay.SAT, datetime(2006, 8, 26), True), + (WeekDay.SAT, datetime(2007, 8, 25), True), + (WeekDay.SAT, datetime(2008, 8, 30), True), + (WeekDay.SAT, datetime(2009, 8, 29), True), + (WeekDay.SAT, datetime(2010, 8, 28), True), + (WeekDay.SAT, datetime(2011, 8, 27), True), + (WeekDay.SAT, datetime(2019, 8, 31), True), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + weekday, dt, expected = case + offset = LastWeekOfMonth(weekday=weekday) + assert offset.onOffset(dt) == expected + + +class TestSemiMonthEnd(Base): + _offset = SemiMonthEnd + offset1 = _offset() + offset2 = _offset(2) + + def test_offset_whole_year(self): + dates = ( + datetime(2007, 12, 31), + datetime(2008, 1, 15), + datetime(2008, 1, 31), + datetime(2008, 2, 15), + datetime(2008, 2, 29), + datetime(2008, 3, 15), + datetime(2008, 3, 31), + datetime(2008, 4, 15), + datetime(2008, 4, 30), + datetime(2008, 5, 15), + datetime(2008, 5, 31), + datetime(2008, 6, 15), + datetime(2008, 6, 30), + datetime(2008, 7, 15), + datetime(2008, 7, 31), + datetime(2008, 8, 15), + datetime(2008, 8, 31), + datetime(2008, 9, 15), + datetime(2008, 9, 30), + datetime(2008, 10, 15), + datetime(2008, 10, 31), + datetime(2008, 11, 15), + datetime(2008, 11, 30), + datetime(2008, 12, 15), + datetime(2008, 12, 31), + ) + + for base, exp_date in zip(dates[:-1], dates[1:]): + assert_offset_equal(SemiMonthEnd(), base, exp_date) + + # ensure .apply_index works as expected + s = DatetimeIndex(dates[:-1]) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = SemiMonthEnd().apply_index(s) + + exp = DatetimeIndex(dates[1:]) + tm.assert_index_equal(result, exp) + + # ensure generating a range with DatetimeIndex gives same result + result = date_range(start=dates[0], end=dates[-1], freq="SM") + exp = DatetimeIndex(dates) + tm.assert_index_equal(result, exp) + + offset_cases = [] + offset_cases.append( + ( + SemiMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 1, 15), + datetime(2008, 1, 15): datetime(2008, 1, 31), + datetime(2008, 1, 31): datetime(2008, 2, 15), + datetime(2006, 12, 14): datetime(2006, 12, 15), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2007, 1, 15), + datetime(2007, 1, 1): datetime(2007, 1, 15), + datetime(2006, 12, 1): datetime(2006, 12, 15), + datetime(2006, 12, 15): datetime(2006, 12, 31), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(day_of_month=20), + { + datetime(2008, 1, 1): datetime(2008, 1, 20), + datetime(2008, 1, 15): datetime(2008, 1, 20), + datetime(2008, 1, 21): datetime(2008, 1, 31), + datetime(2008, 1, 31): datetime(2008, 2, 20), + datetime(2006, 12, 14): datetime(2006, 12, 20), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2007, 1, 20), + datetime(2007, 1, 1): datetime(2007, 1, 20), + datetime(2006, 12, 1): datetime(2006, 12, 20), + datetime(2006, 12, 15): datetime(2006, 12, 20), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 15), + datetime(2008, 1, 16): datetime(2008, 1, 31), + datetime(2008, 1, 15): datetime(2008, 1, 15), + datetime(2008, 1, 31): datetime(2008, 1, 31), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2006, 12, 31), + datetime(2007, 1, 1): datetime(2007, 1, 15), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(0, day_of_month=16), + { + datetime(2008, 1, 1): datetime(2008, 1, 16), + datetime(2008, 1, 16): datetime(2008, 1, 16), + datetime(2008, 1, 15): datetime(2008, 1, 16), + datetime(2008, 1, 31): datetime(2008, 1, 31), + datetime(2006, 12, 29): datetime(2006, 12, 31), + datetime(2006, 12, 31): datetime(2006, 12, 31), + datetime(2007, 1, 1): datetime(2007, 1, 16), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(2), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 1, 31): datetime(2008, 2, 29), + datetime(2006, 12, 29): datetime(2007, 1, 15), + datetime(2006, 12, 31): datetime(2007, 1, 31), + datetime(2007, 1, 1): datetime(2007, 1, 31), + datetime(2007, 1, 16): datetime(2007, 2, 15), + datetime(2006, 11, 1): datetime(2006, 11, 30), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(-1), + { + datetime(2007, 1, 1): datetime(2006, 12, 31), + datetime(2008, 6, 30): datetime(2008, 6, 15), + datetime(2008, 12, 31): datetime(2008, 12, 15), + datetime(2006, 12, 29): datetime(2006, 12, 15), + datetime(2006, 12, 30): datetime(2006, 12, 15), + datetime(2007, 1, 1): datetime(2006, 12, 31), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(-1, day_of_month=4), + { + datetime(2007, 1, 1): datetime(2006, 12, 31), + datetime(2007, 1, 4): datetime(2006, 12, 31), + datetime(2008, 6, 30): datetime(2008, 6, 4), + datetime(2008, 12, 31): datetime(2008, 12, 4), + datetime(2006, 12, 5): datetime(2006, 12, 4), + datetime(2006, 12, 30): datetime(2006, 12, 4), + datetime(2007, 1, 1): datetime(2006, 12, 31), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthEnd(-2), + { + datetime(2007, 1, 1): datetime(2006, 12, 15), + datetime(2008, 6, 30): datetime(2008, 5, 31), + datetime(2008, 3, 15): datetime(2008, 2, 15), + datetime(2008, 12, 31): datetime(2008, 11, 30), + datetime(2006, 12, 29): datetime(2006, 11, 30), + datetime(2006, 12, 14): datetime(2006, 11, 15), + datetime(2007, 1, 1): datetime(2006, 12, 15), + }, + ) + ) + + @pytest.mark.parametrize("case", offset_cases) + def test_offset(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + @pytest.mark.parametrize("case", offset_cases) + def test_apply_index(self, case): + offset, cases = case + s = DatetimeIndex(cases.keys()) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = offset.apply_index(s) + + exp = DatetimeIndex(cases.values()) + tm.assert_index_equal(result, exp) + + on_offset_cases = [ + (datetime(2007, 12, 31), True), + (datetime(2007, 12, 15), True), + (datetime(2007, 12, 14), False), + (datetime(2007, 12, 1), False), + (datetime(2008, 2, 29), True), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + dt, expected = case + assert_onOffset(SemiMonthEnd(), dt, expected) + + @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) + def test_vectorized_offset_addition(self, klass): + s = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthEnd() + result2 = SemiMonthEnd() + s + + exp = klass( + [ + Timestamp("2000-01-31 00:15:00", tz="US/Central"), + Timestamp("2000-02-29", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + s = klass( + [ + Timestamp("2000-01-01 00:15:00", tz="US/Central"), + Timestamp("2000-02-01", tz="US/Central"), + ], + name="a", + ) + + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthEnd() + result2 = SemiMonthEnd() + s + + exp = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + +class TestSemiMonthBegin(Base): + _offset = SemiMonthBegin + offset1 = _offset() + offset2 = _offset(2) + + def test_offset_whole_year(self): + dates = ( + datetime(2007, 12, 15), + datetime(2008, 1, 1), + datetime(2008, 1, 15), + datetime(2008, 2, 1), + datetime(2008, 2, 15), + datetime(2008, 3, 1), + datetime(2008, 3, 15), + datetime(2008, 4, 1), + datetime(2008, 4, 15), + datetime(2008, 5, 1), + datetime(2008, 5, 15), + datetime(2008, 6, 1), + datetime(2008, 6, 15), + datetime(2008, 7, 1), + datetime(2008, 7, 15), + datetime(2008, 8, 1), + datetime(2008, 8, 15), + datetime(2008, 9, 1), + datetime(2008, 9, 15), + datetime(2008, 10, 1), + datetime(2008, 10, 15), + datetime(2008, 11, 1), + datetime(2008, 11, 15), + datetime(2008, 12, 1), + datetime(2008, 12, 15), + ) + + for base, exp_date in zip(dates[:-1], dates[1:]): + assert_offset_equal(SemiMonthBegin(), base, exp_date) + + # ensure .apply_index works as expected + s = DatetimeIndex(dates[:-1]) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = SemiMonthBegin().apply_index(s) + + exp = DatetimeIndex(dates[1:]) + tm.assert_index_equal(result, exp) + + # ensure generating a range with DatetimeIndex gives same result + result = date_range(start=dates[0], end=dates[-1], freq="SMS") + exp = DatetimeIndex(dates) + tm.assert_index_equal(result, exp) + + offset_cases = [] + offset_cases.append( + ( + SemiMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 1, 15), + datetime(2008, 1, 15): datetime(2008, 2, 1), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 14): datetime(2006, 12, 15), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 31): datetime(2007, 1, 1), + datetime(2007, 1, 1): datetime(2007, 1, 15), + datetime(2006, 12, 1): datetime(2006, 12, 15), + datetime(2006, 12, 15): datetime(2007, 1, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(day_of_month=20), + { + datetime(2008, 1, 1): datetime(2008, 1, 20), + datetime(2008, 1, 15): datetime(2008, 1, 20), + datetime(2008, 1, 21): datetime(2008, 2, 1), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 14): datetime(2006, 12, 20), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 31): datetime(2007, 1, 1), + datetime(2007, 1, 1): datetime(2007, 1, 20), + datetime(2006, 12, 1): datetime(2006, 12, 20), + datetime(2006, 12, 15): datetime(2006, 12, 20), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 16): datetime(2008, 2, 1), + datetime(2008, 1, 15): datetime(2008, 1, 15), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 2): datetime(2006, 12, 15), + datetime(2007, 1, 1): datetime(2007, 1, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(0, day_of_month=16), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 16): datetime(2008, 1, 16), + datetime(2008, 1, 15): datetime(2008, 1, 16), + datetime(2008, 1, 31): datetime(2008, 2, 1), + datetime(2006, 12, 29): datetime(2007, 1, 1), + datetime(2006, 12, 31): datetime(2007, 1, 1), + datetime(2007, 1, 5): datetime(2007, 1, 16), + datetime(2007, 1, 1): datetime(2007, 1, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(2), + { + datetime(2008, 1, 1): datetime(2008, 2, 1), + datetime(2008, 1, 31): datetime(2008, 2, 15), + datetime(2006, 12, 1): datetime(2007, 1, 1), + datetime(2006, 12, 29): datetime(2007, 1, 15), + datetime(2006, 12, 15): datetime(2007, 1, 15), + datetime(2007, 1, 1): datetime(2007, 2, 1), + datetime(2007, 1, 16): datetime(2007, 2, 15), + datetime(2006, 11, 1): datetime(2006, 12, 1), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(-1), + { + datetime(2007, 1, 1): datetime(2006, 12, 15), + datetime(2008, 6, 30): datetime(2008, 6, 15), + datetime(2008, 6, 14): datetime(2008, 6, 1), + datetime(2008, 12, 31): datetime(2008, 12, 15), + datetime(2006, 12, 29): datetime(2006, 12, 15), + datetime(2006, 12, 15): datetime(2006, 12, 1), + datetime(2007, 1, 1): datetime(2006, 12, 15), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(-1, day_of_month=4), + { + datetime(2007, 1, 1): datetime(2006, 12, 4), + datetime(2007, 1, 4): datetime(2007, 1, 1), + datetime(2008, 6, 30): datetime(2008, 6, 4), + datetime(2008, 12, 31): datetime(2008, 12, 4), + datetime(2006, 12, 5): datetime(2006, 12, 4), + datetime(2006, 12, 30): datetime(2006, 12, 4), + datetime(2006, 12, 2): datetime(2006, 12, 1), + datetime(2007, 1, 1): datetime(2006, 12, 4), + }, + ) + ) + + offset_cases.append( + ( + SemiMonthBegin(-2), + { + datetime(2007, 1, 1): datetime(2006, 12, 1), + datetime(2008, 6, 30): datetime(2008, 6, 1), + datetime(2008, 6, 14): datetime(2008, 5, 15), + datetime(2008, 12, 31): datetime(2008, 12, 1), + datetime(2006, 12, 29): datetime(2006, 12, 1), + datetime(2006, 12, 15): datetime(2006, 11, 15), + datetime(2007, 1, 1): datetime(2006, 12, 1), + }, + ) + ) + + @pytest.mark.parametrize("case", offset_cases) + def test_offset(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + @pytest.mark.parametrize("case", offset_cases) + def test_apply_index(self, case): + offset, cases = case + s = DatetimeIndex(cases.keys()) + + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = offset.apply_index(s) + + exp = DatetimeIndex(cases.values()) + tm.assert_index_equal(result, exp) + + on_offset_cases = [ + (datetime(2007, 12, 1), True), + (datetime(2007, 12, 15), True), + (datetime(2007, 12, 14), False), + (datetime(2007, 12, 31), False), + (datetime(2008, 2, 15), True), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + dt, expected = case + assert_onOffset(SemiMonthBegin(), dt, expected) + + @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) + def test_vectorized_offset_addition(self, klass): + s = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthBegin() + result2 = SemiMonthBegin() + s + + exp = klass( + [ + Timestamp("2000-02-01 00:15:00", tz="US/Central"), + Timestamp("2000-03-01", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + s = klass( + [ + Timestamp("2000-01-01 00:15:00", tz="US/Central"), + Timestamp("2000-02-01", tz="US/Central"), + ], + name="a", + ) + with tm.assert_produces_warning(None): + # GH#22535 check that we don't get a FutureWarning from adding + # an integer array to PeriodIndex + result = s + SemiMonthBegin() + result2 = SemiMonthBegin() + s + + exp = klass( + [ + Timestamp("2000-01-15 00:15:00", tz="US/Central"), + Timestamp("2000-02-15", tz="US/Central"), + ], + name="a", + ) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) + + +def test_Easter(): + assert_offset_equal(Easter(), datetime(2010, 1, 1), datetime(2010, 4, 4)) + assert_offset_equal(Easter(), datetime(2010, 4, 5), datetime(2011, 4, 24)) + assert_offset_equal(Easter(2), datetime(2010, 1, 1), datetime(2011, 4, 24)) + + assert_offset_equal(Easter(), datetime(2010, 4, 4), datetime(2011, 4, 24)) + assert_offset_equal(Easter(2), datetime(2010, 4, 4), datetime(2012, 4, 8)) + + assert_offset_equal(-Easter(), datetime(2011, 1, 1), datetime(2010, 4, 4)) + assert_offset_equal(-Easter(), datetime(2010, 4, 5), datetime(2010, 4, 4)) + assert_offset_equal(-Easter(2), datetime(2011, 1, 1), datetime(2009, 4, 12)) + + assert_offset_equal(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)) + assert_offset_equal(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)) + + +class TestOffsetNames: + def test_get_offset_name(self): + assert Week(weekday=0).freqstr == "W-MON" + assert Week(weekday=1).freqstr == "W-TUE" + assert Week(weekday=2).freqstr == "W-WED" + assert Week(weekday=3).freqstr == "W-THU" + assert Week(weekday=4).freqstr == "W-FRI" + + assert LastWeekOfMonth(weekday=WeekDay.SUN).freqstr == "LWOM-SUN" + + +def test_get_offset(): + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset("gibberish") + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset("QS-JAN-B") + + pairs = [ + ("W-MON", Week(weekday=0)), + ("W-TUE", Week(weekday=1)), + ("W-WED", Week(weekday=2)), + ("W-THU", Week(weekday=3)), + ("W-FRI", Week(weekday=4)), + ] + + for name, expected in pairs: + offset = get_offset(name) + assert ( + offset == expected + ), "Expected {name!r} to yield {expected!r} (actual: {offset!r})".format( + name=name, expected=expected, offset=offset + ) + + +def test_get_offset_legacy(): + pairs = [("w@Sat", Week(weekday=5))] + for name, expected in pairs: + with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): + get_offset(name) + + +class TestOffsetAliases: + def setup_method(self, method): + _offset_map.clear() + + def test_alias_equality(self): + for k, v in _offset_map.items(): + if v is None: + continue + assert k == v.copy() + + def test_rule_code(self): + lst = ["M", "MS", "D", "H", "T", "S", "L", "U"] + for k in lst: + assert k == get_offset(k).rule_code + # should be cached - this is kind of an internals test... + assert k in _offset_map + assert k == (get_offset(k) * 3).rule_code + + suffix_lst = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] + base = "W" + for v in suffix_lst: + alias = "-".join([base, v]) + assert alias == get_offset(alias).rule_code + assert alias == (get_offset(alias) * 5).rule_code + + suffix_lst = [ + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC", + ] + base_lst = ["A", "AS", "Q", "QS"] + for base in base_lst: + for v in suffix_lst: + alias = "-".join([base, v]) + assert alias == get_offset(alias).rule_code + assert alias == (get_offset(alias) * 5).rule_code + + lst = ["M", "D", "H", "T", "S", "L", "U"] + for k in lst: + code, stride = get_freq_code("3" + k) + assert isinstance(code, int) + assert stride == 3 + assert k == get_freq_str(code) + + +def test_dateoffset_misc(): + oset = offsets.DateOffset(months=2, days=4) + # it works + oset.freqstr + + assert not offsets.DateOffset(months=2) == 2 + + +class TestReprNames: + def test_str_for_named_is_name(self): + # look at all the amazing combinations! + month_prefixes = ["A", "AS", "Q", "QS"] + names = [ + prefix + "-" + month + for prefix in month_prefixes + for month in [ + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC", + ] + ] + days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] + names += ["W-" + day for day in days] + names += ["WOM-" + week + day for week in ("1", "2", "3", "4") for day in days] + _offset_map.clear() + for name in names: + offset = get_offset(name) + assert offset.freqstr == name + + +def get_utc_offset_hours(ts): + # take a Timestamp and compute total hours of utc offset + o = ts.utcoffset() + return (o.days * 24 * 3600 + o.seconds) / 3600.0 + + +class TestDST: + """ + test DateOffset additions over Daylight Savings Time + """ + + # one microsecond before the DST transition + ts_pre_fallback = "2013-11-03 01:59:59.999999" + ts_pre_springfwd = "2013-03-10 01:59:59.999999" + + # test both basic names and dateutil timezones + timezone_utc_offsets = { + "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), + "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), + } + valid_date_offsets_singular = [ + "weekday", + "day", + "hour", + "minute", + "second", + "microsecond", + ] + valid_date_offsets_plural = [ + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + ] + + def _test_all_offsets(self, n, **kwds): + valid_offsets = ( + self.valid_date_offsets_plural + if n > 1 + else self.valid_date_offsets_singular + ) + + for name in valid_offsets: + self._test_offset(offset_name=name, offset_n=n, **kwds) + + def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): + offset = DateOffset(**{offset_name: offset_n}) + + t = tstart + offset + if expected_utc_offset is not None: + assert get_utc_offset_hours(t) == expected_utc_offset + + if offset_name == "weeks": + # dates should match + assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() + # expect the same day of week, hour of day, minute, second, ... + assert ( + t.dayofweek == tstart.dayofweek + and t.hour == tstart.hour + and t.minute == tstart.minute + and t.second == tstart.second + ) + elif offset_name == "days": + # dates should match + assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() + # expect the same hour of day, minute, second, ... + assert ( + t.hour == tstart.hour + and t.minute == tstart.minute + and t.second == tstart.second + ) + elif offset_name in self.valid_date_offsets_singular: + # expect the singular offset value to match between tstart and t + datepart_offset = getattr( + t, offset_name if offset_name != "weekday" else "dayofweek" + ) + assert datepart_offset == offset.kwds[offset_name] + else: + # the offset should be the same as if it was done in UTC + assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") + + def _make_timestamp(self, string, hrs_offset, tz): + if hrs_offset >= 0: + offset_string = "{hrs:02d}00".format(hrs=hrs_offset) + else: + offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) + return Timestamp(string + offset_string).tz_convert(tz) + + def test_springforward_plural(self): + # test moving from standard to daylight savings + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + hrs_post = utc_offsets["utc_offset_daylight"] + self._test_all_offsets( + n=3, + tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), + expected_utc_offset=hrs_post, + ) + + def test_fallback_singular(self): + # in the case of singular offsets, we don't necessarily know which utc + # offset the new Timestamp will wind up in (the tz for 1 month may be + # different from 1 second) so we don't specify an expected_utc_offset + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + self._test_all_offsets( + n=1, + tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), + expected_utc_offset=None, + ) + + def test_springforward_singular(self): + for tz, utc_offsets in self.timezone_utc_offsets.items(): + hrs_pre = utc_offsets["utc_offset_standard"] + self._test_all_offsets( + n=1, + tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), + expected_utc_offset=None, + ) + + offset_classes = { + MonthBegin: ["11/2/2012", "12/1/2012"], + MonthEnd: ["11/2/2012", "11/30/2012"], + SemiMonthBegin: ["11/2/2012", "11/15/2012"], + SemiMonthEnd: ["11/2/2012", "11/15/2012"], + Week: ["11/2/2012", "11/9/2012"], + YearBegin: ["11/2/2012", "1/1/2013"], + YearEnd: ["11/2/2012", "12/31/2012"], + QuarterBegin: ["11/2/2012", "12/1/2012"], + QuarterEnd: ["11/2/2012", "12/31/2012"], + Day: ["11/4/2012", "11/4/2012 23:00"], + }.items() + + @pytest.mark.parametrize("tup", offset_classes) + def test_all_offset_classes(self, tup): + offset, test_values = tup + + first = Timestamp(test_values[0], tz="US/Eastern") + offset() + second = Timestamp(test_values[1], tz="US/Eastern") + assert first == second + + +# --------------------------------------------------------------------- +def test_get_offset_day_error(): + # subclass of _BaseOffset must override _day_opt attribute, or we should + # get a NotImplementedError + + with pytest.raises(NotImplementedError): + DateOffset()._get_offset_day(datetime.now()) + + +def test_valid_default_arguments(date_offset_types): + # GH#19142 check that the calling the constructors without passing + # any keyword arguments produce valid offsets + cls = date_offset_types + cls() + + +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_month_attributes(kwd, date_month_classes): + # GH#18226 + cls = date_month_classes + # check that we cannot create e.g. MonthEnd(weeks=3) + with pytest.raises(TypeError): + cls(**{kwd: 3}) + + +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_relativedelta_kwargs(kwd): + # Check that all the arguments specified in liboffsets.relativedelta_kwds + # are in fact valid relativedelta keyword args + DateOffset(**{kwd: 1}) + + +@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +def test_valid_tick_attributes(kwd, tick_classes): + # GH#18226 + cls = tick_classes + # check that we cannot create e.g. Hour(weeks=3) + with pytest.raises(TypeError): + cls(**{kwd: 3}) + + +def test_validate_n_error(): + with pytest.raises(TypeError): + DateOffset(n="Doh!") + + with pytest.raises(TypeError): + MonthBegin(n=timedelta(1)) + + +def test_require_integers(date_offset_types): + cls = date_offset_types + with pytest.raises(ValueError): + cls(n=1.5) + + +def test_tick_normalize_raises(tick_classes): + # check that trying to create a Tick object with normalize=True raises + # GH#21427 + cls = tick_classes + with pytest.raises(ValueError): + cls(n=3, normalize=True) + + +def test_weeks_onoffset(): + # GH#18510 Week with weekday = None, normalize = False should always + # be onOffset + offset = Week(n=2, weekday=None) + ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + # negative n + offset = Week(n=2, weekday=None) + ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + +def test_weekofmonth_onoffset(): + # GH#18864 + # Make sure that nanoseconds don't trip up onOffset (and with it apply) + offset = WeekOfMonth(n=2, week=2, weekday=0) + ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + # negative n + offset = WeekOfMonth(n=-3, week=1, weekday=0) + ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") + fast = offset.onOffset(ts) + slow = (ts + offset) - offset == ts + assert fast == slow + + +def test_last_week_of_month_on_offset(): + # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth + offset = LastWeekOfMonth(n=4, weekday=6) + ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") + slow = (ts + offset) - offset == ts + fast = offset.onOffset(ts) + assert fast == slow + + # negative n + offset = LastWeekOfMonth(n=-4, weekday=5) + ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") + slow = (ts + offset) - offset == ts + fast = offset.onOffset(ts) + assert fast == slow + + +def test_week_add_invalid(): + # Week with weekday should raise TypeError and _not_ AttributeError + # when adding invalid offset + offset = Week(weekday=1) + other = Day() + with pytest.raises(TypeError, match="Cannot add"): + offset + other From ed100e9e2542ccded13cd6383534f6f16f6d517b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Tue, 10 Dec 2019 23:23:05 +0100 Subject: [PATCH 07/12] Working on rebasing 2 --- pandas/tests/tseries/offsets/test_offsets.py | 3035 ++++++++++++++++-- 1 file changed, 2798 insertions(+), 237 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_offsets.py index f3554931fd8fb..bed8d2461f65d 100644 --- a/pandas/tests/tseries/offsets/test_offsets.py +++ b/pandas/tests/tseries/offsets/test_offsets.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import date, datetime, time as dt_time, timedelta from typing import Dict, List, Tuple, Type import numpy as np @@ -17,6 +17,8 @@ get_freq_str, ) import pandas._libs.tslibs.offsets as liboffsets +from pandas._libs.tslibs.offsets import ApplyTypeError +import pandas.compat as compat from pandas.compat.numpy import np_datetime64_compat from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range @@ -25,12 +27,27 @@ from pandas.io.pickle import read_pickle from pandas.tseries.frequencies import _offset_map, get_offset +from pandas.tseries.holiday import USFederalHolidayCalendar import pandas.tseries.offsets as offsets from pandas.tseries.offsets import ( + FY5253, BaseOffset, + BDay, + BMonthBegin, + BMonthEnd, + BQuarterBegin, + BQuarterEnd, + BusinessHour, + BYearBegin, + BYearEnd, + CBMonthBegin, + CBMonthEnd, + CDay, + CustomBusinessHour, DateOffset, Day, Easter, + FY5253Quarter, LastWeekOfMonth, MonthBegin, MonthEnd, @@ -92,7 +109,24 @@ class Base: def _get_offset(self, klass, value=1, normalize=False): # create instance from offset class - if klass is LastWeekOfMonth: + if klass is FY5253: + klass = klass( + n=value, + startingMonth=1, + weekday=1, + variation="last", + normalize=normalize, + ) + elif klass is FY5253Quarter: + klass = klass( + n=value, + startingMonth=1, + weekday=1, + qtr_with_extra_week=1, + variation="last", + normalize=normalize, + ) + elif klass is LastWeekOfMonth: klass = klass(n=value, weekday=5, normalize=normalize) elif klass is WeekOfMonth: klass = klass(n=value, week=1, weekday=5, normalize=normalize) @@ -112,7 +146,12 @@ def test_apply_out_of_range(self, tz_naive_fixture): # try to create an out-of-bounds result timestamp; if we can't create # the offset skip try: - offset = self._get_offset(self._offset, value=10000) + if self._offset in (BusinessHour, CustomBusinessHour): + # Using 10000 in BusinessHour fails in tz check because of DST + # difference + offset = self._get_offset(self._offset, value=100000) + else: + offset = self._get_offset(self._offset, value=10000) result = Timestamp("20080101") + offset assert isinstance(result, datetime) @@ -203,16 +242,30 @@ class TestCommon(Base): expecteds = { "Day": Timestamp("2011-01-02 09:00:00"), "DateOffset": Timestamp("2011-01-02 09:00:00"), + "BusinessDay": Timestamp("2011-01-03 09:00:00"), + "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), + "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), + "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), "MonthBegin": Timestamp("2011-02-01 09:00:00"), + "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), "MonthEnd": Timestamp("2011-01-31 09:00:00"), "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), + "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), "YearBegin": Timestamp("2012-01-01 09:00:00"), + "BYearBegin": Timestamp("2011-01-03 09:00:00"), "YearEnd": Timestamp("2011-12-31 09:00:00"), + "BYearEnd": Timestamp("2011-12-30 09:00:00"), "QuarterBegin": Timestamp("2011-03-01 09:00:00"), + "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), "QuarterEnd": Timestamp("2011-03-31 09:00:00"), + "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), + "BusinessHour": Timestamp("2011-01-03 10:00:00"), + "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), + "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), + "FY5253": Timestamp("2011-01-25 09:00:00"), "Week": Timestamp("2011-01-08 09:00:00"), "Easter": Timestamp("2011-04-24 09:00:00"), "Hour": Timestamp("2011-01-01 10:00:00"), @@ -223,16 +276,16 @@ class TestCommon(Base): "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), } - def test_immutable(self, date_offset_types): + def test_immutable(self, offset_types): # GH#21341 check that __setattr__ raises - offset = self._get_offset(date_offset_types) + offset = self._get_offset(offset_types) with pytest.raises(AttributeError): offset.normalize = True with pytest.raises(AttributeError): offset.n = 91 - def test_return_type(self, date_offset_types): - offset = self._get_offset(date_offset_types) + def test_return_type(self, offset_types): + offset = self._get_offset(offset_types) # make sure that we are returning a Timestamp result = Timestamp("20080101") + offset @@ -245,8 +298,8 @@ def test_return_type(self, date_offset_types): assert NaT - offset is NaT assert (-offset).apply(NaT) is NaT - def test_offset_n(self, date_offset_types): - offset = self._get_offset(date_offset_types) + def test_offset_n(self, offset_types): + offset = self._get_offset(offset_types) assert offset.n == 1 neg_offset = offset * -1 @@ -255,17 +308,17 @@ def test_offset_n(self, date_offset_types): mul_offset = offset * 3 assert mul_offset.n == 3 - def test_offset_timedelta64_arg(self, date_offset_types): + def test_offset_timedelta64_arg(self, offset_types): # check that offset._validate_n raises TypeError on a timedelt64 # object - off = self._get_offset(date_offset_types) + off = self._get_offset(offset_types) td64 = np.timedelta64(4567, "s") with pytest.raises(TypeError, match="argument must be an integer"): type(off)(n=td64, **off.kwds) - def test_offset_mul_ndarray(self, date_offset_types): - off = self._get_offset(date_offset_types) + def test_offset_mul_ndarray(self, offset_types): + off = self._get_offset(offset_types) expected = np.array([[off, off * 2], [off * 3, off * 4]]) @@ -275,8 +328,8 @@ def test_offset_mul_ndarray(self, date_offset_types): result = off * np.array([[1, 2], [3, 4]]) tm.assert_numpy_array_equal(result, expected) - def test_offset_freqstr(self, date_offset_types): - offset = self._get_offset(date_offset_types) + def test_offset_freqstr(self, offset_types): + offset = self._get_offset(offset_types) freqstr = offset.freqstr if freqstr not in ("", "", "LWOM-SAT"): @@ -329,262 +382,2744 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals tz_obj = timezones.maybe_get_tz(tz) dt_tz = conversion.localize_pydatetime(dt, tz_obj) - result = func(dt_tz) - assert isinstance(result, Timestamp) - assert result == expected_localize + result = func(dt_tz) + assert isinstance(result, Timestamp) + assert result == expected_localize + + result = func(Timestamp(dt, tz=tz)) + assert isinstance(result, Timestamp) + assert result == expected_localize + + # see gh-14101 + exp_warning = None + ts = Timestamp(dt, tz=tz) + Nano(5) + + if ( + offset_s.__class__.__name__ == "DateOffset" + and (funcname == "apply" or normalize) + and ts.nanosecond > 0 + ): + exp_warning = UserWarning + + # test nanosecond is preserved + with tm.assert_produces_warning(exp_warning, check_stacklevel=False): + result = func(ts) + assert isinstance(result, Timestamp) + if normalize is False: + assert result == expected_localize + Nano(5) + else: + assert result == expected_localize + + def test_apply(self, offset_types): + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = self.expecteds[offset_types.__name__] + self._check_offsetfunc_works(offset_types, "apply", dt, expected) + + expected = Timestamp(expected.date()) + self._check_offsetfunc_works( + offset_types, "apply", dt, expected, normalize=True + ) + + def test_rollforward(self, offset_types): + expecteds = self.expecteds.copy() + + # result will not be changed if the target is on the offset + no_changes = [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ] + for n in no_changes: + expecteds[n] = Timestamp("2011/01/01 09:00") + + expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") + expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2011-01-02 00:00:00"), + "DateOffset": Timestamp("2011-01-02 00:00:00"), + "MonthBegin": Timestamp("2011-02-01 00:00:00"), + "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), + "YearBegin": Timestamp("2012-01-01 00:00:00"), + "Week": Timestamp("2011-01-08 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[offset_types.__name__] + self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) + expected = norm_expected[offset_types.__name__] + self._check_offsetfunc_works( + offset_types, "rollforward", dt, expected, normalize=True + ) + + def test_rollback(self, offset_types): + expecteds = { + "BusinessDay": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), + "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), + "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), + "MonthEnd": Timestamp("2010-12-31 09:00:00"), + "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), + "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), + "BYearBegin": Timestamp("2010-01-01 09:00:00"), + "YearEnd": Timestamp("2010-12-31 09:00:00"), + "BYearEnd": Timestamp("2010-12-31 09:00:00"), + "QuarterBegin": Timestamp("2010-12-01 09:00:00"), + "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), + "QuarterEnd": Timestamp("2010-12-31 09:00:00"), + "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), + "BusinessHour": Timestamp("2010-12-31 17:00:00"), + "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), + "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), + "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), + "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), + "FY5253": Timestamp("2010-01-26 09:00:00"), + "Easter": Timestamp("2010-04-04 09:00:00"), + } + + # result will not be changed if the target is on the offset + for n in [ + "Day", + "MonthBegin", + "SemiMonthBegin", + "YearBegin", + "Week", + "Hour", + "Minute", + "Second", + "Milli", + "Micro", + "Nano", + "DateOffset", + ]: + expecteds[n] = Timestamp("2011/01/01 09:00") + + # but be changed when normalize=True + norm_expected = expecteds.copy() + for k in norm_expected: + norm_expected[k] = Timestamp(norm_expected[k].date()) + + normalized = { + "Day": Timestamp("2010-12-31 00:00:00"), + "DateOffset": Timestamp("2010-12-31 00:00:00"), + "MonthBegin": Timestamp("2010-12-01 00:00:00"), + "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), + "YearBegin": Timestamp("2010-01-01 00:00:00"), + "Week": Timestamp("2010-12-25 00:00:00"), + "Hour": Timestamp("2011-01-01 00:00:00"), + "Minute": Timestamp("2011-01-01 00:00:00"), + "Second": Timestamp("2011-01-01 00:00:00"), + "Milli": Timestamp("2011-01-01 00:00:00"), + "Micro": Timestamp("2011-01-01 00:00:00"), + } + norm_expected.update(normalized) + + sdt = datetime(2011, 1, 1, 9, 0) + ndt = np_datetime64_compat("2011-01-01 09:00Z") + + for dt in [sdt, ndt]: + expected = expecteds[offset_types.__name__] + self._check_offsetfunc_works(offset_types, "rollback", dt, expected) + + expected = norm_expected[offset_types.__name__] + self._check_offsetfunc_works( + offset_types, "rollback", dt, expected, normalize=True + ) + + def test_onOffset(self, offset_types): + dt = self.expecteds[offset_types.__name__] + offset_s = self._get_offset(offset_types) + assert offset_s.onOffset(dt) + + # when normalize=True, onOffset checks time is 00:00:00 + if issubclass(offset_types, Tick): + # normalize=True disallowed for Tick subclasses GH#21427 + return + offset_n = self._get_offset(offset_types, normalize=True) + assert not offset_n.onOffset(dt) + + if offset_types in (BusinessHour, CustomBusinessHour): + # In default BusinessHour (9:00-17:00), normalized time + # cannot be in business hour range + return + date = datetime(dt.year, dt.month, dt.day) + assert offset_n.onOffset(date) + + def test_add(self, offset_types, tz_naive_fixture): + tz = tz_naive_fixture + dt = datetime(2011, 1, 1, 9, 0) + + offset_s = self._get_offset(offset_types) + expected = self.expecteds[offset_types.__name__] + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + # normalize=True, disallowed for Tick subclasses GH#21427 + if issubclass(offset_types, Tick): + return + offset_s = self._get_offset(offset_types, normalize=True) + expected = Timestamp(expected.date()) + + result_dt = dt + offset_s + result_ts = Timestamp(dt) + offset_s + for result in [result_dt, result_ts]: + assert isinstance(result, Timestamp) + assert result == expected + + expected_localize = expected.tz_localize(tz) + result = Timestamp(dt, tz=tz) + offset_s + assert isinstance(result, Timestamp) + assert result == expected_localize + + def test_pickle_v0_15_2(self, datapath): + offsets = { + "DateOffset": DateOffset(years=1), + "MonthBegin": MonthBegin(1), + "Day": Day(1), + "YearBegin": YearBegin(1), + "Week": Week(1), + } + + pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") + # This code was executed once on v0.15.2 to generate the pickle: + # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) + # + tm.assert_dict_equal(offsets, read_pickle(pickle_path)) + + +class TestDateOffset(Base): + def setup_method(self, method): + self.d = Timestamp(datetime(2008, 1, 2)) + _offset_map.clear() + + def test_repr(self): + repr(DateOffset()) + repr(DateOffset(2)) + repr(2 * DateOffset()) + repr(2 * DateOffset(months=2)) + + def test_mul(self): + assert DateOffset(2) == 2 * DateOffset(1) + assert DateOffset(2) == DateOffset(1) * 2 + + def test_constructor(self): + + assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2) + assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2) + + assert (self.d + DateOffset(2)) == datetime(2008, 1, 4) + + assert not DateOffset(2).isAnchored() + assert DateOffset(1).isAnchored() + + d = datetime(2008, 1, 31) + assert (d + DateOffset(months=1)) == datetime(2008, 2, 29) + + def test_copy(self): + assert DateOffset(months=2).copy() == DateOffset(months=2) + + def test_eq(self): + offset1 = DateOffset(days=1) + offset2 = DateOffset(days=365) + + assert offset1 != offset2 + + +class TestBusinessDay(Base): + _offset = BDay + + def setup_method(self, method): + self.d = datetime(2008, 1, 1) + + self.offset = BDay() + self.offset1 = self.offset + self.offset2 = BDay(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 * BusinessDays>" + + if compat.PY37: + expected = "" + else: + 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_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): + assert self.offset2(self.d) == datetime(2008, 1, 3) + + def testRollback1(self): + assert BDay(10).rollback(self.d) == self.d + + def testRollback2(self): + assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) + + def testRollforward1(self): + assert BDay(10).rollforward(self.d) == self.d + + def testRollforward2(self): + assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) + + def test_roll_date_object(self): + offset = BDay() + + 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) + + def test_onOffset(self): + tests = [ + (BDay(), datetime(2008, 1, 1), True), + (BDay(), datetime(2008, 1, 5), False), + ] + + for offset, d, expected in tests: + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + 2 * BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + -BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + -2 * BDay(), + { + 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), + }, + ) + ) + + apply_cases.append( + ( + BDay(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 + BDay(10) + assert result == datetime(2012, 11, 6) + + result = dt + BDay(100) - BDay(100) + assert result == dt + + off = BDay() * 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 + + off = BDay() * 10 + rs = datetime(2014, 1, 5) + off # see #5890 + xp = datetime(2014, 1, 17) + assert rs == xp + + 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 TestBusinessHour(Base): + _offset = BusinessHour + + def setup_method(self, method): + self.d = datetime(2014, 7, 1, 10, 00) + + self.offset1 = BusinessHour() + self.offset2 = BusinessHour(n=3) + + self.offset3 = BusinessHour(n=-1) + self.offset4 = BusinessHour(n=-4) + + from datetime import time as dt_time + + self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) + self.offset6 = BusinessHour(start="20:00", end="05:00") + self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) + self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) + self.offset9 = BusinessHour( + n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] + ) + self.offset10 = BusinessHour( + n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] + ) + + @pytest.mark.parametrize( + "start,end,match", + [ + ( + dt_time(11, 0, 5), + "17:00", + "time data must be specified only with hour and minute", + ), + ("AAA", "17:00", "time data must match '%H:%M' format"), + ("14:00:05", "17:00", "time data must match '%H:%M' format"), + ([], "17:00", "Must include at least 1 start time"), + ("09:00", [], "Must include at least 1 end time"), + ( + ["09:00", "11:00"], + "17:00", + "number of starting time and ending time must be the same", + ), + ( + ["09:00", "11:00"], + ["10:00"], + "number of starting time and ending time must be the same", + ), + ( + ["09:00", "11:00"], + ["12:00", "20:00"], + r"invalid starting and ending time\(s\): opening hours should not " + "touch or overlap with one another", + ), + ( + ["12:00", "20:00"], + ["09:00", "11:00"], + r"invalid starting and ending time\(s\): opening hours should not " + "touch or overlap with one another", + ), + ], + ) + def test_constructor_errors(self, start, end, match): + with pytest.raises(ValueError, match=match): + BusinessHour(start=start, end=end) + + 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.offset1) == "" + assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" + assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" + assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" + + assert repr(self.offset5) == "" + assert repr(self.offset6) == "" + assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" + assert repr(self.offset8) == "" + assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" + assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" + + def test_with_offset(self): + expected = Timestamp("2014-07-01 13:00") + + assert self.d + BusinessHour() * 3 == expected + assert self.d + BusinessHour(n=3) == expected + + @pytest.mark.parametrize( + "offset_name", + ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], + ) + def test_eq_attribute(self, offset_name): + offset = getattr(self, offset_name) + assert offset == offset + + @pytest.mark.parametrize( + "offset1,offset2", + [ + (BusinessHour(start="09:00"), BusinessHour()), + ( + BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), + BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), + ), + ], + ) + def test_eq(self, offset1, offset2): + assert offset1 == offset2 + + @pytest.mark.parametrize( + "offset1,offset2", + [ + (BusinessHour(), BusinessHour(-1)), + (BusinessHour(start="09:00"), BusinessHour(start="09:01")), + ( + BusinessHour(start="09:00", end="17:00"), + BusinessHour(start="17:00", end="09:01"), + ), + ( + BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), + BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), + ), + ], + ) + def test_neq(self, offset1, offset2): + assert offset1 != offset2 + + @pytest.mark.parametrize( + "offset_name", + ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], + ) + def test_hash(self, offset_name): + offset = getattr(self, offset_name) + assert offset == offset + + def test_call(self): + assert self.offset1(self.d) == datetime(2014, 7, 1, 11) + assert self.offset2(self.d) == datetime(2014, 7, 1, 13) + assert self.offset3(self.d) == datetime(2014, 6, 30, 17) + assert self.offset4(self.d) == datetime(2014, 6, 30, 14) + assert self.offset8(self.d) == datetime(2014, 7, 1, 11) + assert self.offset9(self.d) == datetime(2014, 7, 1, 22) + assert self.offset10(self.d) == datetime(2014, 7, 1, 1) + + def test_sub(self): + # we have to override test_sub here because self.offset2 is not + # defined as self._offset(2) + off = self.offset2 + msg = "Cannot subtract datetime from offset" + with pytest.raises(TypeError, match=msg): + off - self.d + assert 2 * off - off == off + + assert self.d - self.offset2 == self.d + self._offset(-3) + + def testRollback1(self): + assert self.offset1.rollback(self.d) == self.d + assert self.offset2.rollback(self.d) == self.d + assert self.offset3.rollback(self.d) == self.d + assert self.offset4.rollback(self.d) == self.d + assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) + assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) + assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) + assert self.offset8.rollback(self.d) == self.d + assert self.offset9.rollback(self.d) == self.d + assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) + assert self.offset6.rollback(d) == d + assert self.offset7.rollback(d) == d + assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) + assert self.offset9.rollback(d) == d + assert self.offset10.rollback(d) == d + + assert self._offset(5).rollback(self.d) == self.d + + def testRollback2(self): + assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( + 2014, 7, 4, 17, 0 + ) + + def testRollforward1(self): + assert self.offset1.rollforward(self.d) == self.d + assert self.offset2.rollforward(self.d) == self.d + assert self.offset3.rollforward(self.d) == self.d + assert self.offset4.rollforward(self.d) == self.d + assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) + assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) + assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) + assert self.offset8.rollforward(self.d) == self.d + assert self.offset9.rollforward(self.d) == self.d + assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) + assert self.offset6.rollforward(d) == d + assert self.offset7.rollforward(d) == d + assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset9.rollforward(d) == d + assert self.offset10.rollforward(d) == d + + assert self._offset(5).rollforward(self.d) == self.d + + def testRollforward2(self): + assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( + 2014, 7, 7, 9 + ) + + def test_roll_date_object(self): + offset = BusinessHour() + + dt = datetime(2014, 7, 6, 15, 0) + + result = offset.rollback(dt) + assert result == datetime(2014, 7, 4, 17) + + result = offset.rollforward(dt) + assert result == datetime(2014, 7, 7, 9) + + normalize_cases = [] + normalize_cases.append( + ( + BusinessHour(normalize=True), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 1, 0): datetime(2014, 7, 1), + datetime(2014, 7, 4, 15): datetime(2014, 7, 4), + datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 7), + datetime(2014, 7, 6, 10): datetime(2014, 7, 7), + }, + ) + ) + + normalize_cases.append( + ( + BusinessHour(-1, normalize=True), + { + datetime(2014, 7, 1, 8): datetime(2014, 6, 30), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1), + datetime(2014, 7, 1, 10): datetime(2014, 6, 30), + datetime(2014, 7, 1, 0): datetime(2014, 6, 30), + datetime(2014, 7, 7, 10): datetime(2014, 7, 4), + datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 4), + datetime(2014, 7, 6, 10): datetime(2014, 7, 4), + }, + ) + ) + + normalize_cases.append( + ( + BusinessHour(1, normalize=True, start="17:00", end="04:00"), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 2, 2): datetime(2014, 7, 2), + datetime(2014, 7, 2, 3): datetime(2014, 7, 2), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5), + datetime(2014, 7, 5, 2): datetime(2014, 7, 5), + datetime(2014, 7, 7, 2): datetime(2014, 7, 7), + datetime(2014, 7, 7, 17): datetime(2014, 7, 7), + }, + ) + ) + + @pytest.mark.parametrize("case", normalize_cases) + def test_normalize(self, case): + offset, cases = case + for dt, expected in cases.items(): + assert offset.apply(dt) == expected + + on_offset_cases = [] + on_offset_cases.append( + ( + BusinessHour(), + { + datetime(2014, 7, 1, 9): True, + datetime(2014, 7, 1, 8, 59): False, + datetime(2014, 7, 1, 8): False, + datetime(2014, 7, 1, 17): True, + datetime(2014, 7, 1, 17, 1): False, + datetime(2014, 7, 1, 18): False, + datetime(2014, 7, 5, 9): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start="10:00", end="15:00"), + { + datetime(2014, 7, 1, 9): False, + datetime(2014, 7, 1, 10): True, + datetime(2014, 7, 1, 15): True, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 9, 0): False, + datetime(2014, 7, 1, 10, 0): False, + datetime(2014, 7, 1, 15): False, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12, 0): False, + datetime(2014, 7, 6, 12, 0): False, + datetime(2014, 7, 1, 19, 0): True, + datetime(2014, 7, 2, 0, 0): True, + datetime(2014, 7, 4, 23): True, + datetime(2014, 7, 5, 1): True, + datetime(2014, 7, 5, 5, 0): True, + datetime(2014, 7, 6, 23, 0): False, + datetime(2014, 7, 7, 3, 0): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), + { + datetime(2014, 7, 1, 9): True, + datetime(2014, 7, 1, 8, 59): False, + datetime(2014, 7, 1, 8): False, + datetime(2014, 7, 1, 17): True, + datetime(2014, 7, 1, 17, 1): False, + datetime(2014, 7, 1, 18): False, + datetime(2014, 7, 5, 9): False, + datetime(2014, 7, 6, 12): False, + datetime(2014, 7, 1, 12, 30): False, + }, + ) + ) + + on_offset_cases.append( + ( + BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), + { + datetime(2014, 7, 1, 9, 0): False, + datetime(2014, 7, 1, 10, 0): False, + datetime(2014, 7, 1, 15): False, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12, 0): False, + datetime(2014, 7, 6, 12, 0): False, + datetime(2014, 7, 1, 19, 0): True, + datetime(2014, 7, 2, 0, 0): True, + datetime(2014, 7, 4, 23): True, + datetime(2014, 7, 5, 1): True, + datetime(2014, 7, 5, 5, 0): True, + datetime(2014, 7, 6, 23, 0): False, + datetime(2014, 7, 7, 3, 0): False, + datetime(2014, 7, 4, 22): False, + }, + ) + ) + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, cases = case + for dt, expected in cases.items(): + assert offset.onOffset(dt) == expected + + opening_time_cases = [] + # opening time should be affected by sign of n, not by n's value and + # end + opening_time_cases.append( + ( + [ + BusinessHour(), + BusinessHour(n=2), + BusinessHour(n=4), + BusinessHour(end="10:00"), + BusinessHour(n=2, end="4:00"), + BusinessHour(n=4, end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 9), + ), + # if timestamp is on opening time, next opening time is + # as it is + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 3, 9), + datetime(2014, 7, 2, 9), + ), + # 2014-07-05 is saturday + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 9), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 8, 9), + datetime(2014, 7, 7, 9), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start="11:15"), + BusinessHour(n=2, start="11:15"), + BusinessHour(n=3, start="11:15"), + BusinessHour(start="11:15", end="10:00"), + BusinessHour(n=2, start="11:15", end="4:00"), + BusinessHour(n=3, start="11:15", end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 11, 15), + datetime(2014, 6, 30, 11, 15), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 11, 15), + ), + datetime(2014, 7, 2, 11, 15): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 2, 11, 15, 1): ( + datetime(2014, 7, 3, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 11, 15), + datetime(2014, 7, 3, 11, 15), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 11, 15), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(-1), + BusinessHour(n=-2), + BusinessHour(n=-4), + BusinessHour(n=-1, end="10:00"), + BusinessHour(n=-2, end="4:00"), + BusinessHour(n=-4, end="15:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 1, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 9), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 9), + datetime(2014, 7, 3, 9), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 9): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 7, 9), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 9), + datetime(2014, 7, 8, 9), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start="17:00", end="05:00"), + BusinessHour(n=3, start="17:00", end="03:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 17), + datetime(2014, 6, 30, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 4, 17): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 3, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 7, 17, 1): ( + datetime(2014, 7, 8, 17), + datetime(2014, 7, 7, 17), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(-1, start="17:00", end="05:00"), + BusinessHour(n=-2, start="17:00", end="03:00"), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 16, 59): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 3, 17), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 17), + ), + datetime(2014, 7, 7, 18): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 8, 17), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), + BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), + BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), + BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), + BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 11, 15), + datetime(2014, 6, 30, 15), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 10): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 1, 15), + ), + datetime(2014, 7, 2, 11, 15): ( + datetime(2014, 7, 2, 11, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 2, 11, 15, 1): ( + datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 11, 15), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 11, 15), + datetime(2014, 7, 3, 15), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 9, 1): ( + datetime(2014, 7, 7, 11, 15), + datetime(2014, 7, 4, 15), + ), + datetime(2014, 7, 7, 12): ( + datetime(2014, 7, 7, 15), + datetime(2014, 7, 7, 11, 15), + ), + }, + ) + ) + + opening_time_cases.append( + ( + [ + BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), + BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), + ], + { + datetime(2014, 7, 1, 11): ( + datetime(2014, 7, 1, 8), + datetime(2014, 7, 1, 17), + ), + datetime(2014, 7, 1, 18): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 1, 23): ( + datetime(2014, 7, 1, 17), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 2, 8): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 8), + ), + datetime(2014, 7, 2, 9): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 2, 16, 59): ( + datetime(2014, 7, 2, 8), + datetime(2014, 7, 2, 17), + ), + datetime(2014, 7, 5, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 4, 10): ( + datetime(2014, 7, 4, 8), + datetime(2014, 7, 4, 17), + ), + datetime(2014, 7, 4, 23): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 6, 10): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 7, 5): ( + datetime(2014, 7, 4, 17), + datetime(2014, 7, 7, 8), + ), + datetime(2014, 7, 7, 18): ( + datetime(2014, 7, 7, 17), + datetime(2014, 7, 8, 8), + ), + }, + ) + ) + + @pytest.mark.parametrize("case", opening_time_cases) + def test_opening_time(self, case): + _offsets, cases = case + for offset in _offsets: + for dt, (exp_next, exp_prev) in cases.items(): + assert offset._next_opening_time(dt) == exp_next + assert offset._prev_opening_time(dt) == exp_prev + + apply_cases = [] + apply_cases.append( + ( + BusinessHour(), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(4), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(-1), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), + datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), + datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(-4), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), + datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(start="13:00", end="16:00"), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), + datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=2, start="13:00", end="16:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), + datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), + datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start="13:00", end="16:00"), + { + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), + datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-3, start="10:00", end="16:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), + datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), + datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), + datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), + datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), + datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), + datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), + datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), + datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), + datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), + datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), + datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start="19:00", end="05:00"), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), + datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), + datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), + datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), + datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), + datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), + datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), + }, + ) + ) + + # long business hours (see gh-26381) + apply_cases.append( + ( + BusinessHour(n=4, start="00:00", end="23:00"), + { + datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), + datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), + datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), + datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), + datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), + datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-4, start="00:00", end="23:00"), + { + datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), + datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), + datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), + datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), + datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), + datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), + }, + ) + ) + + # multiple business hours + apply_cases.append( + ( + BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), + # out of business hours + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), + datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), + datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), + datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), + datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), + datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), + datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), + datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), + datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), + datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), + datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), + datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), + { + datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), + datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), + datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), + datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), + datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), + datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), + datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), + datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), + datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), + datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), + datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), + datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), + datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), + }, + ) + ) + + @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) + + apply_large_n_cases = [] + # A week later + apply_large_n_cases.append( + ( + BusinessHour(40), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), + datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), + datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), + datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), + datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), + datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), + datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), + datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), + datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), + datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), + datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), + datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), + datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), + }, + ) + ) + + # 3 days and 1 hour before + apply_large_n_cases.append( + ( + BusinessHour(-25), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), + datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), + datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), + datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), + datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), + datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), + datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), + datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), + datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), + datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), + datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), + }, + ) + ) + + # 5 days and 3 hours later + apply_large_n_cases.append( + ( + BusinessHour(28, start="21:00", end="02:00"), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), + datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), + datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), + datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), + datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), + datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), + datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), + datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), + datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), + datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), + }, + ) + ) + + # large n for multiple opening hours (3 days and 1 hour before) + apply_large_n_cases.append( + ( + BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), + datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), + datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), + datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), + datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), + datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), + datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), + datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), + datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), + datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), + datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), + datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), + datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), + }, + ) + ) + + # 5 days and 3 hours later + apply_large_n_cases.append( + ( + BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), + datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), + datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), + datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), + datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), + datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), + datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), + datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), + datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), + datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), + datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), + datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), + }, + ) + ) + + @pytest.mark.parametrize("case", apply_large_n_cases) + def test_apply_large_n(self, case): + offset, cases = case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_apply_nanoseconds(self): + tests = [] + + tests.append( + ( + BusinessHour(), + { + Timestamp("2014-07-04 15:00") + + Nano(5): Timestamp("2014-07-04 16:00") + + Nano(5), + Timestamp("2014-07-04 16:00") + + Nano(5): Timestamp("2014-07-07 09:00") + + Nano(5), + Timestamp("2014-07-04 16:00") + - Nano(5): Timestamp("2014-07-04 17:00") + - Nano(5), + }, + ) + ) + + tests.append( + ( + BusinessHour(-1), + { + Timestamp("2014-07-04 15:00") + + Nano(5): Timestamp("2014-07-04 14:00") + + Nano(5), + Timestamp("2014-07-04 10:00") + + Nano(5): Timestamp("2014-07-04 09:00") + + Nano(5), + Timestamp("2014-07-04 10:00") + - Nano(5): Timestamp("2014-07-03 17:00") + - Nano(5), + }, + ) + ) + + for offset, cases in tests: + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + def test_datetimeindex(self): + idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") + idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") + idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") + expected = DatetimeIndex( + [ + "2014-07-04 15:00", + "2014-07-04 16:00", + "2014-07-07 09:00", + "2014-07-07 10:00", + "2014-07-07 11:00", + "2014-07-07 12:00", + "2014-07-07 13:00", + "2014-07-07 14:00", + "2014-07-07 15:00", + "2014-07-07 16:00", + "2014-07-08 09:00", + "2014-07-08 10:00", + ], + freq="BH", + ) + for idx in [idx1, idx2, idx3]: + tm.assert_index_equal(idx, expected) + + idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") + idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") + idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") + + expected = DatetimeIndex( + [ + "2014-07-04 15:45", + "2014-07-04 16:45", + "2014-07-07 09:45", + "2014-07-07 10:45", + "2014-07-07 11:45", + "2014-07-07 12:45", + "2014-07-07 13:45", + "2014-07-07 14:45", + "2014-07-07 15:45", + "2014-07-07 16:45", + "2014-07-08 09:45", + "2014-07-08 10:45", + ], + freq="BH", + ) + expected = idx1 + for idx in [idx1, idx2, idx3]: + tm.assert_index_equal(idx, expected) + + +class TestCustomBusinessHour(Base): + _offset = CustomBusinessHour + holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] + + def setup_method(self, method): + # 2014 Calendar to check custom holidays + # Sun Mon Tue Wed Thu Fri Sat + # 6/22 23 24 25 26 27 28 + # 29 30 7/1 2 3 4 5 + # 6 7 8 9 10 11 12 + self.d = datetime(2014, 7, 1, 10, 00) + self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") + + self.offset2 = CustomBusinessHour(holidays=self.holidays) + + def test_constructor_errors(self): + from datetime import time as dt_time + + with pytest.raises(ValueError): + CustomBusinessHour(start=dt_time(11, 0, 5)) + with pytest.raises(ValueError): + CustomBusinessHour(start="AAA") + with pytest.raises(ValueError): + CustomBusinessHour(start="14:00:05") + + 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.offset1) == "" + assert repr(self.offset2) == "" + + def test_with_offset(self): + expected = Timestamp("2014-07-01 13:00") + + assert self.d + CustomBusinessHour() * 3 == expected + assert self.d + CustomBusinessHour(n=3) == expected + + def test_eq(self): + for offset in [self.offset1, self.offset2]: + assert offset == offset + + assert CustomBusinessHour() != CustomBusinessHour(-1) + assert CustomBusinessHour(start="09:00") == CustomBusinessHour() + assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") + assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( + start="17:00", end="09:01" + ) + + assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( + weekmask="Mon Tue Wed Thu Fri" + ) + assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( + holidays=["2014-06-28"] + ) + + def test_sub(self): + # override the Base.test_sub implementation because self.offset2 is + # defined differently in this class than the test expects + pass + + def test_hash(self): + assert hash(self.offset1) == hash(self.offset1) + assert hash(self.offset2) == hash(self.offset2) + + def test_call(self): + assert self.offset1(self.d) == datetime(2014, 7, 1, 11) + assert self.offset2(self.d) == datetime(2014, 7, 1, 11) + + def testRollback1(self): + assert self.offset1.rollback(self.d) == self.d + assert self.offset2.rollback(self.d) == self.d + + d = datetime(2014, 7, 1, 0) + + # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) + assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) + + # 2014/6/30 and 2014/6/27 are holidays + assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) + + def testRollback2(self): + assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( + 2014, 7, 4, 17, 0 + ) + + def testRollforward1(self): + assert self.offset1.rollforward(self.d) == self.d + assert self.offset2.rollforward(self.d) == self.d + + d = datetime(2014, 7, 1, 0) + assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) + assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) + + def testRollforward2(self): + assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( + 2014, 7, 7, 9 + ) + + def test_roll_date_object(self): + offset = BusinessHour() + + dt = datetime(2014, 7, 6, 15, 0) + + result = offset.rollback(dt) + assert result == datetime(2014, 7, 4, 17) + + result = offset.rollforward(dt) + assert result == datetime(2014, 7, 7, 9) + + normalize_cases = [] + normalize_cases.append( + ( + CustomBusinessHour(normalize=True, holidays=holidays), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3), + datetime(2014, 7, 1, 23): datetime(2014, 7, 3), + datetime(2014, 7, 1, 0): datetime(2014, 7, 1), + datetime(2014, 7, 4, 15): datetime(2014, 7, 4), + datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 7), + datetime(2014, 7, 6, 10): datetime(2014, 7, 7), + }, + ) + ) + + normalize_cases.append( + ( + CustomBusinessHour(-1, normalize=True, holidays=holidays), + { + datetime(2014, 7, 1, 8): datetime(2014, 6, 26), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 16): datetime(2014, 7, 1), + datetime(2014, 7, 1, 10): datetime(2014, 6, 26), + datetime(2014, 7, 1, 0): datetime(2014, 6, 26), + datetime(2014, 7, 7, 10): datetime(2014, 7, 4), + datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), + datetime(2014, 7, 5, 23): datetime(2014, 7, 4), + datetime(2014, 7, 6, 10): datetime(2014, 7, 4), + }, + ) + ) + + normalize_cases.append( + ( + CustomBusinessHour( + 1, normalize=True, start="17:00", end="04:00", holidays=holidays + ), + { + datetime(2014, 7, 1, 8): datetime(2014, 7, 1), + datetime(2014, 7, 1, 17): datetime(2014, 7, 1), + datetime(2014, 7, 1, 23): datetime(2014, 7, 2), + datetime(2014, 7, 2, 2): datetime(2014, 7, 2), + datetime(2014, 7, 2, 3): datetime(2014, 7, 3), + datetime(2014, 7, 4, 23): datetime(2014, 7, 5), + datetime(2014, 7, 5, 2): datetime(2014, 7, 5), + datetime(2014, 7, 7, 2): datetime(2014, 7, 7), + datetime(2014, 7, 7, 17): datetime(2014, 7, 7), + }, + ) + ) + + @pytest.mark.parametrize("norm_cases", normalize_cases) + def test_normalize(self, norm_cases): + offset, cases = norm_cases + for dt, expected in cases.items(): + assert offset.apply(dt) == expected + + def test_onOffset(self): + tests = [] + + tests.append( + ( + CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), + { + datetime(2014, 7, 1, 9): False, + datetime(2014, 7, 1, 10): True, + datetime(2014, 7, 1, 15): True, + datetime(2014, 7, 1, 15, 1): False, + datetime(2014, 7, 5, 12): False, + datetime(2014, 7, 6, 12): False, + }, + ) + ) + + for offset, cases in tests: + for dt, expected in cases.items(): + assert offset.onOffset(dt) == expected + + apply_cases = [] + apply_cases.append( + ( + CustomBusinessHour(holidays=holidays), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), + datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), + datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), + datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), + datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), + # out of business hours + datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), + # saturday + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), + }, + ) + ) + + apply_cases.append( + ( + CustomBusinessHour(4, holidays=holidays), + { + datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), + datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), + datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), + datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), + datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), + datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), + datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), + datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), + datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), + datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), + }, + ) + ) + + @pytest.mark.parametrize("apply_case", apply_cases) + def test_apply(self, apply_case): + offset, cases = apply_case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + nano_cases = [] + nano_cases.append( + ( + CustomBusinessHour(holidays=holidays), + { + Timestamp("2014-07-01 15:00") + + Nano(5): Timestamp("2014-07-01 16:00") + + Nano(5), + Timestamp("2014-07-01 16:00") + + Nano(5): Timestamp("2014-07-03 09:00") + + Nano(5), + Timestamp("2014-07-01 16:00") + - Nano(5): Timestamp("2014-07-01 17:00") + - Nano(5), + }, + ) + ) + + nano_cases.append( + ( + CustomBusinessHour(-1, holidays=holidays), + { + Timestamp("2014-07-01 15:00") + + Nano(5): Timestamp("2014-07-01 14:00") + + Nano(5), + Timestamp("2014-07-01 10:00") + + Nano(5): Timestamp("2014-07-01 09:00") + + Nano(5), + Timestamp("2014-07-01 10:00") + - Nano(5): Timestamp("2014-06-26 17:00") + - Nano(5), + }, + ) + ) + + @pytest.mark.parametrize("nano_case", nano_cases) + def test_apply_nanoseconds(self, nano_case): + offset, cases = nano_case + for base, expected in cases.items(): + assert_offset_equal(offset, base, expected) + + +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>" + + if compat.PY37: + expected = "" + else: + 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_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): + 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_onOffset(self, case): + offset, d, expected = case + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + 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), + }, + ) + ) + + apply_cases.append( + ( + 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), + }, + ) + ) + + apply_cases.append( + ( + -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), + }, + ) + ) + + apply_cases.append( + ( + -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), + }, + ) + ) + + apply_cases.append( + ( + 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 + + +class CustomBusinessMonthBase: + def setup_method(self, method): + self.d = datetime(2008, 1, 1) + + self.offset = self._offset() + self.offset1 = self.offset + self.offset2 = self._offset(2) + + 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_roundtrip_pickle(self): + def _check_roundtrip(obj): + unpickled = tm.round_trip_pickle(obj) + assert unpickled == obj + + _check_roundtrip(self._offset()) + _check_roundtrip(self._offset(2)) + _check_roundtrip(self._offset() * 2) + + def test_copy(self): + # GH 17452 + off = self._offset(weekmask="Mon Wed Fri") + assert off == off.copy() + + +class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): + _offset = CBMonthEnd + + 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 * CustomBusinessMonthEnds>" + + def testCall(self): + assert self.offset2(self.d) == datetime(2008, 2, 29) + + def testRollback1(self): + assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) + + def testRollback2(self): + assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) + + def testRollforward1(self): + assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) + + def test_roll_date_object(self): + offset = CBMonthEnd() + + dt = date(2012, 9, 15) + + result = offset.rollback(dt) + assert result == datetime(2012, 8, 31) + + result = offset.rollforward(dt) + assert result == datetime(2012, 9, 28) + + 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 = [ + (CBMonthEnd(), datetime(2008, 1, 31), True), + (CBMonthEnd(), datetime(2008, 1, 1), False), + ] + + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, d, expected = case + assert_onOffset(offset, d, expected) + + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 2, 7): datetime(2008, 2, 29), + }, + ) + ) + + apply_cases.append( + ( + 2 * CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2008, 2, 29), + datetime(2008, 2, 7): datetime(2008, 3, 31), + }, + ) + ) - result = func(Timestamp(dt, tz=tz)) - assert isinstance(result, Timestamp) - assert result == expected_localize + apply_cases.append( + ( + -CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2007, 12, 31), + datetime(2008, 2, 8): datetime(2008, 1, 31), + }, + ) + ) - # see gh-14101 - exp_warning = None - ts = Timestamp(dt, tz=tz) + Nano(5) + apply_cases.append( + ( + -2 * CBMonthEnd(), + { + datetime(2008, 1, 1): datetime(2007, 11, 30), + datetime(2008, 2, 9): datetime(2007, 12, 31), + }, + ) + ) - if ( - offset_s.__class__.__name__ == "DateOffset" - and (funcname == "apply" or normalize) - and ts.nanosecond > 0 - ): - exp_warning = UserWarning + apply_cases.append( + ( + CBMonthEnd(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 31), + datetime(2008, 2, 7): datetime(2008, 2, 29), + }, + ) + ) - # test nanosecond is preserved - with tm.assert_produces_warning(exp_warning, check_stacklevel=False): - result = func(ts) - assert isinstance(result, Timestamp) - if normalize is False: - assert result == expected_localize + Nano(5) - else: - assert result == expected_localize + @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(self, date_offset_types): - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") + def test_apply_large_n(self): + dt = datetime(2012, 10, 23) - for dt in [sdt, ndt]: - expected = self.expecteds[date_offset_types.__name__] - self._check_offsetfunc_works(date_offset_types, "apply", dt, expected) + result = dt + CBMonthEnd(10) + assert result == datetime(2013, 7, 31) - expected = Timestamp(expected.date()) - self._check_offsetfunc_works( - date_offset_types, "apply", dt, expected, normalize=True - ) + result = dt + CDay(100) - CDay(100) + assert result == dt - def test_rollforward(self, date_offset_types): - expecteds = self.expecteds.copy() + off = CBMonthEnd() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 7, 29) + assert rs == xp - # result will not be changed if the target is on the offset - no_changes = [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ] - for n in no_changes: - expecteds[n] = Timestamp("2011/01/01 09:00") + st = datetime(2011, 12, 18) + rs = st + off + xp = datetime(2012, 5, 31) + assert rs == xp - # but be changed when normalize=True - norm_expected = expecteds.copy() - for k in norm_expected: - norm_expected[k] = Timestamp(norm_expected[k].date()) + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] + bm_offset = CBMonthEnd(holidays=holidays) + dt = datetime(2012, 1, 1) + assert dt + bm_offset == datetime(2012, 1, 30) + assert dt + 2 * bm_offset == datetime(2012, 2, 27) - normalized = { - "Day": Timestamp("2011-01-02 00:00:00"), - "DateOffset": Timestamp("2011-01-02 00:00:00"), - "MonthBegin": Timestamp("2011-02-01 00:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), - "YearBegin": Timestamp("2012-01-01 00:00:00"), - "Week": Timestamp("2011-01-08 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_datetimeindex(self): + from pandas.tseries.holiday import USFederalHolidayCalendar - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") + hcal = USFederalHolidayCalendar() + freq = CBMonthEnd(calendar=hcal) - for dt in [sdt, ndt]: - expected = expecteds[date_offset_types.__name__] - self._check_offsetfunc_works(date_offset_types, "rollforward", dt, expected) - expected = norm_expected[date_offset_types.__name__] - self._check_offsetfunc_works( - date_offset_types, "rollforward", dt, expected, normalize=True - ) + assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ + 0 + ] == datetime(2012, 1, 31) - def test_rollback(self, date_offset_types): - expecteds = { - "MonthEnd": Timestamp("2010-12-31 09:00:00"), - "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), - "YearEnd": Timestamp("2010-12-31 09:00:00"), - "QuarterBegin": Timestamp("2010-12-01 09:00:00"), - "QuarterEnd": Timestamp("2010-12-31 09:00:00"), - "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), - "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), - "Easter": Timestamp("2010-04-04 09:00:00"), - } - # result will not be changed if the target is on the offset - for n in [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ]: - expecteds[n] = Timestamp("2011/01/01 09:00") +class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): + _offset = CBMonthBegin - # but be changed when normalize=True - norm_expected = expecteds.copy() - for k in norm_expected: - norm_expected[k] = Timestamp(norm_expected[k].date()) + 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 - normalized = { - "Day": Timestamp("2010-12-31 00:00:00"), - "DateOffset": Timestamp("2010-12-31 00:00:00"), - "MonthBegin": Timestamp("2010-12-01 00:00:00"), - "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), - "YearBegin": Timestamp("2010-01-01 00:00:00"), - "Week": Timestamp("2010-12-25 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) + def test_repr(self): + assert repr(self.offset) == "" + assert repr(self.offset2) == "<2 * CustomBusinessMonthBegins>" - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") + def testCall(self): + assert self.offset2(self.d) == datetime(2008, 3, 3) - for dt in [sdt, ndt]: - expected = expecteds[date_offset_types.__name__] - self._check_offsetfunc_works(date_offset_types, "rollback", dt, expected) + def testRollback1(self): + assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - expected = norm_expected[date_offset_types.__name__] - self._check_offsetfunc_works( - date_offset_types, "rollback", dt, expected, normalize=True - ) + def testRollback2(self): + assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) - def test_onOffset(self, date_offset_types): - dt = self.expecteds[date_offset_types.__name__] - offset_s = self._get_offset(date_offset_types) - assert offset_s.onOffset(dt) + def testRollforward1(self): + assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) - # when normalize=True, onOffset checks time is 00:00:00 - if issubclass(date_offset_types, Tick): - # normalize=True disallowed for Tick subclasses GH#21427 - return - offset_n = self._get_offset(date_offset_types, normalize=True) - assert not offset_n.onOffset(dt) + def test_roll_date_object(self): + offset = CBMonthBegin() - date = datetime(dt.year, dt.month, dt.day) - assert offset_n.onOffset(date) + dt = date(2012, 9, 15) - def test_add(self, date_offset_types, tz_naive_fixture): - tz = tz_naive_fixture - dt = datetime(2011, 1, 1, 9, 0) + result = offset.rollback(dt) + assert result == datetime(2012, 9, 3) - offset_s = self._get_offset(date_offset_types) - expected = self.expecteds[date_offset_types.__name__] + result = offset.rollforward(dt) + assert result == datetime(2012, 10, 1) - result_dt = dt + offset_s - result_ts = Timestamp(dt) + offset_s - for result in [result_dt, result_ts]: - assert isinstance(result, Timestamp) - assert result == expected + offset = offsets.Day() + result = offset.rollback(dt) + assert result == datetime(2012, 9, 15) - expected_localize = expected.tz_localize(tz) - result = Timestamp(dt, tz=tz) + offset_s - assert isinstance(result, Timestamp) - assert result == expected_localize + result = offset.rollforward(dt) + assert result == datetime(2012, 9, 15) - # normalize=True, disallowed for Tick subclasses GH#21427 - if issubclass(date_offset_types, Tick): - return - offset_s = self._get_offset(date_offset_types, normalize=True) - expected = Timestamp(expected.date()) + on_offset_cases = [ + (CBMonthBegin(), datetime(2008, 1, 1), True), + (CBMonthBegin(), datetime(2008, 1, 31), False), + ] - result_dt = dt + offset_s - result_ts = Timestamp(dt) + offset_s - for result in [result_dt, result_ts]: - assert isinstance(result, Timestamp) - assert result == expected + @pytest.mark.parametrize("case", on_offset_cases) + def test_onOffset(self, case): + offset, dt, expected = case + assert_onOffset(offset, dt, expected) - expected_localize = expected.tz_localize(tz) - result = Timestamp(dt, tz=tz) + offset_s - assert isinstance(result, Timestamp) - assert result == expected_localize + apply_cases = [] # type: _ApplyCases + apply_cases.append( + ( + CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 2, 1), + datetime(2008, 2, 7): datetime(2008, 3, 3), + }, + ) + ) - def test_pickle_v0_15_2(self, datapath): - offsets = { - "DateOffset": DateOffset(years=1), - "MonthBegin": MonthBegin(1), - "Day": Day(1), - "YearBegin": YearBegin(1), - "Week": Week(1), - } + apply_cases.append( + ( + 2 * CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2008, 3, 3), + datetime(2008, 2, 7): datetime(2008, 4, 1), + }, + ) + ) - pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") - # This code was executed once on v0.15.2 to generate the pickle: - # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) - # - tm.assert_dict_equal(offsets, read_pickle(pickle_path)) + apply_cases.append( + ( + -CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2007, 12, 3), + datetime(2008, 2, 8): datetime(2008, 2, 1), + }, + ) + ) + apply_cases.append( + ( + -2 * CBMonthBegin(), + { + datetime(2008, 1, 1): datetime(2007, 11, 1), + datetime(2008, 2, 9): datetime(2008, 1, 1), + }, + ) + ) -class TestDateOffset(Base): - def setup_method(self, method): - self.d = Timestamp(datetime(2008, 1, 2)) - _offset_map.clear() + apply_cases.append( + ( + CBMonthBegin(0), + { + datetime(2008, 1, 1): datetime(2008, 1, 1), + datetime(2008, 1, 7): datetime(2008, 2, 1), + }, + ) + ) - def test_repr(self): - repr(DateOffset()) - repr(DateOffset(2)) - repr(2 * DateOffset()) - repr(2 * DateOffset(months=2)) + @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_mul(self): - assert DateOffset(2) == 2 * DateOffset(1) - assert DateOffset(2) == DateOffset(1) * 2 + def test_apply_large_n(self): + dt = datetime(2012, 10, 23) - def test_constructor(self): + result = dt + CBMonthBegin(10) + assert result == datetime(2013, 8, 1) - assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2) - assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2) + result = dt + CDay(100) - CDay(100) + assert result == dt - assert (self.d + DateOffset(2)) == datetime(2008, 1, 4) + off = CBMonthBegin() * 6 + rs = datetime(2012, 1, 1) - off + xp = datetime(2011, 7, 1) + assert rs == xp - assert not DateOffset(2).isAnchored() - assert DateOffset(1).isAnchored() + st = datetime(2011, 12, 18) + rs = st + off - d = datetime(2008, 1, 31) - assert (d + DateOffset(months=1)) == datetime(2008, 2, 29) + xp = datetime(2012, 6, 1) + assert rs == xp - def test_copy(self): - assert DateOffset(months=2).copy() == DateOffset(months=2) + def test_holidays(self): + # Define a TradingDay offset + holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] + bm_offset = CBMonthBegin(holidays=holidays) + dt = datetime(2012, 1, 1) - def test_eq(self): - offset1 = DateOffset(days=1) - offset2 = DateOffset(days=365) + assert dt + bm_offset == datetime(2012, 1, 2) + assert dt + 2 * bm_offset == datetime(2012, 2, 3) - assert offset1 != offset2 + @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") + def test_datetimeindex(self): + hcal = USFederalHolidayCalendar() + cbmb = CBMonthBegin(calendar=hcal) + assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ + 0 + ] == datetime(2012, 1, 3) class TestWeek(Base): @@ -1402,6 +3937,9 @@ def test_Easter(): class TestOffsetNames: def test_get_offset_name(self): + assert BDay().freqstr == "B" + assert BDay(2).freqstr == "2B" + assert BMonthEnd().freqstr == "BM" assert Week(weekday=0).freqstr == "W-MON" assert Week(weekday=1).freqstr == "W-TUE" assert Week(weekday=2).freqstr == "W-WED" @@ -1418,6 +3956,10 @@ def test_get_offset(): get_offset("QS-JAN-B") pairs = [ + ("B", BDay()), + ("b", BDay()), + ("bm", BMonthEnd()), + ("Bm", BMonthEnd()), ("W-MON", Week(weekday=0)), ("W-TUE", Week(weekday=1)), ("W-WED", Week(weekday=2)), @@ -1452,7 +3994,7 @@ def test_alias_equality(self): assert k == v.copy() def test_rule_code(self): - lst = ["M", "MS", "D", "H", "T", "S", "L", "U"] + lst = ["M", "MS", "BM", "BMS", "D", "B", "H", "T", "S", "L", "U"] for k in lst: assert k == get_offset(k).rule_code # should be cached - this is kind of an internals test... @@ -1480,14 +4022,14 @@ def test_rule_code(self): "NOV", "DEC", ] - base_lst = ["A", "AS", "Q", "QS"] + base_lst = ["A", "AS", "BA", "BAS", "Q", "QS", "BQ", "BQS"] for base in base_lst: for v in suffix_lst: alias = "-".join([base, v]) assert alias == get_offset(alias).rule_code assert alias == (get_offset(alias) * 5).rule_code - lst = ["M", "D", "H", "T", "S", "L", "U"] + lst = ["M", "D", "B", "H", "T", "S", "L", "U"] for k in lst: code, stride = get_freq_code("3" + k) assert isinstance(code, int) @@ -1503,10 +4045,18 @@ def test_dateoffset_misc(): assert not offsets.DateOffset(months=2) == 2 +def test_freq_offsets(): + off = BDay(1, offset=timedelta(0, 1800)) + assert off.freqstr == "B+30Min" + + off = BDay(1, offset=timedelta(0, -1800)) + assert off.freqstr == "B-30Min" + + class TestReprNames: def test_str_for_named_is_name(self): # look at all the amazing combinations! - month_prefixes = ["A", "AS", "Q", "QS"] + month_prefixes = ["A", "AS", "BA", "BAS", "Q", "BQ", "BQS", "QS"] names = [ prefix + "-" + month for prefix in month_prefixes @@ -1660,13 +4210,21 @@ def test_springforward_singular(self): offset_classes = { MonthBegin: ["11/2/2012", "12/1/2012"], MonthEnd: ["11/2/2012", "11/30/2012"], + BMonthBegin: ["11/2/2012", "12/3/2012"], + BMonthEnd: ["11/2/2012", "11/30/2012"], + CBMonthBegin: ["11/2/2012", "12/3/2012"], + CBMonthEnd: ["11/2/2012", "11/30/2012"], SemiMonthBegin: ["11/2/2012", "11/15/2012"], SemiMonthEnd: ["11/2/2012", "11/15/2012"], Week: ["11/2/2012", "11/9/2012"], YearBegin: ["11/2/2012", "1/1/2013"], YearEnd: ["11/2/2012", "12/31/2012"], + BYearBegin: ["11/2/2012", "1/1/2013"], + BYearEnd: ["11/2/2012", "12/31/2012"], QuarterBegin: ["11/2/2012", "12/1/2012"], QuarterEnd: ["11/2/2012", "12/31/2012"], + BQuarterBegin: ["11/2/2012", "12/3/2012"], + BQuarterEnd: ["11/2/2012", "12/31/2012"], Day: ["11/4/2012", "11/4/2012 23:00"], }.items() @@ -1688,17 +4246,17 @@ def test_get_offset_day_error(): DateOffset()._get_offset_day(datetime.now()) -def test_valid_default_arguments(date_offset_types): +def test_valid_default_arguments(offset_types): # GH#19142 check that the calling the constructors without passing # any keyword arguments produce valid offsets - cls = date_offset_types + cls = offset_types cls() @pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) -def test_valid_month_attributes(kwd, date_month_classes): +def test_valid_month_attributes(kwd, month_classes): # GH#18226 - cls = date_month_classes + cls = month_classes # check that we cannot create e.g. MonthEnd(weeks=3) with pytest.raises(TypeError): cls(**{kwd: 3}) @@ -1727,9 +4285,12 @@ def test_validate_n_error(): with pytest.raises(TypeError): MonthBegin(n=timedelta(1)) + with pytest.raises(TypeError): + BDay(n=np.array([1, 2], dtype=np.int64)) + -def test_require_integers(date_offset_types): - cls = date_offset_types +def test_require_integers(offset_types): + cls = offset_types with pytest.raises(ValueError): cls(n=1.5) From 89677fe8119054f47159c303c0f8668a7ece16d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Wed, 11 Dec 2019 00:24:14 +0100 Subject: [PATCH 08/12] Rebased business and date offsets --- .../tseries/offsets/test_business_offsets.py | 29 +- .../tseries/offsets/test_date_offsets.py | 25 +- pandas/tests/tseries/offsets/test_offsets.py | 4361 ----------------- 3 files changed, 26 insertions(+), 4389 deletions(-) delete mode 100644 pandas/tests/tseries/offsets/test_offsets.py diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index 6dfbd8a20956f..5916489119201 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -1,5 +1,5 @@ from datetime import date, datetime, time as dt_time, timedelta -from typing import Dict, List, Tuple, Type +from typing import Dict, List, Optional, Tuple, Type import numpy as np import pytest @@ -70,7 +70,7 @@ class WeekDay: class Base: - _offset = None # type: Type[DateOffset] + _offset: Optional[Type[DateOffset]] = None d = Timestamp(datetime(2008, 1, 2)) timezones = [ @@ -307,7 +307,7 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals ts = Timestamp(dt) + Nano(5) if ( - offset_s.__class__.__name__ == "DateOffset" + type(offset_s).__name__ == "DateOffset" and (funcname == "apply" or normalize) and ts.nanosecond > 0 ): @@ -344,7 +344,7 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals ts = Timestamp(dt, tz=tz) + Nano(5) if ( - offset_s.__class__.__name__ == "DateOffset" + type(offset_s).__name__ == "DateOffset" and (funcname == "apply" or normalize) and ts.nanosecond > 0 ): @@ -566,7 +566,7 @@ def test_onOffset(self): for offset, d, expected in tests: assert_onOffset(offset, d, expected) - apply_cases = [] # type: _ApplyCases + apply_cases: _ApplyCases = [] apply_cases.append( ( BDay(), @@ -1523,7 +1523,7 @@ def test_opening_time(self, case): assert offset._next_opening_time(dt) == exp_next assert offset._prev_opening_time(dt) == exp_prev - apply_cases = [] + apply_cases: _ApplyCases = [] apply_cases.append( ( BusinessHour(), @@ -2272,7 +2272,7 @@ def test_onOffset(self): for dt, expected in cases.items(): assert offset.onOffset(dt) == expected - apply_cases = [] + apply_cases: _ApplyCases = [] apply_cases.append( ( CustomBusinessHour(holidays=holidays), @@ -2454,7 +2454,7 @@ def test_onOffset(self, case): offset, d, expected = case assert_onOffset(offset, d, expected) - apply_cases = [] # type: _ApplyCases + apply_cases: _ApplyCases = [] apply_cases.append( ( CDay(), @@ -2701,7 +2701,7 @@ def test_onOffset(self, case): offset, d, expected = case assert_onOffset(offset, d, expected) - apply_cases = [] # type: _ApplyCases + apply_cases: _ApplyCases = [] apply_cases.append( ( CBMonthEnd(), @@ -2850,7 +2850,7 @@ def test_onOffset(self, case): offset, dt, expected = case assert_onOffset(offset, dt, expected) - apply_cases = [] # type: _ApplyCases + apply_cases: _ApplyCases = [] apply_cases.append( ( CBMonthBegin(), @@ -2967,10 +2967,9 @@ def test_get_offset(): for name, expected in pairs: offset = get_offset(name) - assert ( - offset == expected - ), "Expected {name!r} to yield {expected!r} (actual: {offset!r})".format( - name=name, expected=expected, offset=offset + assert offset == expected, ( + f"Expected {repr(name)} to yield {repr(expected)} " + f"(actual: {repr(offset)})" ) @@ -3106,7 +3105,7 @@ def test_valid_default_arguments(business_offset_types): cls() -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) def test_valid_month_attributes(kwd, business_month_classes): # GH#18226 cls = business_month_classes diff --git a/pandas/tests/tseries/offsets/test_date_offsets.py b/pandas/tests/tseries/offsets/test_date_offsets.py index f3554931fd8fb..4567172827d9a 100644 --- a/pandas/tests/tseries/offsets/test_date_offsets.py +++ b/pandas/tests/tseries/offsets/test_date_offsets.py @@ -1,5 +1,5 @@ from datetime import datetime, timedelta -from typing import Dict, List, Tuple, Type +from typing import Dict, List, Optional, Tuple, Type import numpy as np import pytest @@ -78,7 +78,7 @@ def test_to_M8(): class Base: - _offset = None # type: Type[DateOffset] + _offset: Optional[Type[DateOffset]] = None d = Timestamp(datetime(2008, 1, 2)) timezones = [ @@ -305,7 +305,7 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals ts = Timestamp(dt) + Nano(5) if ( - offset_s.__class__.__name__ == "DateOffset" + type(offset_s).__name__ == "DateOffset" and (funcname == "apply" or normalize) and ts.nanosecond > 0 ): @@ -342,7 +342,7 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals ts = Timestamp(dt, tz=tz) + Nano(5) if ( - offset_s.__class__.__name__ == "DateOffset" + type(offset_s).__name__ == "DateOffset" and (funcname == "apply" or normalize) and ts.nanosecond > 0 ): @@ -1427,10 +1427,9 @@ def test_get_offset(): for name, expected in pairs: offset = get_offset(name) - assert ( - offset == expected - ), "Expected {name!r} to yield {expected!r} (actual: {offset!r})".format( - name=name, expected=expected, offset=offset + assert offset == expected, ( + f"Expected {repr(name)} to yield {repr(expected)} " + f"(actual: {repr(offset)})" ) @@ -1620,9 +1619,9 @@ def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): def _make_timestamp(self, string, hrs_offset, tz): if hrs_offset >= 0: - offset_string = "{hrs:02d}00".format(hrs=hrs_offset) + offset_string = f"{hrs_offset:02d}00" else: - offset_string = "-{hrs:02d}00".format(hrs=-1 * hrs_offset) + offset_string = f"-{(hrs_offset * -1):02}00" return Timestamp(string + offset_string).tz_convert(tz) def test_springforward_plural(self): @@ -1695,7 +1694,7 @@ def test_valid_default_arguments(date_offset_types): cls() -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) def test_valid_month_attributes(kwd, date_month_classes): # GH#18226 cls = date_month_classes @@ -1704,14 +1703,14 @@ def test_valid_month_attributes(kwd, date_month_classes): cls(**{kwd: 3}) -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) def test_valid_relativedelta_kwargs(kwd): # Check that all the arguments specified in liboffsets.relativedelta_kwds # are in fact valid relativedelta keyword args DateOffset(**{kwd: 1}) -@pytest.mark.parametrize("kwd", sorted(list(liboffsets.relativedelta_kwds))) +@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) def test_valid_tick_attributes(kwd, tick_classes): # GH#18226 cls = tick_classes diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_offsets.py deleted file mode 100644 index 458d69c1d3216..0000000000000 --- a/pandas/tests/tseries/offsets/test_offsets.py +++ /dev/null @@ -1,4361 +0,0 @@ -from datetime import date, datetime, time as dt_time, timedelta -from typing import Dict, List, Optional, Tuple, Type - -import numpy as np -import pytest - -from pandas._libs.tslibs import ( - NaT, - OutOfBoundsDatetime, - Timestamp, - conversion, - timezones, -) -from pandas._libs.tslibs.frequencies import ( - INVALID_FREQ_ERR_MSG, - get_freq_code, - get_freq_str, -) -import pandas._libs.tslibs.offsets as liboffsets -from pandas._libs.tslibs.offsets import ApplyTypeError -import pandas.compat as compat -from pandas.compat.numpy import np_datetime64_compat - -from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range -from pandas.core.series import Series -import pandas.util.testing as tm - -from pandas.io.pickle import read_pickle -from pandas.tseries.frequencies import _offset_map, get_offset -from pandas.tseries.holiday import USFederalHolidayCalendar -import pandas.tseries.offsets as offsets -from pandas.tseries.offsets import ( - FY5253, - BaseOffset, - BDay, - BMonthBegin, - BMonthEnd, - BQuarterBegin, - BQuarterEnd, - BusinessHour, - BYearBegin, - BYearEnd, - CBMonthBegin, - CBMonthEnd, - CDay, - CustomBusinessHour, - DateOffset, - Day, - Easter, - FY5253Quarter, - LastWeekOfMonth, - MonthBegin, - MonthEnd, - Nano, - QuarterBegin, - QuarterEnd, - SemiMonthBegin, - SemiMonthEnd, - Tick, - Week, - WeekOfMonth, - YearBegin, - YearEnd, -) - -from .common import assert_offset_equal, assert_onOffset - - -class WeekDay: - # TODO: Remove: This is not used outside of tests - MON = 0 - TUE = 1 - WED = 2 - THU = 3 - FRI = 4 - SAT = 5 - SUN = 6 - - -#### -# Misc function tests -#### - - -def test_to_M8(): - valb = datetime(2007, 10, 1) - valu = _to_M8(valb) - assert isinstance(valu, np.datetime64) - - -##### -# DateOffset Tests -##### -_ApplyCases = List[Tuple[BaseOffset, Dict[datetime, datetime]]] - - -class Base: - _offset: Optional[Type[DateOffset]] = None - d = Timestamp(datetime(2008, 1, 2)) - - timezones = [ - None, - "UTC", - "Asia/Tokyo", - "US/Eastern", - "dateutil/Asia/Tokyo", - "dateutil/US/Pacific", - ] - - def _get_offset(self, klass, value=1, normalize=False): - # create instance from offset class - if klass is FY5253: - klass = klass( - n=value, - startingMonth=1, - weekday=1, - variation="last", - normalize=normalize, - ) - elif klass is FY5253Quarter: - klass = klass( - n=value, - startingMonth=1, - weekday=1, - qtr_with_extra_week=1, - variation="last", - normalize=normalize, - ) - elif klass is LastWeekOfMonth: - klass = klass(n=value, weekday=5, normalize=normalize) - elif klass is WeekOfMonth: - klass = klass(n=value, week=1, weekday=5, normalize=normalize) - elif klass is Week: - klass = klass(n=value, weekday=5, normalize=normalize) - elif klass is DateOffset: - klass = klass(days=value, normalize=normalize) - else: - klass = klass(value, normalize=normalize) - return klass - - def test_apply_out_of_range(self, tz_naive_fixture): - tz = tz_naive_fixture - if self._offset is None: - return - - # try to create an out-of-bounds result timestamp; if we can't create - # the offset skip - try: - if self._offset in (BusinessHour, CustomBusinessHour): - # Using 10000 in BusinessHour fails in tz check because of DST - # difference - offset = self._get_offset(self._offset, value=100000) - else: - offset = self._get_offset(self._offset, value=10000) - - result = Timestamp("20080101") + offset - assert isinstance(result, datetime) - assert result.tzinfo is None - - # Check tz is preserved - t = Timestamp("20080101", tz=tz) - result = t + offset - assert isinstance(result, datetime) - assert t.tzinfo == result.tzinfo - - except OutOfBoundsDatetime: - pass - except (ValueError, KeyError): - # we are creating an invalid offset - # so ignore - pass - - def test_offsets_compare_equal(self): - # root cause of GH#456: __ne__ was not implemented - if self._offset is None: - return - offset1 = self._offset() - offset2 = self._offset() - assert not offset1 != offset2 - assert offset1 == offset2 - - def test_rsub(self): - if self._offset is None or not hasattr(self, "offset2"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset2 attr - return - assert self.d - self.offset2 == (-self.offset2).apply(self.d) - - def test_radd(self): - if self._offset is None or not hasattr(self, "offset2"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset2 attr - return - assert self.d + self.offset2 == self.offset2 + self.d - - def test_sub(self): - if self._offset is None or not hasattr(self, "offset2"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset2 attr - return - off = self.offset2 - msg = "Cannot subtract datetime from offset" - with pytest.raises(TypeError, match=msg): - off - self.d - - assert 2 * off - off == off - assert self.d - self.offset2 == self.d + self._offset(-2) - assert self.d - self.offset2 == self.d - (2 * off - off) - - def testMult1(self): - if self._offset is None or not hasattr(self, "offset1"): - # i.e. skip for TestCommon and YQM subclasses that do not have - # offset1 attr - return - assert self.d + 10 * self.offset1 == self.d + self._offset(10) - assert self.d + 5 * self.offset1 == self.d + self._offset(5) - - def testMult2(self): - if self._offset is None: - return - assert self.d + (-5 * self._offset(-10)) == self.d + self._offset(50) - assert self.d + (-3 * self._offset(-2)) == self.d + self._offset(6) - - def test_compare_str(self): - # GH#23524 - # comparing to strings that cannot be cast to DateOffsets should - # not raise for __eq__ or __ne__ - if self._offset is None: - return - off = self._get_offset(self._offset) - - assert not off == "infer" - assert off != "foo" - # Note: inequalities are only implemented for Tick subclasses; - # tests for this are in test_ticks - - -class TestCommon(Base): - # exected value created by Base._get_offset - # are applied to 2011/01/01 09:00 (Saturday) - # used for .apply and .rollforward - expecteds = { - "Day": Timestamp("2011-01-02 09:00:00"), - "DateOffset": Timestamp("2011-01-02 09:00:00"), - "BusinessDay": Timestamp("2011-01-03 09:00:00"), - "CustomBusinessDay": Timestamp("2011-01-03 09:00:00"), - "CustomBusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), - "CustomBusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), - "MonthBegin": Timestamp("2011-02-01 09:00:00"), - "BusinessMonthBegin": Timestamp("2011-01-03 09:00:00"), - "MonthEnd": Timestamp("2011-01-31 09:00:00"), - "SemiMonthEnd": Timestamp("2011-01-15 09:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 09:00:00"), - "BusinessMonthEnd": Timestamp("2011-01-31 09:00:00"), - "YearBegin": Timestamp("2012-01-01 09:00:00"), - "BYearBegin": Timestamp("2011-01-03 09:00:00"), - "YearEnd": Timestamp("2011-12-31 09:00:00"), - "BYearEnd": Timestamp("2011-12-30 09:00:00"), - "QuarterBegin": Timestamp("2011-03-01 09:00:00"), - "BQuarterBegin": Timestamp("2011-03-01 09:00:00"), - "QuarterEnd": Timestamp("2011-03-31 09:00:00"), - "BQuarterEnd": Timestamp("2011-03-31 09:00:00"), - "BusinessHour": Timestamp("2011-01-03 10:00:00"), - "CustomBusinessHour": Timestamp("2011-01-03 10:00:00"), - "WeekOfMonth": Timestamp("2011-01-08 09:00:00"), - "LastWeekOfMonth": Timestamp("2011-01-29 09:00:00"), - "FY5253Quarter": Timestamp("2011-01-25 09:00:00"), - "FY5253": Timestamp("2011-01-25 09:00:00"), - "Week": Timestamp("2011-01-08 09:00:00"), - "Easter": Timestamp("2011-04-24 09:00:00"), - "Hour": Timestamp("2011-01-01 10:00:00"), - "Minute": Timestamp("2011-01-01 09:01:00"), - "Second": Timestamp("2011-01-01 09:00:01"), - "Milli": Timestamp("2011-01-01 09:00:00.001000"), - "Micro": Timestamp("2011-01-01 09:00:00.000001"), - "Nano": Timestamp(np_datetime64_compat("2011-01-01T09:00:00.000000001Z")), - } - - def test_immutable(self, offset_types): - # GH#21341 check that __setattr__ raises - offset = self._get_offset(offset_types) - with pytest.raises(AttributeError): - offset.normalize = True - with pytest.raises(AttributeError): - offset.n = 91 - - def test_return_type(self, offset_types): - offset = self._get_offset(offset_types) - - # make sure that we are returning a Timestamp - result = Timestamp("20080101") + offset - assert isinstance(result, Timestamp) - - # make sure that we are returning NaT - assert NaT + offset is NaT - assert offset + NaT is NaT - - assert NaT - offset is NaT - assert (-offset).apply(NaT) is NaT - - def test_offset_n(self, offset_types): - offset = self._get_offset(offset_types) - assert offset.n == 1 - - neg_offset = offset * -1 - assert neg_offset.n == -1 - - mul_offset = offset * 3 - assert mul_offset.n == 3 - - def test_offset_timedelta64_arg(self, offset_types): - # check that offset._validate_n raises TypeError on a timedelt64 - # object - off = self._get_offset(offset_types) - - td64 = np.timedelta64(4567, "s") - with pytest.raises(TypeError, match="argument must be an integer"): - type(off)(n=td64, **off.kwds) - - def test_offset_mul_ndarray(self, offset_types): - off = self._get_offset(offset_types) - - expected = np.array([[off, off * 2], [off * 3, off * 4]]) - - result = np.array([[1, 2], [3, 4]]) * off - tm.assert_numpy_array_equal(result, expected) - - result = off * np.array([[1, 2], [3, 4]]) - tm.assert_numpy_array_equal(result, expected) - - def test_offset_freqstr(self, offset_types): - offset = self._get_offset(offset_types) - - freqstr = offset.freqstr - if freqstr not in ("", "", "LWOM-SAT"): - code = get_offset(freqstr) - assert offset.rule_code == code - - def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=False): - - if normalize and issubclass(offset, Tick): - # normalize=True disallowed for Tick subclasses GH#21427 - return - - offset_s = self._get_offset(offset, normalize=normalize) - func = getattr(offset_s, funcname) - - result = func(dt) - assert isinstance(result, Timestamp) - assert result == expected - - result = func(Timestamp(dt)) - assert isinstance(result, Timestamp) - assert result == expected - - # see gh-14101 - exp_warning = None - ts = Timestamp(dt) + Nano(5) - - if ( - type(offset_s).__name__ == "DateOffset" - and (funcname == "apply" or normalize) - and ts.nanosecond > 0 - ): - exp_warning = UserWarning - - # test nanosecond is preserved - with tm.assert_produces_warning(exp_warning, check_stacklevel=False): - result = func(ts) - assert isinstance(result, Timestamp) - if normalize is False: - assert result == expected + Nano(5) - else: - assert result == expected - - if isinstance(dt, np.datetime64): - # test tz when input is datetime or Timestamp - return - - for tz in self.timezones: - expected_localize = expected.tz_localize(tz) - tz_obj = timezones.maybe_get_tz(tz) - dt_tz = conversion.localize_pydatetime(dt, tz_obj) - - result = func(dt_tz) - assert isinstance(result, Timestamp) - assert result == expected_localize - - result = func(Timestamp(dt, tz=tz)) - assert isinstance(result, Timestamp) - assert result == expected_localize - - # see gh-14101 - exp_warning = None - ts = Timestamp(dt, tz=tz) + Nano(5) - - if ( - type(offset_s).__name__ == "DateOffset" - and (funcname == "apply" or normalize) - and ts.nanosecond > 0 - ): - exp_warning = UserWarning - - # test nanosecond is preserved - with tm.assert_produces_warning(exp_warning, check_stacklevel=False): - result = func(ts) - assert isinstance(result, Timestamp) - if normalize is False: - assert result == expected_localize + Nano(5) - else: - assert result == expected_localize - - def test_apply(self, offset_types): - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") - - for dt in [sdt, ndt]: - expected = self.expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "apply", dt, expected) - - expected = Timestamp(expected.date()) - self._check_offsetfunc_works( - offset_types, "apply", dt, expected, normalize=True - ) - - def test_rollforward(self, offset_types): - expecteds = self.expecteds.copy() - - # result will not be changed if the target is on the offset - no_changes = [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ] - for n in no_changes: - expecteds[n] = Timestamp("2011/01/01 09:00") - - expecteds["BusinessHour"] = Timestamp("2011-01-03 09:00:00") - expecteds["CustomBusinessHour"] = Timestamp("2011-01-03 09:00:00") - - # but be changed when normalize=True - norm_expected = expecteds.copy() - for k in norm_expected: - norm_expected[k] = Timestamp(norm_expected[k].date()) - - normalized = { - "Day": Timestamp("2011-01-02 00:00:00"), - "DateOffset": Timestamp("2011-01-02 00:00:00"), - "MonthBegin": Timestamp("2011-02-01 00:00:00"), - "SemiMonthBegin": Timestamp("2011-01-15 00:00:00"), - "YearBegin": Timestamp("2012-01-01 00:00:00"), - "Week": Timestamp("2011-01-08 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") - - for dt in [sdt, ndt]: - expected = expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "rollforward", dt, expected) - expected = norm_expected[offset_types.__name__] - self._check_offsetfunc_works( - offset_types, "rollforward", dt, expected, normalize=True - ) - - def test_rollback(self, offset_types): - expecteds = { - "BusinessDay": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessDay": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), - "CustomBusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), - "BusinessMonthBegin": Timestamp("2010-12-01 09:00:00"), - "MonthEnd": Timestamp("2010-12-31 09:00:00"), - "SemiMonthEnd": Timestamp("2010-12-31 09:00:00"), - "BusinessMonthEnd": Timestamp("2010-12-31 09:00:00"), - "BYearBegin": Timestamp("2010-01-01 09:00:00"), - "YearEnd": Timestamp("2010-12-31 09:00:00"), - "BYearEnd": Timestamp("2010-12-31 09:00:00"), - "QuarterBegin": Timestamp("2010-12-01 09:00:00"), - "BQuarterBegin": Timestamp("2010-12-01 09:00:00"), - "QuarterEnd": Timestamp("2010-12-31 09:00:00"), - "BQuarterEnd": Timestamp("2010-12-31 09:00:00"), - "BusinessHour": Timestamp("2010-12-31 17:00:00"), - "CustomBusinessHour": Timestamp("2010-12-31 17:00:00"), - "WeekOfMonth": Timestamp("2010-12-11 09:00:00"), - "LastWeekOfMonth": Timestamp("2010-12-25 09:00:00"), - "FY5253Quarter": Timestamp("2010-10-26 09:00:00"), - "FY5253": Timestamp("2010-01-26 09:00:00"), - "Easter": Timestamp("2010-04-04 09:00:00"), - } - - # result will not be changed if the target is on the offset - for n in [ - "Day", - "MonthBegin", - "SemiMonthBegin", - "YearBegin", - "Week", - "Hour", - "Minute", - "Second", - "Milli", - "Micro", - "Nano", - "DateOffset", - ]: - expecteds[n] = Timestamp("2011/01/01 09:00") - - # but be changed when normalize=True - norm_expected = expecteds.copy() - for k in norm_expected: - norm_expected[k] = Timestamp(norm_expected[k].date()) - - normalized = { - "Day": Timestamp("2010-12-31 00:00:00"), - "DateOffset": Timestamp("2010-12-31 00:00:00"), - "MonthBegin": Timestamp("2010-12-01 00:00:00"), - "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), - "YearBegin": Timestamp("2010-01-01 00:00:00"), - "Week": Timestamp("2010-12-25 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - - sdt = datetime(2011, 1, 1, 9, 0) - ndt = np_datetime64_compat("2011-01-01 09:00Z") - - for dt in [sdt, ndt]: - expected = expecteds[offset_types.__name__] - self._check_offsetfunc_works(offset_types, "rollback", dt, expected) - - expected = norm_expected[offset_types.__name__] - self._check_offsetfunc_works( - offset_types, "rollback", dt, expected, normalize=True - ) - - def test_onOffset(self, offset_types): - dt = self.expecteds[offset_types.__name__] - offset_s = self._get_offset(offset_types) - assert offset_s.onOffset(dt) - - # when normalize=True, onOffset checks time is 00:00:00 - if issubclass(offset_types, Tick): - # normalize=True disallowed for Tick subclasses GH#21427 - return - offset_n = self._get_offset(offset_types, normalize=True) - assert not offset_n.onOffset(dt) - - if offset_types in (BusinessHour, CustomBusinessHour): - # In default BusinessHour (9:00-17:00), normalized time - # cannot be in business hour range - return - date = datetime(dt.year, dt.month, dt.day) - assert offset_n.onOffset(date) - - def test_add(self, offset_types, tz_naive_fixture): - tz = tz_naive_fixture - dt = datetime(2011, 1, 1, 9, 0) - - offset_s = self._get_offset(offset_types) - expected = self.expecteds[offset_types.__name__] - - result_dt = dt + offset_s - result_ts = Timestamp(dt) + offset_s - for result in [result_dt, result_ts]: - assert isinstance(result, Timestamp) - assert result == expected - - expected_localize = expected.tz_localize(tz) - result = Timestamp(dt, tz=tz) + offset_s - assert isinstance(result, Timestamp) - assert result == expected_localize - - # normalize=True, disallowed for Tick subclasses GH#21427 - if issubclass(offset_types, Tick): - return - offset_s = self._get_offset(offset_types, normalize=True) - expected = Timestamp(expected.date()) - - result_dt = dt + offset_s - result_ts = Timestamp(dt) + offset_s - for result in [result_dt, result_ts]: - assert isinstance(result, Timestamp) - assert result == expected - - expected_localize = expected.tz_localize(tz) - result = Timestamp(dt, tz=tz) + offset_s - assert isinstance(result, Timestamp) - assert result == expected_localize - - def test_pickle_v0_15_2(self, datapath): - offsets = { - "DateOffset": DateOffset(years=1), - "MonthBegin": MonthBegin(1), - "Day": Day(1), - "YearBegin": YearBegin(1), - "Week": Week(1), - } - - pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle") - # This code was executed once on v0.15.2 to generate the pickle: - # with open(pickle_path, 'wb') as f: pickle.dump(offsets, f) - # - tm.assert_dict_equal(offsets, read_pickle(pickle_path)) - - -class TestDateOffset(Base): - def setup_method(self, method): - self.d = Timestamp(datetime(2008, 1, 2)) - _offset_map.clear() - - def test_repr(self): - repr(DateOffset()) - repr(DateOffset(2)) - repr(2 * DateOffset()) - repr(2 * DateOffset(months=2)) - - def test_mul(self): - assert DateOffset(2) == 2 * DateOffset(1) - assert DateOffset(2) == DateOffset(1) * 2 - - def test_constructor(self): - - assert (self.d + DateOffset(months=2)) == datetime(2008, 3, 2) - assert (self.d - DateOffset(months=2)) == datetime(2007, 11, 2) - - assert (self.d + DateOffset(2)) == datetime(2008, 1, 4) - - assert not DateOffset(2).isAnchored() - assert DateOffset(1).isAnchored() - - d = datetime(2008, 1, 31) - assert (d + DateOffset(months=1)) == datetime(2008, 2, 29) - - def test_copy(self): - assert DateOffset(months=2).copy() == DateOffset(months=2) - - def test_eq(self): - offset1 = DateOffset(days=1) - offset2 = DateOffset(days=365) - - assert offset1 != offset2 - - -class TestBusinessDay(Base): - _offset = BDay - - def setup_method(self, method): - self.d = datetime(2008, 1, 1) - - self.offset = BDay() - self.offset1 = self.offset - self.offset2 = BDay(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 * BusinessDays>" - - if compat.PY37: - expected = "" - else: - 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_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): - assert self.offset2(self.d) == datetime(2008, 1, 3) - - def testRollback1(self): - assert BDay(10).rollback(self.d) == self.d - - def testRollback2(self): - assert BDay(10).rollback(datetime(2008, 1, 5)) == datetime(2008, 1, 4) - - def testRollforward1(self): - assert BDay(10).rollforward(self.d) == self.d - - def testRollforward2(self): - assert BDay(10).rollforward(datetime(2008, 1, 5)) == datetime(2008, 1, 7) - - def test_roll_date_object(self): - offset = BDay() - - 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) - - def test_onOffset(self): - tests = [ - (BDay(), datetime(2008, 1, 1), True), - (BDay(), datetime(2008, 1, 5), False), - ] - - for offset, d, expected in tests: - assert_onOffset(offset, d, expected) - - apply_cases: _ApplyCases = [] - apply_cases.append( - ( - BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - 2 * BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - -BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - -2 * BDay(), - { - 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), - }, - ) - ) - - apply_cases.append( - ( - BDay(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 + BDay(10) - assert result == datetime(2012, 11, 6) - - result = dt + BDay(100) - BDay(100) - assert result == dt - - off = BDay() * 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 - - off = BDay() * 10 - rs = datetime(2014, 1, 5) + off # see #5890 - xp = datetime(2014, 1, 17) - assert rs == xp - - 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 TestBusinessHour(Base): - _offset = BusinessHour - - def setup_method(self, method): - self.d = datetime(2014, 7, 1, 10, 00) - - self.offset1 = BusinessHour() - self.offset2 = BusinessHour(n=3) - - self.offset3 = BusinessHour(n=-1) - self.offset4 = BusinessHour(n=-4) - - from datetime import time as dt_time - - self.offset5 = BusinessHour(start=dt_time(11, 0), end=dt_time(14, 30)) - self.offset6 = BusinessHour(start="20:00", end="05:00") - self.offset7 = BusinessHour(n=-2, start=dt_time(21, 30), end=dt_time(6, 30)) - self.offset8 = BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]) - self.offset9 = BusinessHour( - n=3, start=["09:00", "22:00"], end=["13:00", "03:00"] - ) - self.offset10 = BusinessHour( - n=-1, start=["23:00", "13:00"], end=["02:00", "17:00"] - ) - - @pytest.mark.parametrize( - "start,end,match", - [ - ( - dt_time(11, 0, 5), - "17:00", - "time data must be specified only with hour and minute", - ), - ("AAA", "17:00", "time data must match '%H:%M' format"), - ("14:00:05", "17:00", "time data must match '%H:%M' format"), - ([], "17:00", "Must include at least 1 start time"), - ("09:00", [], "Must include at least 1 end time"), - ( - ["09:00", "11:00"], - "17:00", - "number of starting time and ending time must be the same", - ), - ( - ["09:00", "11:00"], - ["10:00"], - "number of starting time and ending time must be the same", - ), - ( - ["09:00", "11:00"], - ["12:00", "20:00"], - r"invalid starting and ending time\(s\): opening hours should not " - "touch or overlap with one another", - ), - ( - ["12:00", "20:00"], - ["09:00", "11:00"], - r"invalid starting and ending time\(s\): opening hours should not " - "touch or overlap with one another", - ), - ], - ) - def test_constructor_errors(self, start, end, match): - with pytest.raises(ValueError, match=match): - BusinessHour(start=start, end=end) - - 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.offset1) == "" - assert repr(self.offset2) == "<3 * BusinessHours: BH=09:00-17:00>" - assert repr(self.offset3) == "<-1 * BusinessHour: BH=09:00-17:00>" - assert repr(self.offset4) == "<-4 * BusinessHours: BH=09:00-17:00>" - - assert repr(self.offset5) == "" - assert repr(self.offset6) == "" - assert repr(self.offset7) == "<-2 * BusinessHours: BH=21:30-06:30>" - assert repr(self.offset8) == "" - assert repr(self.offset9) == "<3 * BusinessHours: BH=09:00-13:00,22:00-03:00>" - assert repr(self.offset10) == "<-1 * BusinessHour: BH=13:00-17:00,23:00-02:00>" - - def test_with_offset(self): - expected = Timestamp("2014-07-01 13:00") - - assert self.d + BusinessHour() * 3 == expected - assert self.d + BusinessHour(n=3) == expected - - @pytest.mark.parametrize( - "offset_name", - ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], - ) - def test_eq_attribute(self, offset_name): - offset = getattr(self, offset_name) - assert offset == offset - - @pytest.mark.parametrize( - "offset1,offset2", - [ - (BusinessHour(start="09:00"), BusinessHour()), - ( - BusinessHour(start=["23:00", "13:00"], end=["12:00", "17:00"]), - BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), - ), - ], - ) - def test_eq(self, offset1, offset2): - assert offset1 == offset2 - - @pytest.mark.parametrize( - "offset1,offset2", - [ - (BusinessHour(), BusinessHour(-1)), - (BusinessHour(start="09:00"), BusinessHour(start="09:01")), - ( - BusinessHour(start="09:00", end="17:00"), - BusinessHour(start="17:00", end="09:01"), - ), - ( - BusinessHour(start=["13:00", "23:00"], end=["18:00", "07:00"]), - BusinessHour(start=["13:00", "23:00"], end=["17:00", "12:00"]), - ), - ], - ) - def test_neq(self, offset1, offset2): - assert offset1 != offset2 - - @pytest.mark.parametrize( - "offset_name", - ["offset1", "offset2", "offset3", "offset4", "offset8", "offset9", "offset10"], - ) - def test_hash(self, offset_name): - offset = getattr(self, offset_name) - assert offset == offset - - def test_call(self): - assert self.offset1(self.d) == datetime(2014, 7, 1, 11) - assert self.offset2(self.d) == datetime(2014, 7, 1, 13) - assert self.offset3(self.d) == datetime(2014, 6, 30, 17) - assert self.offset4(self.d) == datetime(2014, 6, 30, 14) - assert self.offset8(self.d) == datetime(2014, 7, 1, 11) - assert self.offset9(self.d) == datetime(2014, 7, 1, 22) - assert self.offset10(self.d) == datetime(2014, 7, 1, 1) - - def test_sub(self): - # we have to override test_sub here because self.offset2 is not - # defined as self._offset(2) - off = self.offset2 - msg = "Cannot subtract datetime from offset" - with pytest.raises(TypeError, match=msg): - off - self.d - assert 2 * off - off == off - - assert self.d - self.offset2 == self.d + self._offset(-3) - - def testRollback1(self): - assert self.offset1.rollback(self.d) == self.d - assert self.offset2.rollback(self.d) == self.d - assert self.offset3.rollback(self.d) == self.d - assert self.offset4.rollback(self.d) == self.d - assert self.offset5.rollback(self.d) == datetime(2014, 6, 30, 14, 30) - assert self.offset6.rollback(self.d) == datetime(2014, 7, 1, 5, 0) - assert self.offset7.rollback(self.d) == datetime(2014, 7, 1, 6, 30) - assert self.offset8.rollback(self.d) == self.d - assert self.offset9.rollback(self.d) == self.d - assert self.offset10.rollback(self.d) == datetime(2014, 7, 1, 2) - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset2.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset3.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset4.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset5.rollback(d) == datetime(2014, 6, 30, 14, 30) - assert self.offset6.rollback(d) == d - assert self.offset7.rollback(d) == d - assert self.offset8.rollback(d) == datetime(2014, 6, 30, 17) - assert self.offset9.rollback(d) == d - assert self.offset10.rollback(d) == d - - assert self._offset(5).rollback(self.d) == self.d - - def testRollback2(self): - assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( - 2014, 7, 4, 17, 0 - ) - - def testRollforward1(self): - assert self.offset1.rollforward(self.d) == self.d - assert self.offset2.rollforward(self.d) == self.d - assert self.offset3.rollforward(self.d) == self.d - assert self.offset4.rollforward(self.d) == self.d - assert self.offset5.rollforward(self.d) == datetime(2014, 7, 1, 11, 0) - assert self.offset6.rollforward(self.d) == datetime(2014, 7, 1, 20, 0) - assert self.offset7.rollforward(self.d) == datetime(2014, 7, 1, 21, 30) - assert self.offset8.rollforward(self.d) == self.d - assert self.offset9.rollforward(self.d) == self.d - assert self.offset10.rollforward(self.d) == datetime(2014, 7, 1, 13) - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset3.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset4.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset5.rollforward(d) == datetime(2014, 7, 1, 11) - assert self.offset6.rollforward(d) == d - assert self.offset7.rollforward(d) == d - assert self.offset8.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset9.rollforward(d) == d - assert self.offset10.rollforward(d) == d - - assert self._offset(5).rollforward(self.d) == self.d - - def testRollforward2(self): - assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( - 2014, 7, 7, 9 - ) - - def test_roll_date_object(self): - offset = BusinessHour() - - dt = datetime(2014, 7, 6, 15, 0) - - result = offset.rollback(dt) - assert result == datetime(2014, 7, 4, 17) - - result = offset.rollforward(dt) - assert result == datetime(2014, 7, 7, 9) - - normalize_cases = [] - normalize_cases.append( - ( - BusinessHour(normalize=True), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 1, 0): datetime(2014, 7, 1), - datetime(2014, 7, 4, 15): datetime(2014, 7, 4), - datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 7), - datetime(2014, 7, 6, 10): datetime(2014, 7, 7), - }, - ) - ) - - normalize_cases.append( - ( - BusinessHour(-1, normalize=True), - { - datetime(2014, 7, 1, 8): datetime(2014, 6, 30), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1), - datetime(2014, 7, 1, 10): datetime(2014, 6, 30), - datetime(2014, 7, 1, 0): datetime(2014, 6, 30), - datetime(2014, 7, 7, 10): datetime(2014, 7, 4), - datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 4), - datetime(2014, 7, 6, 10): datetime(2014, 7, 4), - }, - ) - ) - - normalize_cases.append( - ( - BusinessHour(1, normalize=True, start="17:00", end="04:00"), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 2, 2): datetime(2014, 7, 2), - datetime(2014, 7, 2, 3): datetime(2014, 7, 2), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5), - datetime(2014, 7, 5, 2): datetime(2014, 7, 5), - datetime(2014, 7, 7, 2): datetime(2014, 7, 7), - datetime(2014, 7, 7, 17): datetime(2014, 7, 7), - }, - ) - ) - - @pytest.mark.parametrize("case", normalize_cases) - def test_normalize(self, case): - offset, cases = case - for dt, expected in cases.items(): - assert offset.apply(dt) == expected - - on_offset_cases = [] - on_offset_cases.append( - ( - BusinessHour(), - { - datetime(2014, 7, 1, 9): True, - datetime(2014, 7, 1, 8, 59): False, - datetime(2014, 7, 1, 8): False, - datetime(2014, 7, 1, 17): True, - datetime(2014, 7, 1, 17, 1): False, - datetime(2014, 7, 1, 18): False, - datetime(2014, 7, 5, 9): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start="10:00", end="15:00"), - { - datetime(2014, 7, 1, 9): False, - datetime(2014, 7, 1, 10): True, - datetime(2014, 7, 1, 15): True, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 9, 0): False, - datetime(2014, 7, 1, 10, 0): False, - datetime(2014, 7, 1, 15): False, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12, 0): False, - datetime(2014, 7, 6, 12, 0): False, - datetime(2014, 7, 1, 19, 0): True, - datetime(2014, 7, 2, 0, 0): True, - datetime(2014, 7, 4, 23): True, - datetime(2014, 7, 5, 1): True, - datetime(2014, 7, 5, 5, 0): True, - datetime(2014, 7, 6, 23, 0): False, - datetime(2014, 7, 7, 3, 0): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start=["09:00", "13:00"], end=["12:00", "17:00"]), - { - datetime(2014, 7, 1, 9): True, - datetime(2014, 7, 1, 8, 59): False, - datetime(2014, 7, 1, 8): False, - datetime(2014, 7, 1, 17): True, - datetime(2014, 7, 1, 17, 1): False, - datetime(2014, 7, 1, 18): False, - datetime(2014, 7, 5, 9): False, - datetime(2014, 7, 6, 12): False, - datetime(2014, 7, 1, 12, 30): False, - }, - ) - ) - - on_offset_cases.append( - ( - BusinessHour(start=["19:00", "23:00"], end=["21:00", "05:00"]), - { - datetime(2014, 7, 1, 9, 0): False, - datetime(2014, 7, 1, 10, 0): False, - datetime(2014, 7, 1, 15): False, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12, 0): False, - datetime(2014, 7, 6, 12, 0): False, - datetime(2014, 7, 1, 19, 0): True, - datetime(2014, 7, 2, 0, 0): True, - datetime(2014, 7, 4, 23): True, - datetime(2014, 7, 5, 1): True, - datetime(2014, 7, 5, 5, 0): True, - datetime(2014, 7, 6, 23, 0): False, - datetime(2014, 7, 7, 3, 0): False, - datetime(2014, 7, 4, 22): False, - }, - ) - ) - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, cases = case - for dt, expected in cases.items(): - assert offset.onOffset(dt) == expected - - opening_time_cases = [] - # opening time should be affected by sign of n, not by n's value and - # end - opening_time_cases.append( - ( - [ - BusinessHour(), - BusinessHour(n=2), - BusinessHour(n=4), - BusinessHour(end="10:00"), - BusinessHour(n=2, end="4:00"), - BusinessHour(n=4, end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 9), - ), - # if timestamp is on opening time, next opening time is - # as it is - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 3, 9), - datetime(2014, 7, 2, 9), - ), - # 2014-07-05 is saturday - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 9), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 8, 9), - datetime(2014, 7, 7, 9), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start="11:15"), - BusinessHour(n=2, start="11:15"), - BusinessHour(n=3, start="11:15"), - BusinessHour(start="11:15", end="10:00"), - BusinessHour(n=2, start="11:15", end="4:00"), - BusinessHour(n=3, start="11:15", end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 11, 15), - datetime(2014, 6, 30, 11, 15), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 11, 15), - ), - datetime(2014, 7, 2, 11, 15): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 2, 11, 15, 1): ( - datetime(2014, 7, 3, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 11, 15), - datetime(2014, 7, 3, 11, 15), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 11, 15), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(-1), - BusinessHour(n=-2), - BusinessHour(n=-4), - BusinessHour(n=-1, end="10:00"), - BusinessHour(n=-2, end="4:00"), - BusinessHour(n=-4, end="15:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 1, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 9), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 9), - datetime(2014, 7, 3, 9), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 9): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 7, 9), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 9), - datetime(2014, 7, 8, 9), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start="17:00", end="05:00"), - BusinessHour(n=3, start="17:00", end="03:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 17), - datetime(2014, 6, 30, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 4, 17): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 3, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 7, 17, 1): ( - datetime(2014, 7, 8, 17), - datetime(2014, 7, 7, 17), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(-1, start="17:00", end="05:00"), - BusinessHour(n=-2, start="17:00", end="03:00"), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 16, 59): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 3, 17), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 17), - ), - datetime(2014, 7, 7, 18): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 8, 17), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(start=["11:15", "15:00"], end=["13:00", "20:00"]), - BusinessHour(n=3, start=["11:15", "15:00"], end=["12:00", "20:00"]), - BusinessHour(start=["11:15", "15:00"], end=["13:00", "17:00"]), - BusinessHour(n=2, start=["11:15", "15:00"], end=["12:00", "03:00"]), - BusinessHour(n=3, start=["11:15", "15:00"], end=["13:00", "16:00"]), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 11, 15), - datetime(2014, 6, 30, 15), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 10): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 1, 15), - ), - datetime(2014, 7, 2, 11, 15): ( - datetime(2014, 7, 2, 11, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 2, 11, 15, 1): ( - datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 11, 15), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 11, 15), - datetime(2014, 7, 3, 15), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 9, 1): ( - datetime(2014, 7, 7, 11, 15), - datetime(2014, 7, 4, 15), - ), - datetime(2014, 7, 7, 12): ( - datetime(2014, 7, 7, 15), - datetime(2014, 7, 7, 11, 15), - ), - }, - ) - ) - - opening_time_cases.append( - ( - [ - BusinessHour(n=-1, start=["17:00", "08:00"], end=["05:00", "10:00"]), - BusinessHour(n=-2, start=["08:00", "17:00"], end=["10:00", "03:00"]), - ], - { - datetime(2014, 7, 1, 11): ( - datetime(2014, 7, 1, 8), - datetime(2014, 7, 1, 17), - ), - datetime(2014, 7, 1, 18): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 1, 23): ( - datetime(2014, 7, 1, 17), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 2, 8): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 8), - ), - datetime(2014, 7, 2, 9): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 2, 16, 59): ( - datetime(2014, 7, 2, 8), - datetime(2014, 7, 2, 17), - ), - datetime(2014, 7, 5, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 4, 10): ( - datetime(2014, 7, 4, 8), - datetime(2014, 7, 4, 17), - ), - datetime(2014, 7, 4, 23): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 6, 10): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 7, 5): ( - datetime(2014, 7, 4, 17), - datetime(2014, 7, 7, 8), - ), - datetime(2014, 7, 7, 18): ( - datetime(2014, 7, 7, 17), - datetime(2014, 7, 8, 8), - ), - }, - ) - ) - - @pytest.mark.parametrize("case", opening_time_cases) - def test_opening_time(self, case): - _offsets, cases = case - for offset in _offsets: - for dt, (exp_next, exp_prev) in cases.items(): - assert offset._next_opening_time(dt) == exp_next - assert offset._prev_opening_time(dt) == exp_prev - - apply_cases = [] - apply_cases.append( - ( - BusinessHour(), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 2, 9, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 12), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(4), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(-1), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 10), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 10): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 15, 30, 15), - datetime(2014, 7, 1, 9, 30, 15): datetime(2014, 6, 30, 16, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 5): datetime(2014, 6, 30, 16), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 10), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 16), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 16), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 16), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 16), - datetime(2014, 7, 7, 9): datetime(2014, 7, 4, 16), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 16, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 16, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(-4), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 15), - datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 13), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 13, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 13, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(start="13:00", end="16:00"), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 13), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 14), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 14), - datetime(2014, 7, 1, 15, 30, 15): datetime(2014, 7, 2, 13, 30, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 14), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=2, start="13:00", end="16:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 14): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), - datetime(2014, 7, 2, 14, 30): datetime(2014, 7, 3, 13, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 14, 30): datetime(2014, 7, 7, 13, 30), - datetime(2014, 7, 4, 14, 30, 30): datetime(2014, 7, 7, 13, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start="13:00", end="16:00"), - { - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 14): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 15): datetime(2014, 7, 2, 14), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 16): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 13, 30, 15): datetime(2014, 7, 1, 15, 30, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 15), - datetime(2014, 7, 7, 11): datetime(2014, 7, 4, 15), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-3, start="10:00", end="16:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 11), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 13), - datetime(2014, 7, 2, 13): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 13), - datetime(2014, 7, 2, 11, 30): datetime(2014, 7, 1, 14, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 13), - datetime(2014, 7, 4, 10): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 16): datetime(2014, 7, 4, 13), - datetime(2014, 7, 4, 12, 30): datetime(2014, 7, 3, 15, 30), - datetime(2014, 7, 4, 12, 30, 30): datetime(2014, 7, 3, 15, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 20), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 20), - datetime(2014, 7, 2, 4, 30): datetime(2014, 7, 2, 19, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 1), - datetime(2014, 7, 4, 10): datetime(2014, 7, 4, 20), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5, 0), - datetime(2014, 7, 5, 0): datetime(2014, 7, 5, 1), - datetime(2014, 7, 5, 4): datetime(2014, 7, 7, 19), - datetime(2014, 7, 5, 4, 30): datetime(2014, 7, 7, 19, 30), - datetime(2014, 7, 5, 4, 30, 30): datetime(2014, 7, 7, 19, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start="19:00", end="05:00"), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), - datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), - datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), - datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), - datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 3), - datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 5, 4, 30), - datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 5, 4, 30, 30), - }, - ) - ) - - # long business hours (see gh-26381) - apply_cases.append( - ( - BusinessHour(n=4, start="00:00", end="23:00"), - { - datetime(2014, 7, 3, 22): datetime(2014, 7, 4, 3), - datetime(2014, 7, 4, 22): datetime(2014, 7, 7, 3), - datetime(2014, 7, 3, 22, 30): datetime(2014, 7, 4, 3, 30), - datetime(2014, 7, 3, 22, 20): datetime(2014, 7, 4, 3, 20), - datetime(2014, 7, 4, 22, 30, 30): datetime(2014, 7, 7, 3, 30, 30), - datetime(2014, 7, 4, 22, 30, 20): datetime(2014, 7, 7, 3, 30, 20), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-4, start="00:00", end="23:00"), - { - datetime(2014, 7, 4, 3): datetime(2014, 7, 3, 22), - datetime(2014, 7, 7, 3): datetime(2014, 7, 4, 22), - datetime(2014, 7, 4, 3, 30): datetime(2014, 7, 3, 22, 30), - datetime(2014, 7, 4, 3, 20): datetime(2014, 7, 3, 22, 20), - datetime(2014, 7, 7, 3, 30, 30): datetime(2014, 7, 4, 22, 30, 30), - datetime(2014, 7, 7, 3, 30, 20): datetime(2014, 7, 4, 22, 30, 20), - }, - ) - ) - - # multiple business hours - apply_cases.append( - ( - BusinessHour(start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 17), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 1, 17, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 9), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 14), - # out of business hours - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 15), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 9), - datetime(2014, 7, 4, 17, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 17, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=4, start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 17), - datetime(2014, 7, 1, 13): datetime(2014, 7, 2, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 2, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 2, 11), - datetime(2014, 7, 1, 17): datetime(2014, 7, 2, 14), - datetime(2014, 7, 2, 11): datetime(2014, 7, 2, 17), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 15), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 15), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 15), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 15), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 15), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 14), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 11, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 11, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-4, start=["09:00", "14:00"], end=["12:00", "18:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 30, 16), - datetime(2014, 7, 1, 13): datetime(2014, 6, 30, 17), - datetime(2014, 7, 1, 15): datetime(2014, 6, 30, 18), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1, 10), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 11), - datetime(2014, 7, 2, 11): datetime(2014, 7, 1, 16), - datetime(2014, 7, 2, 8): datetime(2014, 7, 1, 12), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 12), - datetime(2014, 7, 2, 23): datetime(2014, 7, 2, 12), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 12), - datetime(2014, 7, 5, 15): datetime(2014, 7, 4, 12), - datetime(2014, 7, 4, 18): datetime(2014, 7, 4, 12), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 4, 14, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 4, 14, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - BusinessHour(n=-1, start=["19:00", "03:00"], end=["01:00", "05:00"]), - { - datetime(2014, 7, 1, 17): datetime(2014, 7, 1, 4), - datetime(2014, 7, 2, 14): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 8): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 13): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 20): datetime(2014, 7, 2, 5), - datetime(2014, 7, 2, 19): datetime(2014, 7, 2, 4), - datetime(2014, 7, 2, 4): datetime(2014, 7, 2, 1), - datetime(2014, 7, 2, 19, 30): datetime(2014, 7, 2, 4, 30), - datetime(2014, 7, 3, 0): datetime(2014, 7, 2, 23), - datetime(2014, 7, 3, 6): datetime(2014, 7, 3, 4), - datetime(2014, 7, 4, 23): datetime(2014, 7, 4, 22), - datetime(2014, 7, 5, 0): datetime(2014, 7, 4, 23), - datetime(2014, 7, 5, 4): datetime(2014, 7, 5, 0), - datetime(2014, 7, 7, 3, 30): datetime(2014, 7, 5, 0, 30), - datetime(2014, 7, 7, 19, 30): datetime(2014, 7, 7, 4, 30), - datetime(2014, 7, 7, 19, 30, 30): datetime(2014, 7, 7, 4, 30, 30), - }, - ) - ) - - @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) - - apply_large_n_cases = [] - # A week later - apply_large_n_cases.append( - ( - BusinessHour(40), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 8, 11), - datetime(2014, 7, 1, 13): datetime(2014, 7, 8, 13), - datetime(2014, 7, 1, 15): datetime(2014, 7, 8, 15), - datetime(2014, 7, 1, 16): datetime(2014, 7, 8, 16), - datetime(2014, 7, 1, 17): datetime(2014, 7, 9, 9), - datetime(2014, 7, 2, 11): datetime(2014, 7, 9, 11), - datetime(2014, 7, 2, 8): datetime(2014, 7, 9, 9), - datetime(2014, 7, 2, 19): datetime(2014, 7, 10, 9), - datetime(2014, 7, 2, 23): datetime(2014, 7, 10, 9), - datetime(2014, 7, 3, 0): datetime(2014, 7, 10, 9), - datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 9), - datetime(2014, 7, 4, 18): datetime(2014, 7, 14, 9), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 14, 9, 30), - datetime(2014, 7, 7, 9, 30, 30): datetime(2014, 7, 14, 9, 30, 30), - }, - ) - ) - - # 3 days and 1 hour before - apply_large_n_cases.append( - ( - BusinessHour(-25), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), - datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 12), - datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 16), - datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 17), - datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), - datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 16), - datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 16), - datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 16), - datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 16), - datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 16), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 16, 30), - datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), - }, - ) - ) - - # 5 days and 3 hours later - apply_large_n_cases.append( - ( - BusinessHour(28, start="21:00", end="02:00"), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), - datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), - datetime(2014, 7, 2, 2): datetime(2014, 7, 10, 0), - datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), - datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 2): datetime(2014, 7, 12, 0), - datetime(2014, 7, 4, 3): datetime(2014, 7, 12, 0), - datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 5, 15): datetime(2014, 7, 15, 0), - datetime(2014, 7, 6, 18): datetime(2014, 7, 15, 0), - datetime(2014, 7, 7, 1): datetime(2014, 7, 15, 0), - datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), - }, - ) - ) - - # large n for multiple opening hours (3 days and 1 hour before) - apply_large_n_cases.append( - ( - BusinessHour(n=-25, start=["09:00", "14:00"], end=["12:00", "19:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 6, 26, 10), - datetime(2014, 7, 1, 13): datetime(2014, 6, 26, 11), - datetime(2014, 7, 1, 9): datetime(2014, 6, 25, 18), - datetime(2014, 7, 1, 10): datetime(2014, 6, 25, 19), - datetime(2014, 7, 3, 11): datetime(2014, 6, 30, 10), - datetime(2014, 7, 3, 8): datetime(2014, 6, 27, 18), - datetime(2014, 7, 3, 19): datetime(2014, 6, 30, 18), - datetime(2014, 7, 3, 23): datetime(2014, 6, 30, 18), - datetime(2014, 7, 4, 9): datetime(2014, 6, 30, 18), - datetime(2014, 7, 5, 15): datetime(2014, 7, 1, 18), - datetime(2014, 7, 6, 18): datetime(2014, 7, 1, 18), - datetime(2014, 7, 7, 9, 30): datetime(2014, 7, 1, 18, 30), - datetime(2014, 7, 7, 10, 30, 30): datetime(2014, 7, 2, 9, 30, 30), - }, - ) - ) - - # 5 days and 3 hours later - apply_large_n_cases.append( - ( - BusinessHour(28, start=["21:00", "03:00"], end=["01:00", "04:00"]), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 9, 0), - datetime(2014, 7, 1, 22): datetime(2014, 7, 9, 3), - datetime(2014, 7, 1, 23): datetime(2014, 7, 9, 21), - datetime(2014, 7, 2, 2): datetime(2014, 7, 9, 23), - datetime(2014, 7, 3, 21): datetime(2014, 7, 11, 0), - datetime(2014, 7, 4, 1): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 2): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 3): datetime(2014, 7, 11, 23), - datetime(2014, 7, 4, 21): datetime(2014, 7, 12, 0), - datetime(2014, 7, 5, 0): datetime(2014, 7, 14, 22), - datetime(2014, 7, 5, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 5, 15): datetime(2014, 7, 14, 23), - datetime(2014, 7, 6, 18): datetime(2014, 7, 14, 23), - datetime(2014, 7, 7, 1): datetime(2014, 7, 14, 23), - datetime(2014, 7, 7, 23, 30): datetime(2014, 7, 15, 21, 30), - }, - ) - ) - - @pytest.mark.parametrize("case", apply_large_n_cases) - def test_apply_large_n(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_apply_nanoseconds(self): - tests = [] - - tests.append( - ( - BusinessHour(), - { - Timestamp("2014-07-04 15:00") - + Nano(5): Timestamp("2014-07-04 16:00") - + Nano(5), - Timestamp("2014-07-04 16:00") - + Nano(5): Timestamp("2014-07-07 09:00") - + Nano(5), - Timestamp("2014-07-04 16:00") - - Nano(5): Timestamp("2014-07-04 17:00") - - Nano(5), - }, - ) - ) - - tests.append( - ( - BusinessHour(-1), - { - Timestamp("2014-07-04 15:00") - + Nano(5): Timestamp("2014-07-04 14:00") - + Nano(5), - Timestamp("2014-07-04 10:00") - + Nano(5): Timestamp("2014-07-04 09:00") - + Nano(5), - Timestamp("2014-07-04 10:00") - - Nano(5): Timestamp("2014-07-03 17:00") - - Nano(5), - }, - ) - ) - - for offset, cases in tests: - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - def test_datetimeindex(self): - idx1 = date_range(start="2014-07-04 15:00", end="2014-07-08 10:00", freq="BH") - idx2 = date_range(start="2014-07-04 15:00", periods=12, freq="BH") - idx3 = date_range(end="2014-07-08 10:00", periods=12, freq="BH") - expected = DatetimeIndex( - [ - "2014-07-04 15:00", - "2014-07-04 16:00", - "2014-07-07 09:00", - "2014-07-07 10:00", - "2014-07-07 11:00", - "2014-07-07 12:00", - "2014-07-07 13:00", - "2014-07-07 14:00", - "2014-07-07 15:00", - "2014-07-07 16:00", - "2014-07-08 09:00", - "2014-07-08 10:00", - ], - freq="BH", - ) - for idx in [idx1, idx2, idx3]: - tm.assert_index_equal(idx, expected) - - idx1 = date_range(start="2014-07-04 15:45", end="2014-07-08 10:45", freq="BH") - idx2 = date_range(start="2014-07-04 15:45", periods=12, freq="BH") - idx3 = date_range(end="2014-07-08 10:45", periods=12, freq="BH") - - expected = DatetimeIndex( - [ - "2014-07-04 15:45", - "2014-07-04 16:45", - "2014-07-07 09:45", - "2014-07-07 10:45", - "2014-07-07 11:45", - "2014-07-07 12:45", - "2014-07-07 13:45", - "2014-07-07 14:45", - "2014-07-07 15:45", - "2014-07-07 16:45", - "2014-07-08 09:45", - "2014-07-08 10:45", - ], - freq="BH", - ) - expected = idx1 - for idx in [idx1, idx2, idx3]: - tm.assert_index_equal(idx, expected) - - -class TestCustomBusinessHour(Base): - _offset = CustomBusinessHour - holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] - - def setup_method(self, method): - # 2014 Calendar to check custom holidays - # Sun Mon Tue Wed Thu Fri Sat - # 6/22 23 24 25 26 27 28 - # 29 30 7/1 2 3 4 5 - # 6 7 8 9 10 11 12 - self.d = datetime(2014, 7, 1, 10, 00) - self.offset1 = CustomBusinessHour(weekmask="Tue Wed Thu Fri") - - self.offset2 = CustomBusinessHour(holidays=self.holidays) - - def test_constructor_errors(self): - from datetime import time as dt_time - - with pytest.raises(ValueError): - CustomBusinessHour(start=dt_time(11, 0, 5)) - with pytest.raises(ValueError): - CustomBusinessHour(start="AAA") - with pytest.raises(ValueError): - CustomBusinessHour(start="14:00:05") - - 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.offset1) == "" - assert repr(self.offset2) == "" - - def test_with_offset(self): - expected = Timestamp("2014-07-01 13:00") - - assert self.d + CustomBusinessHour() * 3 == expected - assert self.d + CustomBusinessHour(n=3) == expected - - def test_eq(self): - for offset in [self.offset1, self.offset2]: - assert offset == offset - - assert CustomBusinessHour() != CustomBusinessHour(-1) - assert CustomBusinessHour(start="09:00") == CustomBusinessHour() - assert CustomBusinessHour(start="09:00") != CustomBusinessHour(start="09:01") - assert CustomBusinessHour(start="09:00", end="17:00") != CustomBusinessHour( - start="17:00", end="09:01" - ) - - assert CustomBusinessHour(weekmask="Tue Wed Thu Fri") != CustomBusinessHour( - weekmask="Mon Tue Wed Thu Fri" - ) - assert CustomBusinessHour(holidays=["2014-06-27"]) != CustomBusinessHour( - holidays=["2014-06-28"] - ) - - def test_sub(self): - # override the Base.test_sub implementation because self.offset2 is - # defined differently in this class than the test expects - pass - - def test_hash(self): - assert hash(self.offset1) == hash(self.offset1) - assert hash(self.offset2) == hash(self.offset2) - - def test_call(self): - assert self.offset1(self.d) == datetime(2014, 7, 1, 11) - assert self.offset2(self.d) == datetime(2014, 7, 1, 11) - - def testRollback1(self): - assert self.offset1.rollback(self.d) == self.d - assert self.offset2.rollback(self.d) == self.d - - d = datetime(2014, 7, 1, 0) - - # 2014/07/01 is Tuesday, 06/30 is Monday(holiday) - assert self.offset1.rollback(d) == datetime(2014, 6, 27, 17) - - # 2014/6/30 and 2014/6/27 are holidays - assert self.offset2.rollback(d) == datetime(2014, 6, 26, 17) - - def testRollback2(self): - assert self._offset(-3).rollback(datetime(2014, 7, 5, 15, 0)) == datetime( - 2014, 7, 4, 17, 0 - ) - - def testRollforward1(self): - assert self.offset1.rollforward(self.d) == self.d - assert self.offset2.rollforward(self.d) == self.d - - d = datetime(2014, 7, 1, 0) - assert self.offset1.rollforward(d) == datetime(2014, 7, 1, 9) - assert self.offset2.rollforward(d) == datetime(2014, 7, 1, 9) - - def testRollforward2(self): - assert self._offset(-3).rollforward(datetime(2014, 7, 5, 16, 0)) == datetime( - 2014, 7, 7, 9 - ) - - def test_roll_date_object(self): - offset = BusinessHour() - - dt = datetime(2014, 7, 6, 15, 0) - - result = offset.rollback(dt) - assert result == datetime(2014, 7, 4, 17) - - result = offset.rollforward(dt) - assert result == datetime(2014, 7, 7, 9) - - normalize_cases = [] - normalize_cases.append( - ( - CustomBusinessHour(normalize=True, holidays=holidays), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3), - datetime(2014, 7, 1, 23): datetime(2014, 7, 3), - datetime(2014, 7, 1, 0): datetime(2014, 7, 1), - datetime(2014, 7, 4, 15): datetime(2014, 7, 4), - datetime(2014, 7, 4, 15, 59): datetime(2014, 7, 4), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 7), - datetime(2014, 7, 6, 10): datetime(2014, 7, 7), - }, - ) - ) - - normalize_cases.append( - ( - CustomBusinessHour(-1, normalize=True, holidays=holidays), - { - datetime(2014, 7, 1, 8): datetime(2014, 6, 26), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 16): datetime(2014, 7, 1), - datetime(2014, 7, 1, 10): datetime(2014, 6, 26), - datetime(2014, 7, 1, 0): datetime(2014, 6, 26), - datetime(2014, 7, 7, 10): datetime(2014, 7, 4), - datetime(2014, 7, 7, 10, 1): datetime(2014, 7, 7), - datetime(2014, 7, 5, 23): datetime(2014, 7, 4), - datetime(2014, 7, 6, 10): datetime(2014, 7, 4), - }, - ) - ) - - normalize_cases.append( - ( - CustomBusinessHour( - 1, normalize=True, start="17:00", end="04:00", holidays=holidays - ), - { - datetime(2014, 7, 1, 8): datetime(2014, 7, 1), - datetime(2014, 7, 1, 17): datetime(2014, 7, 1), - datetime(2014, 7, 1, 23): datetime(2014, 7, 2), - datetime(2014, 7, 2, 2): datetime(2014, 7, 2), - datetime(2014, 7, 2, 3): datetime(2014, 7, 3), - datetime(2014, 7, 4, 23): datetime(2014, 7, 5), - datetime(2014, 7, 5, 2): datetime(2014, 7, 5), - datetime(2014, 7, 7, 2): datetime(2014, 7, 7), - datetime(2014, 7, 7, 17): datetime(2014, 7, 7), - }, - ) - ) - - @pytest.mark.parametrize("norm_cases", normalize_cases) - def test_normalize(self, norm_cases): - offset, cases = norm_cases - for dt, expected in cases.items(): - assert offset.apply(dt) == expected - - def test_onOffset(self): - tests = [] - - tests.append( - ( - CustomBusinessHour(start="10:00", end="15:00", holidays=self.holidays), - { - datetime(2014, 7, 1, 9): False, - datetime(2014, 7, 1, 10): True, - datetime(2014, 7, 1, 15): True, - datetime(2014, 7, 1, 15, 1): False, - datetime(2014, 7, 5, 12): False, - datetime(2014, 7, 6, 12): False, - }, - ) - ) - - for offset, cases in tests: - for dt, expected in cases.items(): - assert offset.onOffset(dt) == expected - - apply_cases = [] - apply_cases.append( - ( - CustomBusinessHour(holidays=holidays), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 12), - datetime(2014, 7, 1, 13): datetime(2014, 7, 1, 14), - datetime(2014, 7, 1, 15): datetime(2014, 7, 1, 16), - datetime(2014, 7, 1, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 9), - datetime(2014, 7, 1, 16, 30, 15): datetime(2014, 7, 3, 9, 30, 15), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 10), - # out of business hours - datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 10), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 10), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 10), - # saturday - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 10), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 9, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 9, 30, 30), - }, - ) - ) - - apply_cases.append( - ( - CustomBusinessHour(4, holidays=holidays), - { - datetime(2014, 7, 1, 11): datetime(2014, 7, 1, 15), - datetime(2014, 7, 1, 13): datetime(2014, 7, 3, 9), - datetime(2014, 7, 1, 15): datetime(2014, 7, 3, 11), - datetime(2014, 7, 1, 16): datetime(2014, 7, 3, 12), - datetime(2014, 7, 1, 17): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 11): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 8): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 19): datetime(2014, 7, 3, 13), - datetime(2014, 7, 2, 23): datetime(2014, 7, 3, 13), - datetime(2014, 7, 3, 0): datetime(2014, 7, 3, 13), - datetime(2014, 7, 5, 15): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 17): datetime(2014, 7, 7, 13), - datetime(2014, 7, 4, 16, 30): datetime(2014, 7, 7, 12, 30), - datetime(2014, 7, 4, 16, 30, 30): datetime(2014, 7, 7, 12, 30, 30), - }, - ) - ) - - @pytest.mark.parametrize("apply_case", apply_cases) - def test_apply(self, apply_case): - offset, cases = apply_case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - nano_cases = [] - nano_cases.append( - ( - CustomBusinessHour(holidays=holidays), - { - Timestamp("2014-07-01 15:00") - + Nano(5): Timestamp("2014-07-01 16:00") - + Nano(5), - Timestamp("2014-07-01 16:00") - + Nano(5): Timestamp("2014-07-03 09:00") - + Nano(5), - Timestamp("2014-07-01 16:00") - - Nano(5): Timestamp("2014-07-01 17:00") - - Nano(5), - }, - ) - ) - - nano_cases.append( - ( - CustomBusinessHour(-1, holidays=holidays), - { - Timestamp("2014-07-01 15:00") - + Nano(5): Timestamp("2014-07-01 14:00") - + Nano(5), - Timestamp("2014-07-01 10:00") - + Nano(5): Timestamp("2014-07-01 09:00") - + Nano(5), - Timestamp("2014-07-01 10:00") - - Nano(5): Timestamp("2014-06-26 17:00") - - Nano(5), - }, - ) - ) - - @pytest.mark.parametrize("nano_case", nano_cases) - def test_apply_nanoseconds(self, nano_case): - offset, cases = nano_case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - -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>" - - if compat.PY37: - expected = "" - else: - 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_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): - 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_onOffset(self, case): - offset, d, expected = case - assert_onOffset(offset, d, expected) - - apply_cases: _ApplyCases = [] - apply_cases.append( - ( - 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), - }, - ) - ) - - apply_cases.append( - ( - 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), - }, - ) - ) - - apply_cases.append( - ( - -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), - }, - ) - ) - - apply_cases.append( - ( - -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), - }, - ) - ) - - apply_cases.append( - ( - 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 - - -class CustomBusinessMonthBase: - def setup_method(self, method): - self.d = datetime(2008, 1, 1) - - self.offset = self._offset() - self.offset1 = self.offset - self.offset2 = self._offset(2) - - 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_roundtrip_pickle(self): - def _check_roundtrip(obj): - unpickled = tm.round_trip_pickle(obj) - assert unpickled == obj - - _check_roundtrip(self._offset()) - _check_roundtrip(self._offset(2)) - _check_roundtrip(self._offset() * 2) - - def test_copy(self): - # GH 17452 - off = self._offset(weekmask="Mon Wed Fri") - assert off == off.copy() - - -class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): - _offset = CBMonthEnd - - 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 * CustomBusinessMonthEnds>" - - def testCall(self): - assert self.offset2(self.d) == datetime(2008, 2, 29) - - def testRollback1(self): - assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - - def testRollback2(self): - assert CBMonthEnd(10).rollback(self.d) == datetime(2007, 12, 31) - - def testRollforward1(self): - assert CBMonthEnd(10).rollforward(self.d) == datetime(2008, 1, 31) - - def test_roll_date_object(self): - offset = CBMonthEnd() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 8, 31) - - result = offset.rollforward(dt) - assert result == datetime(2012, 9, 28) - - 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 = [ - (CBMonthEnd(), datetime(2008, 1, 31), True), - (CBMonthEnd(), datetime(2008, 1, 1), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, d, expected = case - assert_onOffset(offset, d, expected) - - apply_cases: _ApplyCases = [] - apply_cases.append( - ( - CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 2, 7): datetime(2008, 2, 29), - }, - ) - ) - - apply_cases.append( - ( - 2 * CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 2, 29), - datetime(2008, 2, 7): datetime(2008, 3, 31), - }, - ) - ) - - apply_cases.append( - ( - -CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2007, 12, 31), - datetime(2008, 2, 8): datetime(2008, 1, 31), - }, - ) - ) - - apply_cases.append( - ( - -2 * CBMonthEnd(), - { - datetime(2008, 1, 1): datetime(2007, 11, 30), - datetime(2008, 2, 9): datetime(2007, 12, 31), - }, - ) - ) - - apply_cases.append( - ( - CBMonthEnd(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 2, 7): datetime(2008, 2, 29), - }, - ) - ) - - @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 + CBMonthEnd(10) - assert result == datetime(2013, 7, 31) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CBMonthEnd() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 7, 29) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - xp = datetime(2012, 5, 31) - assert rs == xp - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-01-31", datetime(2012, 2, 28), np.datetime64("2012-02-29")] - bm_offset = CBMonthEnd(holidays=holidays) - dt = datetime(2012, 1, 1) - assert dt + bm_offset == datetime(2012, 1, 30) - assert dt + 2 * bm_offset == datetime(2012, 2, 27) - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_datetimeindex(self): - from pandas.tseries.holiday import USFederalHolidayCalendar - - hcal = USFederalHolidayCalendar() - freq = CBMonthEnd(calendar=hcal) - - assert date_range(start="20120101", end="20130101", freq=freq).tolist()[ - 0 - ] == datetime(2012, 1, 31) - - -class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): - _offset = CBMonthBegin - - 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 * CustomBusinessMonthBegins>" - - def testCall(self): - assert self.offset2(self.d) == datetime(2008, 3, 3) - - def testRollback1(self): - assert CDay(10).rollback(datetime(2007, 12, 31)) == datetime(2007, 12, 31) - - def testRollback2(self): - assert CBMonthBegin(10).rollback(self.d) == datetime(2008, 1, 1) - - def testRollforward1(self): - assert CBMonthBegin(10).rollforward(self.d) == datetime(2008, 1, 1) - - def test_roll_date_object(self): - offset = CBMonthBegin() - - dt = date(2012, 9, 15) - - result = offset.rollback(dt) - assert result == datetime(2012, 9, 3) - - result = offset.rollforward(dt) - assert result == datetime(2012, 10, 1) - - 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 = [ - (CBMonthBegin(), datetime(2008, 1, 1), True), - (CBMonthBegin(), datetime(2008, 1, 31), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - offset, dt, expected = case - assert_onOffset(offset, dt, expected) - - apply_cases: _ApplyCases = [] - apply_cases.append( - ( - CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 2, 1), - datetime(2008, 2, 7): datetime(2008, 3, 3), - }, - ) - ) - - apply_cases.append( - ( - 2 * CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 3, 3), - datetime(2008, 2, 7): datetime(2008, 4, 1), - }, - ) - ) - - apply_cases.append( - ( - -CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2007, 12, 3), - datetime(2008, 2, 8): datetime(2008, 2, 1), - }, - ) - ) - - apply_cases.append( - ( - -2 * CBMonthBegin(), - { - datetime(2008, 1, 1): datetime(2007, 11, 1), - datetime(2008, 2, 9): datetime(2008, 1, 1), - }, - ) - ) - - apply_cases.append( - ( - CBMonthBegin(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 7): datetime(2008, 2, 1), - }, - ) - ) - - @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 + CBMonthBegin(10) - assert result == datetime(2013, 8, 1) - - result = dt + CDay(100) - CDay(100) - assert result == dt - - off = CBMonthBegin() * 6 - rs = datetime(2012, 1, 1) - off - xp = datetime(2011, 7, 1) - assert rs == xp - - st = datetime(2011, 12, 18) - rs = st + off - - xp = datetime(2012, 6, 1) - assert rs == xp - - def test_holidays(self): - # Define a TradingDay offset - holidays = ["2012-02-01", datetime(2012, 2, 2), np.datetime64("2012-03-01")] - bm_offset = CBMonthBegin(holidays=holidays) - dt = datetime(2012, 1, 1) - - assert dt + bm_offset == datetime(2012, 1, 2) - assert dt + 2 * bm_offset == datetime(2012, 2, 3) - - @pytest.mark.filterwarnings("ignore:Non:pandas.errors.PerformanceWarning") - def test_datetimeindex(self): - hcal = USFederalHolidayCalendar() - cbmb = CBMonthBegin(calendar=hcal) - assert date_range(start="20120101", end="20130101", freq=cbmb).tolist()[ - 0 - ] == datetime(2012, 1, 3) - - -class TestWeek(Base): - _offset = Week - d = Timestamp(datetime(2008, 1, 2)) - offset1 = _offset() - offset2 = _offset(2) - - def test_repr(self): - assert repr(Week(weekday=0)) == "" - assert repr(Week(n=-1, weekday=0)) == "<-1 * Week: weekday=0>" - assert repr(Week(n=-2, weekday=0)) == "<-2 * Weeks: weekday=0>" - - def test_corner(self): - with pytest.raises(ValueError): - Week(weekday=7) - - with pytest.raises(ValueError, match="Day must be"): - Week(weekday=-1) - - def test_isAnchored(self): - assert Week(weekday=0).isAnchored() - assert not Week().isAnchored() - assert not Week(2, weekday=2).isAnchored() - assert not Week(2).isAnchored() - - offset_cases = [] - # not business week - offset_cases.append( - ( - Week(), - { - datetime(2008, 1, 1): datetime(2008, 1, 8), - datetime(2008, 1, 4): datetime(2008, 1, 11), - datetime(2008, 1, 5): datetime(2008, 1, 12), - datetime(2008, 1, 6): datetime(2008, 1, 13), - datetime(2008, 1, 7): datetime(2008, 1, 14), - }, - ) - ) - - # Mon - offset_cases.append( - ( - Week(weekday=0), - { - datetime(2007, 12, 31): datetime(2008, 1, 7), - 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, 14), - }, - ) - ) - - # n=0 -> roll forward. Mon - offset_cases.append( - ( - Week(0, weekday=0), - { - datetime(2007, 12, 31): datetime(2007, 12, 31), - 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, 7), - }, - ) - ) - - # n=0 -> roll forward. Mon - offset_cases.append( - ( - Week(-2, weekday=1), - { - datetime(2010, 4, 6): datetime(2010, 3, 23), - datetime(2010, 4, 8): datetime(2010, 3, 30), - datetime(2010, 4, 5): datetime(2010, 3, 23), - }, - ) - ) - - @pytest.mark.parametrize("case", offset_cases) - def test_offset(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - @pytest.mark.parametrize("weekday", range(7)) - def test_onOffset(self, weekday): - offset = Week(weekday=weekday) - - for day in range(1, 8): - date = datetime(2008, 1, day) - - if day % 7 == weekday: - expected = True - else: - expected = False - assert_onOffset(offset, date, expected) - - -class TestWeekOfMonth(Base): - _offset = WeekOfMonth - offset1 = _offset() - offset2 = _offset(2) - - def test_constructor(self): - with pytest.raises(ValueError, match="^Week"): - WeekOfMonth(n=1, week=4, weekday=0) - - with pytest.raises(ValueError, match="^Week"): - WeekOfMonth(n=1, week=-1, weekday=0) - - with pytest.raises(ValueError, match="^Day"): - WeekOfMonth(n=1, week=0, weekday=-1) - - with pytest.raises(ValueError, match="^Day"): - WeekOfMonth(n=1, week=0, weekday=-7) - - def test_repr(self): - assert ( - repr(WeekOfMonth(weekday=1, week=2)) == "" - ) - - def test_offset(self): - date1 = datetime(2011, 1, 4) # 1st Tuesday of Month - date2 = datetime(2011, 1, 11) # 2nd Tuesday of Month - date3 = datetime(2011, 1, 18) # 3rd Tuesday of Month - date4 = datetime(2011, 1, 25) # 4th Tuesday of Month - - # see for loop for structure - test_cases = [ - (-2, 2, 1, date1, datetime(2010, 11, 16)), - (-2, 2, 1, date2, datetime(2010, 11, 16)), - (-2, 2, 1, date3, datetime(2010, 11, 16)), - (-2, 2, 1, date4, datetime(2010, 12, 21)), - (-1, 2, 1, date1, datetime(2010, 12, 21)), - (-1, 2, 1, date2, datetime(2010, 12, 21)), - (-1, 2, 1, date3, datetime(2010, 12, 21)), - (-1, 2, 1, date4, datetime(2011, 1, 18)), - (0, 0, 1, date1, datetime(2011, 1, 4)), - (0, 0, 1, date2, datetime(2011, 2, 1)), - (0, 0, 1, date3, datetime(2011, 2, 1)), - (0, 0, 1, date4, datetime(2011, 2, 1)), - (0, 1, 1, date1, datetime(2011, 1, 11)), - (0, 1, 1, date2, datetime(2011, 1, 11)), - (0, 1, 1, date3, datetime(2011, 2, 8)), - (0, 1, 1, date4, datetime(2011, 2, 8)), - (0, 0, 1, date1, datetime(2011, 1, 4)), - (0, 1, 1, date2, datetime(2011, 1, 11)), - (0, 2, 1, date3, datetime(2011, 1, 18)), - (0, 3, 1, date4, datetime(2011, 1, 25)), - (1, 0, 0, date1, datetime(2011, 2, 7)), - (1, 0, 0, date2, datetime(2011, 2, 7)), - (1, 0, 0, date3, datetime(2011, 2, 7)), - (1, 0, 0, date4, datetime(2011, 2, 7)), - (1, 0, 1, date1, datetime(2011, 2, 1)), - (1, 0, 1, date2, datetime(2011, 2, 1)), - (1, 0, 1, date3, datetime(2011, 2, 1)), - (1, 0, 1, date4, datetime(2011, 2, 1)), - (1, 0, 2, date1, datetime(2011, 1, 5)), - (1, 0, 2, date2, datetime(2011, 2, 2)), - (1, 0, 2, date3, datetime(2011, 2, 2)), - (1, 0, 2, date4, datetime(2011, 2, 2)), - (1, 2, 1, date1, datetime(2011, 1, 18)), - (1, 2, 1, date2, datetime(2011, 1, 18)), - (1, 2, 1, date3, datetime(2011, 2, 15)), - (1, 2, 1, date4, datetime(2011, 2, 15)), - (2, 2, 1, date1, datetime(2011, 2, 15)), - (2, 2, 1, date2, datetime(2011, 2, 15)), - (2, 2, 1, date3, datetime(2011, 3, 15)), - (2, 2, 1, date4, datetime(2011, 3, 15)), - ] - - for n, week, weekday, dt, expected in test_cases: - offset = WeekOfMonth(n, week=week, weekday=weekday) - assert_offset_equal(offset, dt, expected) - - # try subtracting - result = datetime(2011, 2, 1) - WeekOfMonth(week=1, weekday=2) - assert result == datetime(2011, 1, 12) - - result = datetime(2011, 2, 3) - WeekOfMonth(week=0, weekday=2) - assert result == datetime(2011, 2, 2) - - on_offset_cases = [ - (0, 0, datetime(2011, 2, 7), True), - (0, 0, datetime(2011, 2, 6), False), - (0, 0, datetime(2011, 2, 14), False), - (1, 0, datetime(2011, 2, 14), True), - (0, 1, datetime(2011, 2, 1), True), - (0, 1, datetime(2011, 2, 8), False), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - week, weekday, dt, expected = case - offset = WeekOfMonth(week=week, weekday=weekday) - assert offset.onOffset(dt) == expected - - -class TestLastWeekOfMonth(Base): - _offset = LastWeekOfMonth - offset1 = _offset() - offset2 = _offset(2) - - def test_constructor(self): - with pytest.raises(ValueError, match="^N cannot be 0"): - LastWeekOfMonth(n=0, weekday=1) - - with pytest.raises(ValueError, match="^Day"): - LastWeekOfMonth(n=1, weekday=-1) - - with pytest.raises(ValueError, match="^Day"): - LastWeekOfMonth(n=1, weekday=7) - - def test_offset(self): - # Saturday - last_sat = datetime(2013, 8, 31) - next_sat = datetime(2013, 9, 28) - offset_sat = LastWeekOfMonth(n=1, weekday=5) - - one_day_before = last_sat + timedelta(days=-1) - assert one_day_before + offset_sat == last_sat - - one_day_after = last_sat + timedelta(days=+1) - assert one_day_after + offset_sat == next_sat - - # Test On that day - assert last_sat + offset_sat == next_sat - - # Thursday - - offset_thur = LastWeekOfMonth(n=1, weekday=3) - last_thurs = datetime(2013, 1, 31) - next_thurs = datetime(2013, 2, 28) - - one_day_before = last_thurs + timedelta(days=-1) - assert one_day_before + offset_thur == last_thurs - - one_day_after = last_thurs + timedelta(days=+1) - assert one_day_after + offset_thur == next_thurs - - # Test on that day - assert last_thurs + offset_thur == next_thurs - - three_before = last_thurs + timedelta(days=-3) - assert three_before + offset_thur == last_thurs - - two_after = last_thurs + timedelta(days=+2) - assert two_after + offset_thur == next_thurs - - offset_sunday = LastWeekOfMonth(n=1, weekday=WeekDay.SUN) - assert datetime(2013, 7, 31) + offset_sunday == datetime(2013, 8, 25) - - on_offset_cases = [ - (WeekDay.SUN, datetime(2013, 1, 27), True), - (WeekDay.SAT, datetime(2013, 3, 30), True), - (WeekDay.MON, datetime(2013, 2, 18), False), # Not the last Mon - (WeekDay.SUN, datetime(2013, 2, 25), False), # Not a SUN - (WeekDay.MON, datetime(2013, 2, 25), True), - (WeekDay.SAT, datetime(2013, 11, 30), True), - (WeekDay.SAT, datetime(2006, 8, 26), True), - (WeekDay.SAT, datetime(2007, 8, 25), True), - (WeekDay.SAT, datetime(2008, 8, 30), True), - (WeekDay.SAT, datetime(2009, 8, 29), True), - (WeekDay.SAT, datetime(2010, 8, 28), True), - (WeekDay.SAT, datetime(2011, 8, 27), True), - (WeekDay.SAT, datetime(2019, 8, 31), True), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - weekday, dt, expected = case - offset = LastWeekOfMonth(weekday=weekday) - assert offset.onOffset(dt) == expected - - -class TestSemiMonthEnd(Base): - _offset = SemiMonthEnd - offset1 = _offset() - offset2 = _offset(2) - - def test_offset_whole_year(self): - dates = ( - datetime(2007, 12, 31), - datetime(2008, 1, 15), - datetime(2008, 1, 31), - datetime(2008, 2, 15), - datetime(2008, 2, 29), - datetime(2008, 3, 15), - datetime(2008, 3, 31), - datetime(2008, 4, 15), - datetime(2008, 4, 30), - datetime(2008, 5, 15), - datetime(2008, 5, 31), - datetime(2008, 6, 15), - datetime(2008, 6, 30), - datetime(2008, 7, 15), - datetime(2008, 7, 31), - datetime(2008, 8, 15), - datetime(2008, 8, 31), - datetime(2008, 9, 15), - datetime(2008, 9, 30), - datetime(2008, 10, 15), - datetime(2008, 10, 31), - datetime(2008, 11, 15), - datetime(2008, 11, 30), - datetime(2008, 12, 15), - datetime(2008, 12, 31), - ) - - for base, exp_date in zip(dates[:-1], dates[1:]): - assert_offset_equal(SemiMonthEnd(), base, exp_date) - - # ensure .apply_index works as expected - s = DatetimeIndex(dates[:-1]) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = SemiMonthEnd().apply_index(s) - - exp = DatetimeIndex(dates[1:]) - tm.assert_index_equal(result, exp) - - # ensure generating a range with DatetimeIndex gives same result - result = date_range(start=dates[0], end=dates[-1], freq="SM") - exp = DatetimeIndex(dates) - tm.assert_index_equal(result, exp) - - offset_cases = [] - offset_cases.append( - ( - SemiMonthEnd(), - { - datetime(2008, 1, 1): datetime(2008, 1, 15), - datetime(2008, 1, 15): datetime(2008, 1, 31), - datetime(2008, 1, 31): datetime(2008, 2, 15), - datetime(2006, 12, 14): datetime(2006, 12, 15), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2007, 1, 15), - datetime(2007, 1, 1): datetime(2007, 1, 15), - datetime(2006, 12, 1): datetime(2006, 12, 15), - datetime(2006, 12, 15): datetime(2006, 12, 31), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(day_of_month=20), - { - datetime(2008, 1, 1): datetime(2008, 1, 20), - datetime(2008, 1, 15): datetime(2008, 1, 20), - datetime(2008, 1, 21): datetime(2008, 1, 31), - datetime(2008, 1, 31): datetime(2008, 2, 20), - datetime(2006, 12, 14): datetime(2006, 12, 20), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2007, 1, 20), - datetime(2007, 1, 1): datetime(2007, 1, 20), - datetime(2006, 12, 1): datetime(2006, 12, 20), - datetime(2006, 12, 15): datetime(2006, 12, 20), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 15), - datetime(2008, 1, 16): datetime(2008, 1, 31), - datetime(2008, 1, 15): datetime(2008, 1, 15), - datetime(2008, 1, 31): datetime(2008, 1, 31), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2006, 12, 31), - datetime(2007, 1, 1): datetime(2007, 1, 15), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(0, day_of_month=16), - { - datetime(2008, 1, 1): datetime(2008, 1, 16), - datetime(2008, 1, 16): datetime(2008, 1, 16), - datetime(2008, 1, 15): datetime(2008, 1, 16), - datetime(2008, 1, 31): datetime(2008, 1, 31), - datetime(2006, 12, 29): datetime(2006, 12, 31), - datetime(2006, 12, 31): datetime(2006, 12, 31), - datetime(2007, 1, 1): datetime(2007, 1, 16), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(2), - { - datetime(2008, 1, 1): datetime(2008, 1, 31), - datetime(2008, 1, 31): datetime(2008, 2, 29), - datetime(2006, 12, 29): datetime(2007, 1, 15), - datetime(2006, 12, 31): datetime(2007, 1, 31), - datetime(2007, 1, 1): datetime(2007, 1, 31), - datetime(2007, 1, 16): datetime(2007, 2, 15), - datetime(2006, 11, 1): datetime(2006, 11, 30), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(-1), - { - datetime(2007, 1, 1): datetime(2006, 12, 31), - datetime(2008, 6, 30): datetime(2008, 6, 15), - datetime(2008, 12, 31): datetime(2008, 12, 15), - datetime(2006, 12, 29): datetime(2006, 12, 15), - datetime(2006, 12, 30): datetime(2006, 12, 15), - datetime(2007, 1, 1): datetime(2006, 12, 31), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(-1, day_of_month=4), - { - datetime(2007, 1, 1): datetime(2006, 12, 31), - datetime(2007, 1, 4): datetime(2006, 12, 31), - datetime(2008, 6, 30): datetime(2008, 6, 4), - datetime(2008, 12, 31): datetime(2008, 12, 4), - datetime(2006, 12, 5): datetime(2006, 12, 4), - datetime(2006, 12, 30): datetime(2006, 12, 4), - datetime(2007, 1, 1): datetime(2006, 12, 31), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthEnd(-2), - { - datetime(2007, 1, 1): datetime(2006, 12, 15), - datetime(2008, 6, 30): datetime(2008, 5, 31), - datetime(2008, 3, 15): datetime(2008, 2, 15), - datetime(2008, 12, 31): datetime(2008, 11, 30), - datetime(2006, 12, 29): datetime(2006, 11, 30), - datetime(2006, 12, 14): datetime(2006, 11, 15), - datetime(2007, 1, 1): datetime(2006, 12, 15), - }, - ) - ) - - @pytest.mark.parametrize("case", offset_cases) - def test_offset(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - @pytest.mark.parametrize("case", offset_cases) - def test_apply_index(self, case): - offset, cases = case - s = DatetimeIndex(cases.keys()) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = offset.apply_index(s) - - exp = DatetimeIndex(cases.values()) - tm.assert_index_equal(result, exp) - - on_offset_cases = [ - (datetime(2007, 12, 31), True), - (datetime(2007, 12, 15), True), - (datetime(2007, 12, 14), False), - (datetime(2007, 12, 1), False), - (datetime(2008, 2, 29), True), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - dt, expected = case - assert_onOffset(SemiMonthEnd(), dt, expected) - - @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) - def test_vectorized_offset_addition(self, klass): - s = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthEnd() - result2 = SemiMonthEnd() + s - - exp = klass( - [ - Timestamp("2000-01-31 00:15:00", tz="US/Central"), - Timestamp("2000-02-29", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - s = klass( - [ - Timestamp("2000-01-01 00:15:00", tz="US/Central"), - Timestamp("2000-02-01", tz="US/Central"), - ], - name="a", - ) - - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthEnd() - result2 = SemiMonthEnd() + s - - exp = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - -class TestSemiMonthBegin(Base): - _offset = SemiMonthBegin - offset1 = _offset() - offset2 = _offset(2) - - def test_offset_whole_year(self): - dates = ( - datetime(2007, 12, 15), - datetime(2008, 1, 1), - datetime(2008, 1, 15), - datetime(2008, 2, 1), - datetime(2008, 2, 15), - datetime(2008, 3, 1), - datetime(2008, 3, 15), - datetime(2008, 4, 1), - datetime(2008, 4, 15), - datetime(2008, 5, 1), - datetime(2008, 5, 15), - datetime(2008, 6, 1), - datetime(2008, 6, 15), - datetime(2008, 7, 1), - datetime(2008, 7, 15), - datetime(2008, 8, 1), - datetime(2008, 8, 15), - datetime(2008, 9, 1), - datetime(2008, 9, 15), - datetime(2008, 10, 1), - datetime(2008, 10, 15), - datetime(2008, 11, 1), - datetime(2008, 11, 15), - datetime(2008, 12, 1), - datetime(2008, 12, 15), - ) - - for base, exp_date in zip(dates[:-1], dates[1:]): - assert_offset_equal(SemiMonthBegin(), base, exp_date) - - # ensure .apply_index works as expected - s = DatetimeIndex(dates[:-1]) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = SemiMonthBegin().apply_index(s) - - exp = DatetimeIndex(dates[1:]) - tm.assert_index_equal(result, exp) - - # ensure generating a range with DatetimeIndex gives same result - result = date_range(start=dates[0], end=dates[-1], freq="SMS") - exp = DatetimeIndex(dates) - tm.assert_index_equal(result, exp) - - offset_cases = [] - offset_cases.append( - ( - SemiMonthBegin(), - { - datetime(2008, 1, 1): datetime(2008, 1, 15), - datetime(2008, 1, 15): datetime(2008, 2, 1), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 14): datetime(2006, 12, 15), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 31): datetime(2007, 1, 1), - datetime(2007, 1, 1): datetime(2007, 1, 15), - datetime(2006, 12, 1): datetime(2006, 12, 15), - datetime(2006, 12, 15): datetime(2007, 1, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(day_of_month=20), - { - datetime(2008, 1, 1): datetime(2008, 1, 20), - datetime(2008, 1, 15): datetime(2008, 1, 20), - datetime(2008, 1, 21): datetime(2008, 2, 1), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 14): datetime(2006, 12, 20), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 31): datetime(2007, 1, 1), - datetime(2007, 1, 1): datetime(2007, 1, 20), - datetime(2006, 12, 1): datetime(2006, 12, 20), - datetime(2006, 12, 15): datetime(2006, 12, 20), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(0), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 16): datetime(2008, 2, 1), - datetime(2008, 1, 15): datetime(2008, 1, 15), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 2): datetime(2006, 12, 15), - datetime(2007, 1, 1): datetime(2007, 1, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(0, day_of_month=16), - { - datetime(2008, 1, 1): datetime(2008, 1, 1), - datetime(2008, 1, 16): datetime(2008, 1, 16), - datetime(2008, 1, 15): datetime(2008, 1, 16), - datetime(2008, 1, 31): datetime(2008, 2, 1), - datetime(2006, 12, 29): datetime(2007, 1, 1), - datetime(2006, 12, 31): datetime(2007, 1, 1), - datetime(2007, 1, 5): datetime(2007, 1, 16), - datetime(2007, 1, 1): datetime(2007, 1, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(2), - { - datetime(2008, 1, 1): datetime(2008, 2, 1), - datetime(2008, 1, 31): datetime(2008, 2, 15), - datetime(2006, 12, 1): datetime(2007, 1, 1), - datetime(2006, 12, 29): datetime(2007, 1, 15), - datetime(2006, 12, 15): datetime(2007, 1, 15), - datetime(2007, 1, 1): datetime(2007, 2, 1), - datetime(2007, 1, 16): datetime(2007, 2, 15), - datetime(2006, 11, 1): datetime(2006, 12, 1), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(-1), - { - datetime(2007, 1, 1): datetime(2006, 12, 15), - datetime(2008, 6, 30): datetime(2008, 6, 15), - datetime(2008, 6, 14): datetime(2008, 6, 1), - datetime(2008, 12, 31): datetime(2008, 12, 15), - datetime(2006, 12, 29): datetime(2006, 12, 15), - datetime(2006, 12, 15): datetime(2006, 12, 1), - datetime(2007, 1, 1): datetime(2006, 12, 15), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(-1, day_of_month=4), - { - datetime(2007, 1, 1): datetime(2006, 12, 4), - datetime(2007, 1, 4): datetime(2007, 1, 1), - datetime(2008, 6, 30): datetime(2008, 6, 4), - datetime(2008, 12, 31): datetime(2008, 12, 4), - datetime(2006, 12, 5): datetime(2006, 12, 4), - datetime(2006, 12, 30): datetime(2006, 12, 4), - datetime(2006, 12, 2): datetime(2006, 12, 1), - datetime(2007, 1, 1): datetime(2006, 12, 4), - }, - ) - ) - - offset_cases.append( - ( - SemiMonthBegin(-2), - { - datetime(2007, 1, 1): datetime(2006, 12, 1), - datetime(2008, 6, 30): datetime(2008, 6, 1), - datetime(2008, 6, 14): datetime(2008, 5, 15), - datetime(2008, 12, 31): datetime(2008, 12, 1), - datetime(2006, 12, 29): datetime(2006, 12, 1), - datetime(2006, 12, 15): datetime(2006, 11, 15), - datetime(2007, 1, 1): datetime(2006, 12, 1), - }, - ) - ) - - @pytest.mark.parametrize("case", offset_cases) - def test_offset(self, case): - offset, cases = case - for base, expected in cases.items(): - assert_offset_equal(offset, base, expected) - - @pytest.mark.parametrize("case", offset_cases) - def test_apply_index(self, case): - offset, cases = case - s = DatetimeIndex(cases.keys()) - - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = offset.apply_index(s) - - exp = DatetimeIndex(cases.values()) - tm.assert_index_equal(result, exp) - - on_offset_cases = [ - (datetime(2007, 12, 1), True), - (datetime(2007, 12, 15), True), - (datetime(2007, 12, 14), False), - (datetime(2007, 12, 31), False), - (datetime(2008, 2, 15), True), - ] - - @pytest.mark.parametrize("case", on_offset_cases) - def test_onOffset(self, case): - dt, expected = case - assert_onOffset(SemiMonthBegin(), dt, expected) - - @pytest.mark.parametrize("klass", [Series, DatetimeIndex]) - def test_vectorized_offset_addition(self, klass): - s = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthBegin() - result2 = SemiMonthBegin() + s - - exp = klass( - [ - Timestamp("2000-02-01 00:15:00", tz="US/Central"), - Timestamp("2000-03-01", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - s = klass( - [ - Timestamp("2000-01-01 00:15:00", tz="US/Central"), - Timestamp("2000-02-01", tz="US/Central"), - ], - name="a", - ) - with tm.assert_produces_warning(None): - # GH#22535 check that we don't get a FutureWarning from adding - # an integer array to PeriodIndex - result = s + SemiMonthBegin() - result2 = SemiMonthBegin() + s - - exp = klass( - [ - Timestamp("2000-01-15 00:15:00", tz="US/Central"), - Timestamp("2000-02-15", tz="US/Central"), - ], - name="a", - ) - tm.assert_equal(result, exp) - tm.assert_equal(result2, exp) - - -def test_Easter(): - assert_offset_equal(Easter(), datetime(2010, 1, 1), datetime(2010, 4, 4)) - assert_offset_equal(Easter(), datetime(2010, 4, 5), datetime(2011, 4, 24)) - assert_offset_equal(Easter(2), datetime(2010, 1, 1), datetime(2011, 4, 24)) - - assert_offset_equal(Easter(), datetime(2010, 4, 4), datetime(2011, 4, 24)) - assert_offset_equal(Easter(2), datetime(2010, 4, 4), datetime(2012, 4, 8)) - - assert_offset_equal(-Easter(), datetime(2011, 1, 1), datetime(2010, 4, 4)) - assert_offset_equal(-Easter(), datetime(2010, 4, 5), datetime(2010, 4, 4)) - assert_offset_equal(-Easter(2), datetime(2011, 1, 1), datetime(2009, 4, 12)) - - assert_offset_equal(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)) - assert_offset_equal(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)) - - -class TestOffsetNames: - def test_get_offset_name(self): - assert BDay().freqstr == "B" - assert BDay(2).freqstr == "2B" - assert BMonthEnd().freqstr == "BM" - assert Week(weekday=0).freqstr == "W-MON" - assert Week(weekday=1).freqstr == "W-TUE" - assert Week(weekday=2).freqstr == "W-WED" - assert Week(weekday=3).freqstr == "W-THU" - assert Week(weekday=4).freqstr == "W-FRI" - - assert LastWeekOfMonth(weekday=WeekDay.SUN).freqstr == "LWOM-SUN" - - -def test_get_offset(): - with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): - get_offset("gibberish") - with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): - get_offset("QS-JAN-B") - - pairs = [ - ("B", BDay()), - ("b", BDay()), - ("bm", BMonthEnd()), - ("Bm", BMonthEnd()), - ("W-MON", Week(weekday=0)), - ("W-TUE", Week(weekday=1)), - ("W-WED", Week(weekday=2)), - ("W-THU", Week(weekday=3)), - ("W-FRI", Week(weekday=4)), - ] - - for name, expected in pairs: - offset = get_offset(name) - assert offset == expected, ( - f"Expected {repr(name)} to yield {repr(expected)} " - f"(actual: {repr(offset)})" - ) - - -def test_get_offset_legacy(): - pairs = [("w@Sat", Week(weekday=5))] - for name, expected in pairs: - with pytest.raises(ValueError, match=INVALID_FREQ_ERR_MSG): - get_offset(name) - - -class TestOffsetAliases: - def setup_method(self, method): - _offset_map.clear() - - def test_alias_equality(self): - for k, v in _offset_map.items(): - if v is None: - continue - assert k == v.copy() - - def test_rule_code(self): - lst = ["M", "MS", "BM", "BMS", "D", "B", "H", "T", "S", "L", "U"] - for k in lst: - assert k == get_offset(k).rule_code - # should be cached - this is kind of an internals test... - assert k in _offset_map - assert k == (get_offset(k) * 3).rule_code - - suffix_lst = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] - base = "W" - for v in suffix_lst: - alias = "-".join([base, v]) - assert alias == get_offset(alias).rule_code - assert alias == (get_offset(alias) * 5).rule_code - - suffix_lst = [ - "JAN", - "FEB", - "MAR", - "APR", - "MAY", - "JUN", - "JUL", - "AUG", - "SEP", - "OCT", - "NOV", - "DEC", - ] - base_lst = ["A", "AS", "BA", "BAS", "Q", "QS", "BQ", "BQS"] - for base in base_lst: - for v in suffix_lst: - alias = "-".join([base, v]) - assert alias == get_offset(alias).rule_code - assert alias == (get_offset(alias) * 5).rule_code - - lst = ["M", "D", "B", "H", "T", "S", "L", "U"] - for k in lst: - code, stride = get_freq_code("3" + k) - assert isinstance(code, int) - assert stride == 3 - assert k == get_freq_str(code) - - -def test_dateoffset_misc(): - oset = offsets.DateOffset(months=2, days=4) - # it works - oset.freqstr - - assert not offsets.DateOffset(months=2) == 2 - - -def test_freq_offsets(): - off = BDay(1, offset=timedelta(0, 1800)) - assert off.freqstr == "B+30Min" - - off = BDay(1, offset=timedelta(0, -1800)) - assert off.freqstr == "B-30Min" - - -class TestReprNames: - def test_str_for_named_is_name(self): - # look at all the amazing combinations! - month_prefixes = ["A", "AS", "BA", "BAS", "Q", "BQ", "BQS", "QS"] - names = [ - prefix + "-" + month - for prefix in month_prefixes - for month in [ - "JAN", - "FEB", - "MAR", - "APR", - "MAY", - "JUN", - "JUL", - "AUG", - "SEP", - "OCT", - "NOV", - "DEC", - ] - ] - days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] - names += ["W-" + day for day in days] - names += ["WOM-" + week + day for week in ("1", "2", "3", "4") for day in days] - _offset_map.clear() - for name in names: - offset = get_offset(name) - assert offset.freqstr == name - - -def get_utc_offset_hours(ts): - # take a Timestamp and compute total hours of utc offset - o = ts.utcoffset() - return (o.days * 24 * 3600 + o.seconds) / 3600.0 - - -class TestDST: - """ - test DateOffset additions over Daylight Savings Time - """ - - # one microsecond before the DST transition - ts_pre_fallback = "2013-11-03 01:59:59.999999" - ts_pre_springfwd = "2013-03-10 01:59:59.999999" - - # test both basic names and dateutil timezones - timezone_utc_offsets = { - "US/Eastern": dict(utc_offset_daylight=-4, utc_offset_standard=-5), - "dateutil/US/Pacific": dict(utc_offset_daylight=-7, utc_offset_standard=-8), - } - valid_date_offsets_singular = [ - "weekday", - "day", - "hour", - "minute", - "second", - "microsecond", - ] - valid_date_offsets_plural = [ - "weeks", - "days", - "hours", - "minutes", - "seconds", - "milliseconds", - "microseconds", - ] - - def _test_all_offsets(self, n, **kwds): - valid_offsets = ( - self.valid_date_offsets_plural - if n > 1 - else self.valid_date_offsets_singular - ) - - for name in valid_offsets: - self._test_offset(offset_name=name, offset_n=n, **kwds) - - def _test_offset(self, offset_name, offset_n, tstart, expected_utc_offset): - offset = DateOffset(**{offset_name: offset_n}) - - t = tstart + offset - if expected_utc_offset is not None: - assert get_utc_offset_hours(t) == expected_utc_offset - - if offset_name == "weeks": - # dates should match - assert t.date() == timedelta(days=7 * offset.kwds["weeks"]) + tstart.date() - # expect the same day of week, hour of day, minute, second, ... - assert ( - t.dayofweek == tstart.dayofweek - and t.hour == tstart.hour - and t.minute == tstart.minute - and t.second == tstart.second - ) - elif offset_name == "days": - # dates should match - assert timedelta(offset.kwds["days"]) + tstart.date() == t.date() - # expect the same hour of day, minute, second, ... - assert ( - t.hour == tstart.hour - and t.minute == tstart.minute - and t.second == tstart.second - ) - elif offset_name in self.valid_date_offsets_singular: - # expect the singular offset value to match between tstart and t - datepart_offset = getattr( - t, offset_name if offset_name != "weekday" else "dayofweek" - ) - assert datepart_offset == offset.kwds[offset_name] - else: - # the offset should be the same as if it was done in UTC - assert t == (tstart.tz_convert("UTC") + offset).tz_convert("US/Pacific") - - def _make_timestamp(self, string, hrs_offset, tz): - if hrs_offset >= 0: - offset_string = f"{hrs_offset:02d}00" - else: - offset_string = f"-{(hrs_offset * -1):02}00" - return Timestamp(string + offset_string).tz_convert(tz) - - def test_springforward_plural(self): - # test moving from standard to daylight savings - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - hrs_post = utc_offsets["utc_offset_daylight"] - self._test_all_offsets( - n=3, - tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), - expected_utc_offset=hrs_post, - ) - - def test_fallback_singular(self): - # in the case of singular offsets, we don't necessarily know which utc - # offset the new Timestamp will wind up in (the tz for 1 month may be - # different from 1 second) so we don't specify an expected_utc_offset - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - self._test_all_offsets( - n=1, - tstart=self._make_timestamp(self.ts_pre_fallback, hrs_pre, tz), - expected_utc_offset=None, - ) - - def test_springforward_singular(self): - for tz, utc_offsets in self.timezone_utc_offsets.items(): - hrs_pre = utc_offsets["utc_offset_standard"] - self._test_all_offsets( - n=1, - tstart=self._make_timestamp(self.ts_pre_springfwd, hrs_pre, tz), - expected_utc_offset=None, - ) - - offset_classes = { - MonthBegin: ["11/2/2012", "12/1/2012"], - MonthEnd: ["11/2/2012", "11/30/2012"], - BMonthBegin: ["11/2/2012", "12/3/2012"], - BMonthEnd: ["11/2/2012", "11/30/2012"], - CBMonthBegin: ["11/2/2012", "12/3/2012"], - CBMonthEnd: ["11/2/2012", "11/30/2012"], - SemiMonthBegin: ["11/2/2012", "11/15/2012"], - SemiMonthEnd: ["11/2/2012", "11/15/2012"], - Week: ["11/2/2012", "11/9/2012"], - YearBegin: ["11/2/2012", "1/1/2013"], - YearEnd: ["11/2/2012", "12/31/2012"], - BYearBegin: ["11/2/2012", "1/1/2013"], - BYearEnd: ["11/2/2012", "12/31/2012"], - QuarterBegin: ["11/2/2012", "12/1/2012"], - QuarterEnd: ["11/2/2012", "12/31/2012"], - BQuarterBegin: ["11/2/2012", "12/3/2012"], - BQuarterEnd: ["11/2/2012", "12/31/2012"], - Day: ["11/4/2012", "11/4/2012 23:00"], - }.items() - - @pytest.mark.parametrize("tup", offset_classes) - def test_all_offset_classes(self, tup): - offset, test_values = tup - - first = Timestamp(test_values[0], tz="US/Eastern") + offset() - second = Timestamp(test_values[1], tz="US/Eastern") - assert first == second - - -# --------------------------------------------------------------------- -def test_get_offset_day_error(): - # subclass of _BaseOffset must override _day_opt attribute, or we should - # get a NotImplementedError - - with pytest.raises(NotImplementedError): - DateOffset()._get_offset_day(datetime.now()) - - -def test_valid_default_arguments(offset_types): - # GH#19142 check that the calling the constructors without passing - # any keyword arguments produce valid offsets - cls = offset_types - cls() - - -@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) -def test_valid_month_attributes(kwd, month_classes): - # GH#18226 - cls = month_classes - # check that we cannot create e.g. MonthEnd(weeks=3) - with pytest.raises(TypeError): - cls(**{kwd: 3}) - - -@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) -def test_valid_relativedelta_kwargs(kwd): - # Check that all the arguments specified in liboffsets.relativedelta_kwds - # are in fact valid relativedelta keyword args - DateOffset(**{kwd: 1}) - - -@pytest.mark.parametrize("kwd", sorted(liboffsets.relativedelta_kwds)) -def test_valid_tick_attributes(kwd, tick_classes): - # GH#18226 - cls = tick_classes - # check that we cannot create e.g. Hour(weeks=3) - with pytest.raises(TypeError): - cls(**{kwd: 3}) - - -def test_validate_n_error(): - with pytest.raises(TypeError): - DateOffset(n="Doh!") - - with pytest.raises(TypeError): - MonthBegin(n=timedelta(1)) - - with pytest.raises(TypeError): - BDay(n=np.array([1, 2], dtype=np.int64)) - - -def test_require_integers(offset_types): - cls = offset_types - with pytest.raises(ValueError): - cls(n=1.5) - - -def test_tick_normalize_raises(tick_classes): - # check that trying to create a Tick object with normalize=True raises - # GH#21427 - cls = tick_classes - with pytest.raises(ValueError): - cls(n=3, normalize=True) - - -def test_weeks_onoffset(): - # GH#18510 Week with weekday = None, normalize = False should always - # be onOffset - offset = Week(n=2, weekday=None) - ts = Timestamp("1862-01-13 09:03:34.873477378+0210", tz="Africa/Lusaka") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - # negative n - offset = Week(n=2, weekday=None) - ts = Timestamp("1856-10-24 16:18:36.556360110-0717", tz="Pacific/Easter") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - -def test_weekofmonth_onoffset(): - # GH#18864 - # Make sure that nanoseconds don't trip up onOffset (and with it apply) - offset = WeekOfMonth(n=2, week=2, weekday=0) - ts = Timestamp("1916-05-15 01:14:49.583410462+0422", tz="Asia/Qyzylorda") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - # negative n - offset = WeekOfMonth(n=-3, week=1, weekday=0) - ts = Timestamp("1980-12-08 03:38:52.878321185+0500", tz="Asia/Oral") - fast = offset.onOffset(ts) - slow = (ts + offset) - offset == ts - assert fast == slow - - -def test_last_week_of_month_on_offset(): - # GH#19036, GH#18977 _adjust_dst was incorrect for LastWeekOfMonth - offset = LastWeekOfMonth(n=4, weekday=6) - ts = Timestamp("1917-05-27 20:55:27.084284178+0200", tz="Europe/Warsaw") - slow = (ts + offset) - offset == ts - fast = offset.onOffset(ts) - assert fast == slow - - # negative n - offset = LastWeekOfMonth(n=-4, weekday=5) - ts = Timestamp("2005-08-27 05:01:42.799392561-0500", tz="America/Rainy_River") - slow = (ts + offset) - offset == ts - fast = offset.onOffset(ts) - assert fast == slow - - -def test_week_add_invalid(): - # Week with weekday should raise TypeError and _not_ AttributeError - # when adding invalid offset - offset = Week(weekday=1) - other = Day() - with pytest.raises(TypeError, match="Cannot add"): - offset + other From 200ee6e6ae9e91d4481d7df97e2013c485418670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Wed, 11 Dec 2019 00:34:35 +0100 Subject: [PATCH 09/12] flake8 warns refactored --- pandas/tests/tseries/offsets/conftest.py | 2 +- .../tests/tseries/offsets/test_business_offsets.py | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pandas/tests/tseries/offsets/conftest.py b/pandas/tests/tseries/offsets/conftest.py index c9fb60b01e109..9cebf88989c72 100644 --- a/pandas/tests/tseries/offsets/conftest.py +++ b/pandas/tests/tseries/offsets/conftest.py @@ -86,4 +86,4 @@ def business_month_classes(request): """ Fixture for month based datetime offsets available for a time series. """ - return request.param \ No newline at end of file + return request.param diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index 5916489119201..28158fe51ae8f 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -21,7 +21,7 @@ import pandas.compat as compat from pandas.compat.numpy import np_datetime64_compat -from pandas.core.indexes.datetimes import DatetimeIndex, _to_M8, date_range +from pandas.core.indexes.datetimes import DatetimeIndex, date_range import pandas.util.testing as tm from pandas.io.pickle import read_pickle @@ -344,7 +344,7 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected, normalize=Fals ts = Timestamp(dt, tz=tz) + Nano(5) if ( - type(offset_s).__name__ == "DateOffset" + type(offset_s).__name__ == "DateOffset" and (funcname == "apply" or normalize) and ts.nanosecond > 0 ): @@ -388,7 +388,8 @@ def test_rollforward(self, business_offset_types): for dt in [sdt, ndt]: expected = expecteds[business_offset_types.__name__] - self._check_offsetfunc_works(business_offset_types, "rollforward", dt, expected) + self._check_offsetfunc_works(business_offset_types, + "rollforward", dt, expected) expected = norm_expected[business_offset_types.__name__] self._check_offsetfunc_works( business_offset_types, "rollforward", dt, expected, normalize=True @@ -422,7 +423,8 @@ def test_rollback(self, business_offset_types): for dt in [sdt, ndt]: expected = expecteds[business_offset_types.__name__] - self._check_offsetfunc_works(business_offset_types, "rollback", dt, expected) + self._check_offsetfunc_works(business_offset_types, + "rollback", dt, expected) expected = norm_expected[business_offset_types.__name__] self._check_offsetfunc_works( @@ -3019,7 +3021,7 @@ def test_rule_code(self): assert alias == get_offset(alias).rule_code assert alias == (get_offset(alias) * 5).rule_code - lst = ["B",] + lst = ["B", ] for k in lst: code, stride = get_freq_code("3" + k) assert isinstance(code, int) From 8a03a664c6a56331d9a1c85b15fb61e4eedeb648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Wed, 11 Dec 2019 06:19:49 +0100 Subject: [PATCH 10/12] black python refactored --- .../tseries/offsets/test_business_offsets.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index 28158fe51ae8f..f52ace81c3de5 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -46,7 +46,7 @@ FY5253Quarter, DateOffset, Nano, - Tick + Tick, ) from .common import assert_offset_equal, assert_onOffset @@ -388,8 +388,9 @@ def test_rollforward(self, business_offset_types): for dt in [sdt, ndt]: expected = expecteds[business_offset_types.__name__] - self._check_offsetfunc_works(business_offset_types, - "rollforward", dt, expected) + self._check_offsetfunc_works( + business_offset_types, "rollforward", dt, expected + ) expected = norm_expected[business_offset_types.__name__] self._check_offsetfunc_works( business_offset_types, "rollforward", dt, expected, normalize=True @@ -423,8 +424,9 @@ def test_rollback(self, business_offset_types): for dt in [sdt, ndt]: expected = expecteds[business_offset_types.__name__] - self._check_offsetfunc_works(business_offset_types, - "rollback", dt, expected) + self._check_offsetfunc_works( + business_offset_types, "rollback", dt, expected + ) expected = norm_expected[business_offset_types.__name__] self._check_offsetfunc_works( @@ -3021,7 +3023,9 @@ def test_rule_code(self): assert alias == get_offset(alias).rule_code assert alias == (get_offset(alias) * 5).rule_code - lst = ["B", ] + lst = [ + "B", + ] for k in lst: code, stride = get_freq_code("3" + k) assert isinstance(code, int) From 736f7fff4160119c4bc2e817607571fdd937beae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Wed, 11 Dec 2019 06:41:18 +0100 Subject: [PATCH 11/12] isort dependencies sorted --- pandas/tests/tseries/offsets/test_business_offsets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_business_offsets.py b/pandas/tests/tseries/offsets/test_business_offsets.py index f52ace81c3de5..f45f529c0d032 100644 --- a/pandas/tests/tseries/offsets/test_business_offsets.py +++ b/pandas/tests/tseries/offsets/test_business_offsets.py @@ -29,8 +29,8 @@ from pandas.tseries.holiday import USFederalHolidayCalendar import pandas.tseries.offsets as offsets from pandas.tseries.offsets import ( - BaseOffset, FY5253, + BaseOffset, BDay, BMonthBegin, BMonthEnd, @@ -43,8 +43,8 @@ CBMonthEnd, CDay, CustomBusinessHour, - FY5253Quarter, DateOffset, + FY5253Quarter, Nano, Tick, ) From d9c3dd950733868497c48ff529c4946c497dd383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Jankowski?= Date: Wed, 11 Dec 2019 08:22:02 +0100 Subject: [PATCH 12/12] Fixed imports in fiscal and yqm --- pandas/tests/tseries/offsets/test_fiscal.py | 2 +- pandas/tests/tseries/offsets/test_yqm_offsets.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_fiscal.py b/pandas/tests/tseries/offsets/test_fiscal.py index c97e0b8493f9c..b92f7dcb1935f 100644 --- a/pandas/tests/tseries/offsets/test_fiscal.py +++ b/pandas/tests/tseries/offsets/test_fiscal.py @@ -14,7 +14,7 @@ from pandas.tseries.offsets import FY5253, FY5253Quarter from .common import assert_offset_equal, assert_onOffset -from .test_offsets import Base, WeekDay +from .test_date_offsets import Base, WeekDay def makeFY5253LastOfMonthQuarter(*args, **kwds): diff --git a/pandas/tests/tseries/offsets/test_yqm_offsets.py b/pandas/tests/tseries/offsets/test_yqm_offsets.py index 12a524d82fcf5..7c02ca2d97abc 100644 --- a/pandas/tests/tseries/offsets/test_yqm_offsets.py +++ b/pandas/tests/tseries/offsets/test_yqm_offsets.py @@ -24,7 +24,7 @@ ) from .common import assert_offset_equal, assert_onOffset -from .test_offsets import Base +from .test_date_offsets import Base # -------------------------------------------------------------------- # Misc