123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- from datetime import datetime
- from dateutil.tz.tz import tzlocal
- import pytest
- from pandas._libs.tslibs import (
- OutOfBoundsDatetime,
- Timestamp,
- )
- from pandas.compat import (
- IS64,
- is_platform_windows,
- )
- from pandas.tseries.offsets import (
- FY5253,
- BDay,
- BMonthBegin,
- BMonthEnd,
- BQuarterBegin,
- BQuarterEnd,
- BusinessHour,
- BYearBegin,
- BYearEnd,
- CBMonthBegin,
- CBMonthEnd,
- CDay,
- CustomBusinessHour,
- DateOffset,
- FY5253Quarter,
- LastWeekOfMonth,
- MonthBegin,
- MonthEnd,
- QuarterEnd,
- SemiMonthBegin,
- SemiMonthEnd,
- Week,
- WeekOfMonth,
- YearBegin,
- YearEnd,
- )
- def _get_offset(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
- @pytest.fixture(
- params=[
- BDay,
- BusinessHour,
- BMonthEnd,
- BMonthBegin,
- BQuarterEnd,
- BQuarterBegin,
- BYearEnd,
- BYearBegin,
- CDay,
- CustomBusinessHour,
- CBMonthEnd,
- CBMonthBegin,
- MonthEnd,
- MonthBegin,
- SemiMonthBegin,
- SemiMonthEnd,
- QuarterEnd,
- LastWeekOfMonth,
- WeekOfMonth,
- Week,
- YearBegin,
- YearEnd,
- FY5253,
- FY5253Quarter,
- DateOffset,
- ]
- )
- def _offset(request):
- return request.param
- @pytest.fixture
- def dt(_offset):
- if _offset in (CBMonthBegin, CBMonthEnd, BDay):
- return Timestamp(2008, 1, 1)
- elif _offset is (CustomBusinessHour, BusinessHour):
- return Timestamp(2014, 7, 1, 10, 00)
- return Timestamp(2008, 1, 2)
- def test_apply_out_of_range(request, tz_naive_fixture, _offset):
- tz = tz_naive_fixture
- # try to create an out-of-bounds result timestamp; if we can't create
- # the offset skip
- try:
- if _offset in (BusinessHour, CustomBusinessHour):
- # Using 10000 in BusinessHour fails in tz check because of DST
- # difference
- offset = _get_offset(_offset, value=100000)
- else:
- offset = _get_offset(_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)
- if tz is not None:
- assert t.tzinfo is not None
- if isinstance(tz, tzlocal) and not IS64 and _offset is not DateOffset:
- # If we hit OutOfBoundsDatetime on non-64 bit machines
- # we'll drop out of the try clause before the next test
- request.node.add_marker(
- pytest.mark.xfail(reason="OverflowError inside tzlocal past 2038")
- )
- elif (
- isinstance(tz, tzlocal)
- and is_platform_windows()
- and _offset in (QuarterEnd, BQuarterBegin, BQuarterEnd)
- ):
- request.node.add_marker(
- pytest.mark.xfail(reason="After GH#49737 t.tzinfo is None on CI")
- )
- assert str(t.tzinfo) == str(result.tzinfo)
- except OutOfBoundsDatetime:
- pass
- except (ValueError, KeyError):
- # we are creating an invalid offset
- # so ignore
- pass
- def test_offsets_compare_equal(_offset):
- # root cause of GH#456: __ne__ was not implemented
- offset1 = _offset()
- offset2 = _offset()
- assert not offset1 != offset2
- assert offset1 == offset2
- @pytest.mark.parametrize(
- "date, offset2",
- [
- [Timestamp(2008, 1, 1), BDay(2)],
- [Timestamp(2014, 7, 1, 10, 00), BusinessHour(n=3)],
- [
- Timestamp(2014, 7, 1, 10),
- CustomBusinessHour(
- holidays=["2014-06-27", Timestamp(2014, 6, 30), Timestamp("2014-07-02")]
- ),
- ],
- [Timestamp(2008, 1, 2), SemiMonthEnd(2)],
- [Timestamp(2008, 1, 2), SemiMonthBegin(2)],
- [Timestamp(2008, 1, 2), Week(2)],
- [Timestamp(2008, 1, 2), WeekOfMonth(2)],
- [Timestamp(2008, 1, 2), LastWeekOfMonth(2)],
- ],
- )
- def test_rsub(date, offset2):
- assert date - offset2 == (-offset2)._apply(date)
- @pytest.mark.parametrize(
- "date, offset2",
- [
- [Timestamp(2008, 1, 1), BDay(2)],
- [Timestamp(2014, 7, 1, 10, 00), BusinessHour(n=3)],
- [
- Timestamp(2014, 7, 1, 10),
- CustomBusinessHour(
- holidays=["2014-06-27", Timestamp(2014, 6, 30), Timestamp("2014-07-02")]
- ),
- ],
- [Timestamp(2008, 1, 2), SemiMonthEnd(2)],
- [Timestamp(2008, 1, 2), SemiMonthBegin(2)],
- [Timestamp(2008, 1, 2), Week(2)],
- [Timestamp(2008, 1, 2), WeekOfMonth(2)],
- [Timestamp(2008, 1, 2), LastWeekOfMonth(2)],
- ],
- )
- def test_radd(date, offset2):
- assert date + offset2 == offset2 + date
- @pytest.mark.parametrize(
- "date, offset_box, offset2",
- [
- [Timestamp(2008, 1, 1), BDay, BDay(2)],
- [Timestamp(2008, 1, 2), SemiMonthEnd, SemiMonthEnd(2)],
- [Timestamp(2008, 1, 2), SemiMonthBegin, SemiMonthBegin(2)],
- [Timestamp(2008, 1, 2), Week, Week(2)],
- [Timestamp(2008, 1, 2), WeekOfMonth, WeekOfMonth(2)],
- [Timestamp(2008, 1, 2), LastWeekOfMonth, LastWeekOfMonth(2)],
- ],
- )
- def test_sub(date, offset_box, offset2):
- off = offset2
- msg = "Cannot subtract datetime from offset"
- with pytest.raises(TypeError, match=msg):
- off - date
- assert 2 * off - off == off
- assert date - offset2 == date + offset_box(-2)
- assert date - offset2 == date - (2 * off - off)
- @pytest.mark.parametrize(
- "offset_box, offset1",
- [
- [BDay, BDay()],
- [LastWeekOfMonth, LastWeekOfMonth()],
- [WeekOfMonth, WeekOfMonth()],
- [Week, Week()],
- [SemiMonthBegin, SemiMonthBegin()],
- [SemiMonthEnd, SemiMonthEnd()],
- [CustomBusinessHour, CustomBusinessHour(weekmask="Tue Wed Thu Fri")],
- [BusinessHour, BusinessHour()],
- ],
- )
- def test_Mult1(offset_box, offset1, dt):
- assert dt + 10 * offset1 == dt + offset_box(10)
- assert dt + 5 * offset1 == dt + offset_box(5)
- def test_compare_str(_offset):
- # GH#23524
- # comparing to strings that cannot be cast to DateOffsets should
- # not raise for __eq__ or __ne__
- off = _get_offset(_offset)
- assert not off == "infer"
- assert off != "foo"
- # Note: inequalities are only implemented for Tick subclasses;
- # tests for this are in test_ticks
|