364 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
Tests for the following offsets:
 | 
						|
- Week
 | 
						|
- WeekOfMonth
 | 
						|
- LastWeekOfMonth
 | 
						|
"""
 | 
						|
from datetime import (
 | 
						|
    datetime,
 | 
						|
    timedelta,
 | 
						|
)
 | 
						|
 | 
						|
import pytest
 | 
						|
 | 
						|
from pandas._libs.tslibs import Timestamp
 | 
						|
from pandas._libs.tslibs.offsets import (
 | 
						|
    Day,
 | 
						|
    LastWeekOfMonth,
 | 
						|
    Week,
 | 
						|
    WeekOfMonth,
 | 
						|
)
 | 
						|
 | 
						|
from pandas.tests.tseries.offsets.common import (
 | 
						|
    Base,
 | 
						|
    WeekDay,
 | 
						|
    assert_is_on_offset,
 | 
						|
    assert_offset_equal,
 | 
						|
)
 | 
						|
 | 
						|
 | 
						|
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)) == "<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, match="Day must be"):
 | 
						|
            Week(weekday=7)
 | 
						|
 | 
						|
        with pytest.raises(ValueError, match="Day must be"):
 | 
						|
            Week(weekday=-1)
 | 
						|
 | 
						|
    def test_is_anchored(self):
 | 
						|
        assert Week(weekday=0).is_anchored()
 | 
						|
        assert not Week().is_anchored()
 | 
						|
        assert not Week(2, weekday=2).is_anchored()
 | 
						|
        assert not Week(2).is_anchored()
 | 
						|
 | 
						|
    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_is_on_offset(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_is_on_offset(offset, date, expected)
 | 
						|
 | 
						|
    @pytest.mark.parametrize(
 | 
						|
        "n,date",
 | 
						|
        [
 | 
						|
            (2, "1862-01-13 09:03:34.873477378+0210"),
 | 
						|
            (-2, "1856-10-24 16:18:36.556360110-0717"),
 | 
						|
        ],
 | 
						|
    )
 | 
						|
    def test_is_on_offset_weekday_none(self, n, date):
 | 
						|
        # GH 18510 Week with weekday = None, normalize = False
 | 
						|
        # should always be is_on_offset
 | 
						|
        offset = Week(n=n, weekday=None)
 | 
						|
        ts = Timestamp(date, tz="Africa/Lusaka")
 | 
						|
        fast = offset.is_on_offset(ts)
 | 
						|
        slow = (ts + offset) - offset == ts
 | 
						|
        assert fast == slow
 | 
						|
 | 
						|
    def test_week_add_invalid(self):
 | 
						|
        # 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
 | 
						|
 | 
						|
 | 
						|
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)) == "<WeekOfMonth: week=2, weekday=1>"
 | 
						|
        )
 | 
						|
 | 
						|
    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_is_on_offset(self, case):
 | 
						|
        week, weekday, dt, expected = case
 | 
						|
        offset = WeekOfMonth(week=week, weekday=weekday)
 | 
						|
        assert offset.is_on_offset(dt) == expected
 | 
						|
 | 
						|
    @pytest.mark.parametrize(
 | 
						|
        "n,week,date,tz",
 | 
						|
        [
 | 
						|
            (2, 2, "1916-05-15 01:14:49.583410462+0422", "Asia/Qyzylorda"),
 | 
						|
            (-3, 1, "1980-12-08 03:38:52.878321185+0500", "Asia/Oral"),
 | 
						|
        ],
 | 
						|
    )
 | 
						|
    def test_is_on_offset_nanoseconds(self, n, week, date, tz):
 | 
						|
        # GH 18864
 | 
						|
        # Make sure that nanoseconds don't trip up is_on_offset (and with it apply)
 | 
						|
        offset = WeekOfMonth(n=n, week=week, weekday=0)
 | 
						|
        ts = Timestamp(date, tz=tz)
 | 
						|
        fast = offset.is_on_offset(ts)
 | 
						|
        slow = (ts + offset) - offset == ts
 | 
						|
        assert fast == slow
 | 
						|
 | 
						|
 | 
						|
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_is_on_offset(self, case):
 | 
						|
        weekday, dt, expected = case
 | 
						|
        offset = LastWeekOfMonth(weekday=weekday)
 | 
						|
        assert offset.is_on_offset(dt) == expected
 | 
						|
 | 
						|
    @pytest.mark.parametrize(
 | 
						|
        "n,weekday,date,tz",
 | 
						|
        [
 | 
						|
            (4, 6, "1917-05-27 20:55:27.084284178+0200", "Europe/Warsaw"),
 | 
						|
            (-4, 5, "2005-08-27 05:01:42.799392561-0500", "America/Rainy_River"),
 | 
						|
        ],
 | 
						|
    )
 | 
						|
    def test_last_week_of_month_on_offset(self, n, weekday, date, tz):
 | 
						|
        # GH 19036, GH 18977 _adjust_dst was incorrect for LastWeekOfMonth
 | 
						|
        offset = LastWeekOfMonth(n=n, weekday=weekday)
 | 
						|
        ts = Timestamp(date, tz=tz)
 | 
						|
        slow = (ts + offset) - offset == ts
 | 
						|
        fast = offset.is_on_offset(ts)
 | 
						|
        assert fast == slow
 | 
						|
 | 
						|
    def test_repr(self):
 | 
						|
        assert (
 | 
						|
            repr(LastWeekOfMonth(n=2, weekday=1)) == "<2 * LastWeekOfMonths: weekday=1>"
 | 
						|
        )
 |