1"""
2Tests for Year, Quarter, and Month-based DateOffset subclasses
3"""
4from datetime import datetime
5
6import pytest
7
8import pandas as pd
9from pandas import Timestamp
10
11from pandas.tseries.offsets import (
12    BMonthBegin,
13    BMonthEnd,
14    BQuarterBegin,
15    BQuarterEnd,
16    BYearBegin,
17    BYearEnd,
18    MonthBegin,
19    MonthEnd,
20    QuarterBegin,
21    QuarterEnd,
22    YearBegin,
23    YearEnd,
24)
25
26from .common import assert_is_on_offset, assert_offset_equal
27from .test_offsets import Base
28
29# --------------------------------------------------------------------
30# Misc
31
32
33def test_quarterly_dont_normalize():
34    date = datetime(2012, 3, 31, 5, 30)
35
36    offsets = (QuarterBegin, QuarterEnd, BQuarterEnd, BQuarterBegin)
37
38    for klass in offsets:
39        result = date + klass()
40        assert result.time() == date.time()
41
42
43@pytest.mark.parametrize("n", [-2, 1])
44@pytest.mark.parametrize(
45    "cls",
46    [
47        MonthBegin,
48        MonthEnd,
49        BMonthBegin,
50        BMonthEnd,
51        QuarterBegin,
52        QuarterEnd,
53        BQuarterBegin,
54        BQuarterEnd,
55        YearBegin,
56        YearEnd,
57        BYearBegin,
58        BYearEnd,
59    ],
60)
61def test_apply_index(cls, n):
62    offset = cls(n=n)
63    rng = pd.date_range(start="1/1/2000", periods=100000, freq="T")
64    ser = pd.Series(rng)
65
66    res = rng + offset
67    assert res.freq is None  # not retained
68    assert res[0] == rng[0] + offset
69    assert res[-1] == rng[-1] + offset
70    res2 = ser + offset
71    # apply_index is only for indexes, not series, so no res2_v2
72    assert res2.iloc[0] == ser.iloc[0] + offset
73    assert res2.iloc[-1] == ser.iloc[-1] + offset
74
75
76@pytest.mark.parametrize(
77    "offset", [QuarterBegin(), QuarterEnd(), BQuarterBegin(), BQuarterEnd()]
78)
79def test_on_offset(offset):
80    dates = [
81        datetime(2016, m, d)
82        for m in [10, 11, 12]
83        for d in [1, 2, 3, 28, 29, 30, 31]
84        if not (m == 11 and d == 31)
85    ]
86    for date in dates:
87        res = offset.is_on_offset(date)
88        slow_version = date == (date + offset) - offset
89        assert res == slow_version
90
91
92# --------------------------------------------------------------------
93# Months
94
95
96class TestMonthBegin(Base):
97    _offset = MonthBegin
98
99    offset_cases = []
100    # NOTE: I'm not entirely happy with the logic here for Begin -ss
101    # see thread 'offset conventions' on the ML
102    offset_cases.append(
103        (
104            MonthBegin(),
105            {
106                datetime(2008, 1, 31): datetime(2008, 2, 1),
107                datetime(2008, 2, 1): datetime(2008, 3, 1),
108                datetime(2006, 12, 31): datetime(2007, 1, 1),
109                datetime(2006, 12, 1): datetime(2007, 1, 1),
110                datetime(2007, 1, 31): datetime(2007, 2, 1),
111            },
112        )
113    )
114
115    offset_cases.append(
116        (
117            MonthBegin(0),
118            {
119                datetime(2008, 1, 31): datetime(2008, 2, 1),
120                datetime(2008, 1, 1): datetime(2008, 1, 1),
121                datetime(2006, 12, 3): datetime(2007, 1, 1),
122                datetime(2007, 1, 31): datetime(2007, 2, 1),
123            },
124        )
125    )
126
127    offset_cases.append(
128        (
129            MonthBegin(2),
130            {
131                datetime(2008, 2, 29): datetime(2008, 4, 1),
132                datetime(2008, 1, 31): datetime(2008, 3, 1),
133                datetime(2006, 12, 31): datetime(2007, 2, 1),
134                datetime(2007, 12, 28): datetime(2008, 2, 1),
135                datetime(2007, 1, 1): datetime(2007, 3, 1),
136                datetime(2006, 11, 1): datetime(2007, 1, 1),
137            },
138        )
139    )
140
141    offset_cases.append(
142        (
143            MonthBegin(-1),
144            {
145                datetime(2007, 1, 1): datetime(2006, 12, 1),
146                datetime(2008, 5, 31): datetime(2008, 5, 1),
147                datetime(2008, 12, 31): datetime(2008, 12, 1),
148                datetime(2006, 12, 29): datetime(2006, 12, 1),
149                datetime(2006, 1, 2): datetime(2006, 1, 1),
150            },
151        )
152    )
153
154    @pytest.mark.parametrize("case", offset_cases)
155    def test_offset(self, case):
156        offset, cases = case
157        for base, expected in cases.items():
158            assert_offset_equal(offset, base, expected)
159
160
161class TestMonthEnd(Base):
162    _offset = MonthEnd
163
164    def test_day_of_month(self):
165        dt = datetime(2007, 1, 1)
166        offset = MonthEnd()
167
168        result = dt + offset
169        assert result == Timestamp(2007, 1, 31)
170
171        result = result + offset
172        assert result == Timestamp(2007, 2, 28)
173
174    def test_normalize(self):
175        dt = datetime(2007, 1, 1, 3)
176
177        result = dt + MonthEnd(normalize=True)
178        expected = dt.replace(hour=0) + MonthEnd()
179        assert result == expected
180
181    offset_cases = []
182    offset_cases.append(
183        (
184            MonthEnd(),
185            {
186                datetime(2008, 1, 1): datetime(2008, 1, 31),
187                datetime(2008, 1, 31): datetime(2008, 2, 29),
188                datetime(2006, 12, 29): datetime(2006, 12, 31),
189                datetime(2006, 12, 31): datetime(2007, 1, 31),
190                datetime(2007, 1, 1): datetime(2007, 1, 31),
191                datetime(2006, 12, 1): datetime(2006, 12, 31),
192            },
193        )
194    )
195
196    offset_cases.append(
197        (
198            MonthEnd(0),
199            {
200                datetime(2008, 1, 1): datetime(2008, 1, 31),
201                datetime(2008, 1, 31): datetime(2008, 1, 31),
202                datetime(2006, 12, 29): datetime(2006, 12, 31),
203                datetime(2006, 12, 31): datetime(2006, 12, 31),
204                datetime(2007, 1, 1): datetime(2007, 1, 31),
205            },
206        )
207    )
208
209    offset_cases.append(
210        (
211            MonthEnd(2),
212            {
213                datetime(2008, 1, 1): datetime(2008, 2, 29),
214                datetime(2008, 1, 31): datetime(2008, 3, 31),
215                datetime(2006, 12, 29): datetime(2007, 1, 31),
216                datetime(2006, 12, 31): datetime(2007, 2, 28),
217                datetime(2007, 1, 1): datetime(2007, 2, 28),
218                datetime(2006, 11, 1): datetime(2006, 12, 31),
219            },
220        )
221    )
222
223    offset_cases.append(
224        (
225            MonthEnd(-1),
226            {
227                datetime(2007, 1, 1): datetime(2006, 12, 31),
228                datetime(2008, 6, 30): datetime(2008, 5, 31),
229                datetime(2008, 12, 31): datetime(2008, 11, 30),
230                datetime(2006, 12, 29): datetime(2006, 11, 30),
231                datetime(2006, 12, 30): datetime(2006, 11, 30),
232                datetime(2007, 1, 1): datetime(2006, 12, 31),
233            },
234        )
235    )
236
237    @pytest.mark.parametrize("case", offset_cases)
238    def test_offset(self, case):
239        offset, cases = case
240        for base, expected in cases.items():
241            assert_offset_equal(offset, base, expected)
242
243    on_offset_cases = [
244        (MonthEnd(), datetime(2007, 12, 31), True),
245        (MonthEnd(), datetime(2008, 1, 1), False),
246    ]
247
248    @pytest.mark.parametrize("case", on_offset_cases)
249    def test_is_on_offset(self, case):
250        offset, dt, expected = case
251        assert_is_on_offset(offset, dt, expected)
252
253
254class TestBMonthBegin(Base):
255    _offset = BMonthBegin
256
257    def test_offsets_compare_equal(self):
258        # root cause of #456
259        offset1 = BMonthBegin()
260        offset2 = BMonthBegin()
261        assert not offset1 != offset2
262
263    offset_cases = []
264    offset_cases.append(
265        (
266            BMonthBegin(),
267            {
268                datetime(2008, 1, 1): datetime(2008, 2, 1),
269                datetime(2008, 1, 31): datetime(2008, 2, 1),
270                datetime(2006, 12, 29): datetime(2007, 1, 1),
271                datetime(2006, 12, 31): datetime(2007, 1, 1),
272                datetime(2006, 9, 1): datetime(2006, 10, 2),
273                datetime(2007, 1, 1): datetime(2007, 2, 1),
274                datetime(2006, 12, 1): datetime(2007, 1, 1),
275            },
276        )
277    )
278
279    offset_cases.append(
280        (
281            BMonthBegin(0),
282            {
283                datetime(2008, 1, 1): datetime(2008, 1, 1),
284                datetime(2006, 10, 2): datetime(2006, 10, 2),
285                datetime(2008, 1, 31): datetime(2008, 2, 1),
286                datetime(2006, 12, 29): datetime(2007, 1, 1),
287                datetime(2006, 12, 31): datetime(2007, 1, 1),
288                datetime(2006, 9, 15): datetime(2006, 10, 2),
289            },
290        )
291    )
292
293    offset_cases.append(
294        (
295            BMonthBegin(2),
296            {
297                datetime(2008, 1, 1): datetime(2008, 3, 3),
298                datetime(2008, 1, 15): datetime(2008, 3, 3),
299                datetime(2006, 12, 29): datetime(2007, 2, 1),
300                datetime(2006, 12, 31): datetime(2007, 2, 1),
301                datetime(2007, 1, 1): datetime(2007, 3, 1),
302                datetime(2006, 11, 1): datetime(2007, 1, 1),
303            },
304        )
305    )
306
307    offset_cases.append(
308        (
309            BMonthBegin(-1),
310            {
311                datetime(2007, 1, 1): datetime(2006, 12, 1),
312                datetime(2008, 6, 30): datetime(2008, 6, 2),
313                datetime(2008, 6, 1): datetime(2008, 5, 1),
314                datetime(2008, 3, 10): datetime(2008, 3, 3),
315                datetime(2008, 12, 31): datetime(2008, 12, 1),
316                datetime(2006, 12, 29): datetime(2006, 12, 1),
317                datetime(2006, 12, 30): datetime(2006, 12, 1),
318                datetime(2007, 1, 1): datetime(2006, 12, 1),
319            },
320        )
321    )
322
323    @pytest.mark.parametrize("case", offset_cases)
324    def test_offset(self, case):
325        offset, cases = case
326        for base, expected in cases.items():
327            assert_offset_equal(offset, base, expected)
328
329    on_offset_cases = [
330        (BMonthBegin(), datetime(2007, 12, 31), False),
331        (BMonthBegin(), datetime(2008, 1, 1), True),
332        (BMonthBegin(), datetime(2001, 4, 2), True),
333        (BMonthBegin(), datetime(2008, 3, 3), True),
334    ]
335
336    @pytest.mark.parametrize("case", on_offset_cases)
337    def test_is_on_offset(self, case):
338        offset, dt, expected = case
339        assert_is_on_offset(offset, dt, expected)
340
341
342class TestBMonthEnd(Base):
343    _offset = BMonthEnd
344
345    def test_normalize(self):
346        dt = datetime(2007, 1, 1, 3)
347
348        result = dt + BMonthEnd(normalize=True)
349        expected = dt.replace(hour=0) + BMonthEnd()
350        assert result == expected
351
352    def test_offsets_compare_equal(self):
353        # root cause of #456
354        offset1 = BMonthEnd()
355        offset2 = BMonthEnd()
356        assert not offset1 != offset2
357
358    offset_cases = []
359    offset_cases.append(
360        (
361            BMonthEnd(),
362            {
363                datetime(2008, 1, 1): datetime(2008, 1, 31),
364                datetime(2008, 1, 31): datetime(2008, 2, 29),
365                datetime(2006, 12, 29): datetime(2007, 1, 31),
366                datetime(2006, 12, 31): datetime(2007, 1, 31),
367                datetime(2007, 1, 1): datetime(2007, 1, 31),
368                datetime(2006, 12, 1): datetime(2006, 12, 29),
369            },
370        )
371    )
372
373    offset_cases.append(
374        (
375            BMonthEnd(0),
376            {
377                datetime(2008, 1, 1): datetime(2008, 1, 31),
378                datetime(2008, 1, 31): datetime(2008, 1, 31),
379                datetime(2006, 12, 29): datetime(2006, 12, 29),
380                datetime(2006, 12, 31): datetime(2007, 1, 31),
381                datetime(2007, 1, 1): datetime(2007, 1, 31),
382            },
383        )
384    )
385
386    offset_cases.append(
387        (
388            BMonthEnd(2),
389            {
390                datetime(2008, 1, 1): datetime(2008, 2, 29),
391                datetime(2008, 1, 31): datetime(2008, 3, 31),
392                datetime(2006, 12, 29): datetime(2007, 2, 28),
393                datetime(2006, 12, 31): datetime(2007, 2, 28),
394                datetime(2007, 1, 1): datetime(2007, 2, 28),
395                datetime(2006, 11, 1): datetime(2006, 12, 29),
396            },
397        )
398    )
399
400    offset_cases.append(
401        (
402            BMonthEnd(-1),
403            {
404                datetime(2007, 1, 1): datetime(2006, 12, 29),
405                datetime(2008, 6, 30): datetime(2008, 5, 30),
406                datetime(2008, 12, 31): datetime(2008, 11, 28),
407                datetime(2006, 12, 29): datetime(2006, 11, 30),
408                datetime(2006, 12, 30): datetime(2006, 12, 29),
409                datetime(2007, 1, 1): datetime(2006, 12, 29),
410            },
411        )
412    )
413
414    @pytest.mark.parametrize("case", offset_cases)
415    def test_offset(self, case):
416        offset, cases = case
417        for base, expected in cases.items():
418            assert_offset_equal(offset, base, expected)
419
420    on_offset_cases = [
421        (BMonthEnd(), datetime(2007, 12, 31), True),
422        (BMonthEnd(), datetime(2008, 1, 1), False),
423    ]
424
425    @pytest.mark.parametrize("case", on_offset_cases)
426    def test_is_on_offset(self, case):
427        offset, dt, expected = case
428        assert_is_on_offset(offset, dt, expected)
429
430
431# --------------------------------------------------------------------
432# Quarters
433
434
435class TestQuarterBegin(Base):
436    def test_repr(self):
437        expected = "<QuarterBegin: startingMonth=3>"
438        assert repr(QuarterBegin()) == expected
439        expected = "<QuarterBegin: startingMonth=3>"
440        assert repr(QuarterBegin(startingMonth=3)) == expected
441        expected = "<QuarterBegin: startingMonth=1>"
442        assert repr(QuarterBegin(startingMonth=1)) == expected
443
444    def test_is_anchored(self):
445        assert QuarterBegin(startingMonth=1).is_anchored()
446        assert QuarterBegin().is_anchored()
447        assert not QuarterBegin(2, startingMonth=1).is_anchored()
448
449    def test_offset_corner_case(self):
450        # corner
451        offset = QuarterBegin(n=-1, startingMonth=1)
452        assert datetime(2010, 2, 1) + offset == datetime(2010, 1, 1)
453
454    offset_cases = []
455    offset_cases.append(
456        (
457            QuarterBegin(startingMonth=1),
458            {
459                datetime(2007, 12, 1): datetime(2008, 1, 1),
460                datetime(2008, 1, 1): datetime(2008, 4, 1),
461                datetime(2008, 2, 15): datetime(2008, 4, 1),
462                datetime(2008, 2, 29): datetime(2008, 4, 1),
463                datetime(2008, 3, 15): datetime(2008, 4, 1),
464                datetime(2008, 3, 31): datetime(2008, 4, 1),
465                datetime(2008, 4, 15): datetime(2008, 7, 1),
466                datetime(2008, 4, 1): datetime(2008, 7, 1),
467            },
468        )
469    )
470
471    offset_cases.append(
472        (
473            QuarterBegin(startingMonth=2),
474            {
475                datetime(2008, 1, 1): datetime(2008, 2, 1),
476                datetime(2008, 1, 31): datetime(2008, 2, 1),
477                datetime(2008, 1, 15): datetime(2008, 2, 1),
478                datetime(2008, 2, 29): datetime(2008, 5, 1),
479                datetime(2008, 3, 15): datetime(2008, 5, 1),
480                datetime(2008, 3, 31): datetime(2008, 5, 1),
481                datetime(2008, 4, 15): datetime(2008, 5, 1),
482                datetime(2008, 4, 30): datetime(2008, 5, 1),
483            },
484        )
485    )
486
487    offset_cases.append(
488        (
489            QuarterBegin(startingMonth=1, n=0),
490            {
491                datetime(2008, 1, 1): datetime(2008, 1, 1),
492                datetime(2008, 12, 1): datetime(2009, 1, 1),
493                datetime(2008, 1, 1): datetime(2008, 1, 1),
494                datetime(2008, 2, 15): datetime(2008, 4, 1),
495                datetime(2008, 2, 29): datetime(2008, 4, 1),
496                datetime(2008, 3, 15): datetime(2008, 4, 1),
497                datetime(2008, 3, 31): datetime(2008, 4, 1),
498                datetime(2008, 4, 15): datetime(2008, 7, 1),
499                datetime(2008, 4, 30): datetime(2008, 7, 1),
500            },
501        )
502    )
503
504    offset_cases.append(
505        (
506            QuarterBegin(startingMonth=1, n=-1),
507            {
508                datetime(2008, 1, 1): datetime(2007, 10, 1),
509                datetime(2008, 1, 31): datetime(2008, 1, 1),
510                datetime(2008, 2, 15): datetime(2008, 1, 1),
511                datetime(2008, 2, 29): datetime(2008, 1, 1),
512                datetime(2008, 3, 15): datetime(2008, 1, 1),
513                datetime(2008, 3, 31): datetime(2008, 1, 1),
514                datetime(2008, 4, 15): datetime(2008, 4, 1),
515                datetime(2008, 4, 30): datetime(2008, 4, 1),
516                datetime(2008, 7, 1): datetime(2008, 4, 1),
517            },
518        )
519    )
520
521    offset_cases.append(
522        (
523            QuarterBegin(startingMonth=1, n=2),
524            {
525                datetime(2008, 1, 1): datetime(2008, 7, 1),
526                datetime(2008, 2, 15): datetime(2008, 7, 1),
527                datetime(2008, 2, 29): datetime(2008, 7, 1),
528                datetime(2008, 3, 15): datetime(2008, 7, 1),
529                datetime(2008, 3, 31): datetime(2008, 7, 1),
530                datetime(2008, 4, 15): datetime(2008, 10, 1),
531                datetime(2008, 4, 1): datetime(2008, 10, 1),
532            },
533        )
534    )
535
536    @pytest.mark.parametrize("case", offset_cases)
537    def test_offset(self, case):
538        offset, cases = case
539        for base, expected in cases.items():
540            assert_offset_equal(offset, base, expected)
541
542
543class TestQuarterEnd(Base):
544    _offset = QuarterEnd
545
546    def test_repr(self):
547        expected = "<QuarterEnd: startingMonth=3>"
548        assert repr(QuarterEnd()) == expected
549        expected = "<QuarterEnd: startingMonth=3>"
550        assert repr(QuarterEnd(startingMonth=3)) == expected
551        expected = "<QuarterEnd: startingMonth=1>"
552        assert repr(QuarterEnd(startingMonth=1)) == expected
553
554    def test_is_anchored(self):
555        assert QuarterEnd(startingMonth=1).is_anchored()
556        assert QuarterEnd().is_anchored()
557        assert not QuarterEnd(2, startingMonth=1).is_anchored()
558
559    def test_offset_corner_case(self):
560        # corner
561        offset = QuarterEnd(n=-1, startingMonth=1)
562        assert datetime(2010, 2, 1) + offset == datetime(2010, 1, 31)
563
564    offset_cases = []
565    offset_cases.append(
566        (
567            QuarterEnd(startingMonth=1),
568            {
569                datetime(2008, 1, 1): datetime(2008, 1, 31),
570                datetime(2008, 1, 31): datetime(2008, 4, 30),
571                datetime(2008, 2, 15): datetime(2008, 4, 30),
572                datetime(2008, 2, 29): datetime(2008, 4, 30),
573                datetime(2008, 3, 15): datetime(2008, 4, 30),
574                datetime(2008, 3, 31): datetime(2008, 4, 30),
575                datetime(2008, 4, 15): datetime(2008, 4, 30),
576                datetime(2008, 4, 30): datetime(2008, 7, 31),
577            },
578        )
579    )
580
581    offset_cases.append(
582        (
583            QuarterEnd(startingMonth=2),
584            {
585                datetime(2008, 1, 1): datetime(2008, 2, 29),
586                datetime(2008, 1, 31): datetime(2008, 2, 29),
587                datetime(2008, 2, 15): datetime(2008, 2, 29),
588                datetime(2008, 2, 29): datetime(2008, 5, 31),
589                datetime(2008, 3, 15): datetime(2008, 5, 31),
590                datetime(2008, 3, 31): datetime(2008, 5, 31),
591                datetime(2008, 4, 15): datetime(2008, 5, 31),
592                datetime(2008, 4, 30): datetime(2008, 5, 31),
593            },
594        )
595    )
596
597    offset_cases.append(
598        (
599            QuarterEnd(startingMonth=1, n=0),
600            {
601                datetime(2008, 1, 1): datetime(2008, 1, 31),
602                datetime(2008, 1, 31): datetime(2008, 1, 31),
603                datetime(2008, 2, 15): datetime(2008, 4, 30),
604                datetime(2008, 2, 29): datetime(2008, 4, 30),
605                datetime(2008, 3, 15): datetime(2008, 4, 30),
606                datetime(2008, 3, 31): datetime(2008, 4, 30),
607                datetime(2008, 4, 15): datetime(2008, 4, 30),
608                datetime(2008, 4, 30): datetime(2008, 4, 30),
609            },
610        )
611    )
612
613    offset_cases.append(
614        (
615            QuarterEnd(startingMonth=1, n=-1),
616            {
617                datetime(2008, 1, 1): datetime(2007, 10, 31),
618                datetime(2008, 1, 31): datetime(2007, 10, 31),
619                datetime(2008, 2, 15): datetime(2008, 1, 31),
620                datetime(2008, 2, 29): datetime(2008, 1, 31),
621                datetime(2008, 3, 15): datetime(2008, 1, 31),
622                datetime(2008, 3, 31): datetime(2008, 1, 31),
623                datetime(2008, 4, 15): datetime(2008, 1, 31),
624                datetime(2008, 4, 30): datetime(2008, 1, 31),
625                datetime(2008, 7, 1): datetime(2008, 4, 30),
626            },
627        )
628    )
629
630    offset_cases.append(
631        (
632            QuarterEnd(startingMonth=1, n=2),
633            {
634                datetime(2008, 1, 31): datetime(2008, 7, 31),
635                datetime(2008, 2, 15): datetime(2008, 7, 31),
636                datetime(2008, 2, 29): datetime(2008, 7, 31),
637                datetime(2008, 3, 15): datetime(2008, 7, 31),
638                datetime(2008, 3, 31): datetime(2008, 7, 31),
639                datetime(2008, 4, 15): datetime(2008, 7, 31),
640                datetime(2008, 4, 30): datetime(2008, 10, 31),
641            },
642        )
643    )
644
645    @pytest.mark.parametrize("case", offset_cases)
646    def test_offset(self, case):
647        offset, cases = case
648        for base, expected in cases.items():
649            assert_offset_equal(offset, base, expected)
650
651    on_offset_cases = [
652        (QuarterEnd(1, startingMonth=1), datetime(2008, 1, 31), True),
653        (QuarterEnd(1, startingMonth=1), datetime(2007, 12, 31), False),
654        (QuarterEnd(1, startingMonth=1), datetime(2008, 2, 29), False),
655        (QuarterEnd(1, startingMonth=1), datetime(2007, 3, 30), False),
656        (QuarterEnd(1, startingMonth=1), datetime(2007, 3, 31), False),
657        (QuarterEnd(1, startingMonth=1), datetime(2008, 4, 30), True),
658        (QuarterEnd(1, startingMonth=1), datetime(2008, 5, 30), False),
659        (QuarterEnd(1, startingMonth=1), datetime(2008, 5, 31), False),
660        (QuarterEnd(1, startingMonth=1), datetime(2007, 6, 29), False),
661        (QuarterEnd(1, startingMonth=1), datetime(2007, 6, 30), False),
662        (QuarterEnd(1, startingMonth=2), datetime(2008, 1, 31), False),
663        (QuarterEnd(1, startingMonth=2), datetime(2007, 12, 31), False),
664        (QuarterEnd(1, startingMonth=2), datetime(2008, 2, 29), True),
665        (QuarterEnd(1, startingMonth=2), datetime(2007, 3, 30), False),
666        (QuarterEnd(1, startingMonth=2), datetime(2007, 3, 31), False),
667        (QuarterEnd(1, startingMonth=2), datetime(2008, 4, 30), False),
668        (QuarterEnd(1, startingMonth=2), datetime(2008, 5, 30), False),
669        (QuarterEnd(1, startingMonth=2), datetime(2008, 5, 31), True),
670        (QuarterEnd(1, startingMonth=2), datetime(2007, 6, 29), False),
671        (QuarterEnd(1, startingMonth=2), datetime(2007, 6, 30), False),
672        (QuarterEnd(1, startingMonth=3), datetime(2008, 1, 31), False),
673        (QuarterEnd(1, startingMonth=3), datetime(2007, 12, 31), True),
674        (QuarterEnd(1, startingMonth=3), datetime(2008, 2, 29), False),
675        (QuarterEnd(1, startingMonth=3), datetime(2007, 3, 30), False),
676        (QuarterEnd(1, startingMonth=3), datetime(2007, 3, 31), True),
677        (QuarterEnd(1, startingMonth=3), datetime(2008, 4, 30), False),
678        (QuarterEnd(1, startingMonth=3), datetime(2008, 5, 30), False),
679        (QuarterEnd(1, startingMonth=3), datetime(2008, 5, 31), False),
680        (QuarterEnd(1, startingMonth=3), datetime(2007, 6, 29), False),
681        (QuarterEnd(1, startingMonth=3), datetime(2007, 6, 30), True),
682    ]
683
684    @pytest.mark.parametrize("case", on_offset_cases)
685    def test_is_on_offset(self, case):
686        offset, dt, expected = case
687        assert_is_on_offset(offset, dt, expected)
688
689
690class TestBQuarterBegin(Base):
691    _offset = BQuarterBegin
692
693    def test_repr(self):
694        expected = "<BusinessQuarterBegin: startingMonth=3>"
695        assert repr(BQuarterBegin()) == expected
696        expected = "<BusinessQuarterBegin: startingMonth=3>"
697        assert repr(BQuarterBegin(startingMonth=3)) == expected
698        expected = "<BusinessQuarterBegin: startingMonth=1>"
699        assert repr(BQuarterBegin(startingMonth=1)) == expected
700
701    def test_is_anchored(self):
702        assert BQuarterBegin(startingMonth=1).is_anchored()
703        assert BQuarterBegin().is_anchored()
704        assert not BQuarterBegin(2, startingMonth=1).is_anchored()
705
706    def test_offset_corner_case(self):
707        # corner
708        offset = BQuarterBegin(n=-1, startingMonth=1)
709        assert datetime(2007, 4, 3) + offset == datetime(2007, 4, 2)
710
711    offset_cases = []
712    offset_cases.append(
713        (
714            BQuarterBegin(startingMonth=1),
715            {
716                datetime(2008, 1, 1): datetime(2008, 4, 1),
717                datetime(2008, 1, 31): datetime(2008, 4, 1),
718                datetime(2008, 2, 15): datetime(2008, 4, 1),
719                datetime(2008, 2, 29): datetime(2008, 4, 1),
720                datetime(2008, 3, 15): datetime(2008, 4, 1),
721                datetime(2008, 3, 31): datetime(2008, 4, 1),
722                datetime(2008, 4, 15): datetime(2008, 7, 1),
723                datetime(2007, 3, 15): datetime(2007, 4, 2),
724                datetime(2007, 2, 28): datetime(2007, 4, 2),
725                datetime(2007, 1, 1): datetime(2007, 4, 2),
726                datetime(2007, 4, 15): datetime(2007, 7, 2),
727                datetime(2007, 7, 1): datetime(2007, 7, 2),
728                datetime(2007, 4, 1): datetime(2007, 4, 2),
729                datetime(2007, 4, 2): datetime(2007, 7, 2),
730                datetime(2008, 4, 30): datetime(2008, 7, 1),
731            },
732        )
733    )
734
735    offset_cases.append(
736        (
737            BQuarterBegin(startingMonth=2),
738            {
739                datetime(2008, 1, 1): datetime(2008, 2, 1),
740                datetime(2008, 1, 31): datetime(2008, 2, 1),
741                datetime(2008, 1, 15): datetime(2008, 2, 1),
742                datetime(2008, 2, 29): datetime(2008, 5, 1),
743                datetime(2008, 3, 15): datetime(2008, 5, 1),
744                datetime(2008, 3, 31): datetime(2008, 5, 1),
745                datetime(2008, 4, 15): datetime(2008, 5, 1),
746                datetime(2008, 8, 15): datetime(2008, 11, 3),
747                datetime(2008, 9, 15): datetime(2008, 11, 3),
748                datetime(2008, 11, 1): datetime(2008, 11, 3),
749                datetime(2008, 4, 30): datetime(2008, 5, 1),
750            },
751        )
752    )
753
754    offset_cases.append(
755        (
756            BQuarterBegin(startingMonth=1, n=0),
757            {
758                datetime(2008, 1, 1): datetime(2008, 1, 1),
759                datetime(2007, 12, 31): datetime(2008, 1, 1),
760                datetime(2008, 2, 15): datetime(2008, 4, 1),
761                datetime(2008, 2, 29): datetime(2008, 4, 1),
762                datetime(2008, 1, 15): datetime(2008, 4, 1),
763                datetime(2008, 2, 27): datetime(2008, 4, 1),
764                datetime(2008, 3, 15): datetime(2008, 4, 1),
765                datetime(2007, 4, 1): datetime(2007, 4, 2),
766                datetime(2007, 4, 2): datetime(2007, 4, 2),
767                datetime(2007, 7, 1): datetime(2007, 7, 2),
768                datetime(2007, 4, 15): datetime(2007, 7, 2),
769                datetime(2007, 7, 2): datetime(2007, 7, 2),
770            },
771        )
772    )
773
774    offset_cases.append(
775        (
776            BQuarterBegin(startingMonth=1, n=-1),
777            {
778                datetime(2008, 1, 1): datetime(2007, 10, 1),
779                datetime(2008, 1, 31): datetime(2008, 1, 1),
780                datetime(2008, 2, 15): datetime(2008, 1, 1),
781                datetime(2008, 2, 29): datetime(2008, 1, 1),
782                datetime(2008, 3, 15): datetime(2008, 1, 1),
783                datetime(2008, 3, 31): datetime(2008, 1, 1),
784                datetime(2008, 4, 15): datetime(2008, 4, 1),
785                datetime(2007, 7, 3): datetime(2007, 7, 2),
786                datetime(2007, 4, 3): datetime(2007, 4, 2),
787                datetime(2007, 7, 2): datetime(2007, 4, 2),
788                datetime(2008, 4, 1): datetime(2008, 1, 1),
789            },
790        )
791    )
792
793    offset_cases.append(
794        (
795            BQuarterBegin(startingMonth=1, n=2),
796            {
797                datetime(2008, 1, 1): datetime(2008, 7, 1),
798                datetime(2008, 1, 15): datetime(2008, 7, 1),
799                datetime(2008, 2, 29): datetime(2008, 7, 1),
800                datetime(2008, 3, 15): datetime(2008, 7, 1),
801                datetime(2007, 3, 31): datetime(2007, 7, 2),
802                datetime(2007, 4, 15): datetime(2007, 10, 1),
803                datetime(2008, 4, 30): datetime(2008, 10, 1),
804            },
805        )
806    )
807
808    @pytest.mark.parametrize("case", offset_cases)
809    def test_offset(self, case):
810        offset, cases = case
811        for base, expected in cases.items():
812            assert_offset_equal(offset, base, expected)
813
814
815class TestBQuarterEnd(Base):
816    _offset = BQuarterEnd
817
818    def test_repr(self):
819        expected = "<BusinessQuarterEnd: startingMonth=3>"
820        assert repr(BQuarterEnd()) == expected
821        expected = "<BusinessQuarterEnd: startingMonth=3>"
822        assert repr(BQuarterEnd(startingMonth=3)) == expected
823        expected = "<BusinessQuarterEnd: startingMonth=1>"
824        assert repr(BQuarterEnd(startingMonth=1)) == expected
825
826    def test_is_anchored(self):
827        assert BQuarterEnd(startingMonth=1).is_anchored()
828        assert BQuarterEnd().is_anchored()
829        assert not BQuarterEnd(2, startingMonth=1).is_anchored()
830
831    def test_offset_corner_case(self):
832        # corner
833        offset = BQuarterEnd(n=-1, startingMonth=1)
834        assert datetime(2010, 1, 31) + offset == datetime(2010, 1, 29)
835
836    offset_cases = []
837    offset_cases.append(
838        (
839            BQuarterEnd(startingMonth=1),
840            {
841                datetime(2008, 1, 1): datetime(2008, 1, 31),
842                datetime(2008, 1, 31): datetime(2008, 4, 30),
843                datetime(2008, 2, 15): datetime(2008, 4, 30),
844                datetime(2008, 2, 29): datetime(2008, 4, 30),
845                datetime(2008, 3, 15): datetime(2008, 4, 30),
846                datetime(2008, 3, 31): datetime(2008, 4, 30),
847                datetime(2008, 4, 15): datetime(2008, 4, 30),
848                datetime(2008, 4, 30): datetime(2008, 7, 31),
849            },
850        )
851    )
852
853    offset_cases.append(
854        (
855            BQuarterEnd(startingMonth=2),
856            {
857                datetime(2008, 1, 1): datetime(2008, 2, 29),
858                datetime(2008, 1, 31): datetime(2008, 2, 29),
859                datetime(2008, 2, 15): datetime(2008, 2, 29),
860                datetime(2008, 2, 29): datetime(2008, 5, 30),
861                datetime(2008, 3, 15): datetime(2008, 5, 30),
862                datetime(2008, 3, 31): datetime(2008, 5, 30),
863                datetime(2008, 4, 15): datetime(2008, 5, 30),
864                datetime(2008, 4, 30): datetime(2008, 5, 30),
865            },
866        )
867    )
868
869    offset_cases.append(
870        (
871            BQuarterEnd(startingMonth=1, n=0),
872            {
873                datetime(2008, 1, 1): datetime(2008, 1, 31),
874                datetime(2008, 1, 31): datetime(2008, 1, 31),
875                datetime(2008, 2, 15): datetime(2008, 4, 30),
876                datetime(2008, 2, 29): datetime(2008, 4, 30),
877                datetime(2008, 3, 15): datetime(2008, 4, 30),
878                datetime(2008, 3, 31): datetime(2008, 4, 30),
879                datetime(2008, 4, 15): datetime(2008, 4, 30),
880                datetime(2008, 4, 30): datetime(2008, 4, 30),
881            },
882        )
883    )
884
885    offset_cases.append(
886        (
887            BQuarterEnd(startingMonth=1, n=-1),
888            {
889                datetime(2008, 1, 1): datetime(2007, 10, 31),
890                datetime(2008, 1, 31): datetime(2007, 10, 31),
891                datetime(2008, 2, 15): datetime(2008, 1, 31),
892                datetime(2008, 2, 29): datetime(2008, 1, 31),
893                datetime(2008, 3, 15): datetime(2008, 1, 31),
894                datetime(2008, 3, 31): datetime(2008, 1, 31),
895                datetime(2008, 4, 15): datetime(2008, 1, 31),
896                datetime(2008, 4, 30): datetime(2008, 1, 31),
897            },
898        )
899    )
900
901    offset_cases.append(
902        (
903            BQuarterEnd(startingMonth=1, n=2),
904            {
905                datetime(2008, 1, 31): datetime(2008, 7, 31),
906                datetime(2008, 2, 15): datetime(2008, 7, 31),
907                datetime(2008, 2, 29): datetime(2008, 7, 31),
908                datetime(2008, 3, 15): datetime(2008, 7, 31),
909                datetime(2008, 3, 31): datetime(2008, 7, 31),
910                datetime(2008, 4, 15): datetime(2008, 7, 31),
911                datetime(2008, 4, 30): datetime(2008, 10, 31),
912            },
913        )
914    )
915
916    @pytest.mark.parametrize("case", offset_cases)
917    def test_offset(self, case):
918        offset, cases = case
919        for base, expected in cases.items():
920            assert_offset_equal(offset, base, expected)
921
922    on_offset_cases = [
923        (BQuarterEnd(1, startingMonth=1), datetime(2008, 1, 31), True),
924        (BQuarterEnd(1, startingMonth=1), datetime(2007, 12, 31), False),
925        (BQuarterEnd(1, startingMonth=1), datetime(2008, 2, 29), False),
926        (BQuarterEnd(1, startingMonth=1), datetime(2007, 3, 30), False),
927        (BQuarterEnd(1, startingMonth=1), datetime(2007, 3, 31), False),
928        (BQuarterEnd(1, startingMonth=1), datetime(2008, 4, 30), True),
929        (BQuarterEnd(1, startingMonth=1), datetime(2008, 5, 30), False),
930        (BQuarterEnd(1, startingMonth=1), datetime(2007, 6, 29), False),
931        (BQuarterEnd(1, startingMonth=1), datetime(2007, 6, 30), False),
932        (BQuarterEnd(1, startingMonth=2), datetime(2008, 1, 31), False),
933        (BQuarterEnd(1, startingMonth=2), datetime(2007, 12, 31), False),
934        (BQuarterEnd(1, startingMonth=2), datetime(2008, 2, 29), True),
935        (BQuarterEnd(1, startingMonth=2), datetime(2007, 3, 30), False),
936        (BQuarterEnd(1, startingMonth=2), datetime(2007, 3, 31), False),
937        (BQuarterEnd(1, startingMonth=2), datetime(2008, 4, 30), False),
938        (BQuarterEnd(1, startingMonth=2), datetime(2008, 5, 30), True),
939        (BQuarterEnd(1, startingMonth=2), datetime(2007, 6, 29), False),
940        (BQuarterEnd(1, startingMonth=2), datetime(2007, 6, 30), False),
941        (BQuarterEnd(1, startingMonth=3), datetime(2008, 1, 31), False),
942        (BQuarterEnd(1, startingMonth=3), datetime(2007, 12, 31), True),
943        (BQuarterEnd(1, startingMonth=3), datetime(2008, 2, 29), False),
944        (BQuarterEnd(1, startingMonth=3), datetime(2007, 3, 30), True),
945        (BQuarterEnd(1, startingMonth=3), datetime(2007, 3, 31), False),
946        (BQuarterEnd(1, startingMonth=3), datetime(2008, 4, 30), False),
947        (BQuarterEnd(1, startingMonth=3), datetime(2008, 5, 30), False),
948        (BQuarterEnd(1, startingMonth=3), datetime(2007, 6, 29), True),
949        (BQuarterEnd(1, startingMonth=3), datetime(2007, 6, 30), False),
950    ]
951
952    @pytest.mark.parametrize("case", on_offset_cases)
953    def test_is_on_offset(self, case):
954        offset, dt, expected = case
955        assert_is_on_offset(offset, dt, expected)
956
957
958# --------------------------------------------------------------------
959# Years
960
961
962class TestYearBegin(Base):
963    _offset = YearBegin
964
965    def test_misspecified(self):
966        with pytest.raises(ValueError, match="Month must go from 1 to 12"):
967            YearBegin(month=13)
968
969    offset_cases = []
970    offset_cases.append(
971        (
972            YearBegin(),
973            {
974                datetime(2008, 1, 1): datetime(2009, 1, 1),
975                datetime(2008, 6, 30): datetime(2009, 1, 1),
976                datetime(2008, 12, 31): datetime(2009, 1, 1),
977                datetime(2005, 12, 30): datetime(2006, 1, 1),
978                datetime(2005, 12, 31): datetime(2006, 1, 1),
979            },
980        )
981    )
982
983    offset_cases.append(
984        (
985            YearBegin(0),
986            {
987                datetime(2008, 1, 1): datetime(2008, 1, 1),
988                datetime(2008, 6, 30): datetime(2009, 1, 1),
989                datetime(2008, 12, 31): datetime(2009, 1, 1),
990                datetime(2005, 12, 30): datetime(2006, 1, 1),
991                datetime(2005, 12, 31): datetime(2006, 1, 1),
992            },
993        )
994    )
995
996    offset_cases.append(
997        (
998            YearBegin(3),
999            {
1000                datetime(2008, 1, 1): datetime(2011, 1, 1),
1001                datetime(2008, 6, 30): datetime(2011, 1, 1),
1002                datetime(2008, 12, 31): datetime(2011, 1, 1),
1003                datetime(2005, 12, 30): datetime(2008, 1, 1),
1004                datetime(2005, 12, 31): datetime(2008, 1, 1),
1005            },
1006        )
1007    )
1008
1009    offset_cases.append(
1010        (
1011            YearBegin(-1),
1012            {
1013                datetime(2007, 1, 1): datetime(2006, 1, 1),
1014                datetime(2007, 1, 15): datetime(2007, 1, 1),
1015                datetime(2008, 6, 30): datetime(2008, 1, 1),
1016                datetime(2008, 12, 31): datetime(2008, 1, 1),
1017                datetime(2006, 12, 29): datetime(2006, 1, 1),
1018                datetime(2006, 12, 30): datetime(2006, 1, 1),
1019                datetime(2007, 1, 1): datetime(2006, 1, 1),
1020            },
1021        )
1022    )
1023
1024    offset_cases.append(
1025        (
1026            YearBegin(-2),
1027            {
1028                datetime(2007, 1, 1): datetime(2005, 1, 1),
1029                datetime(2008, 6, 30): datetime(2007, 1, 1),
1030                datetime(2008, 12, 31): datetime(2007, 1, 1),
1031            },
1032        )
1033    )
1034
1035    offset_cases.append(
1036        (
1037            YearBegin(month=4),
1038            {
1039                datetime(2007, 4, 1): datetime(2008, 4, 1),
1040                datetime(2007, 4, 15): datetime(2008, 4, 1),
1041                datetime(2007, 3, 1): datetime(2007, 4, 1),
1042                datetime(2007, 12, 15): datetime(2008, 4, 1),
1043                datetime(2012, 1, 31): datetime(2012, 4, 1),
1044            },
1045        )
1046    )
1047
1048    offset_cases.append(
1049        (
1050            YearBegin(0, month=4),
1051            {
1052                datetime(2007, 4, 1): datetime(2007, 4, 1),
1053                datetime(2007, 3, 1): datetime(2007, 4, 1),
1054                datetime(2007, 12, 15): datetime(2008, 4, 1),
1055                datetime(2012, 1, 31): datetime(2012, 4, 1),
1056            },
1057        )
1058    )
1059
1060    offset_cases.append(
1061        (
1062            YearBegin(4, month=4),
1063            {
1064                datetime(2007, 4, 1): datetime(2011, 4, 1),
1065                datetime(2007, 4, 15): datetime(2011, 4, 1),
1066                datetime(2007, 3, 1): datetime(2010, 4, 1),
1067                datetime(2007, 12, 15): datetime(2011, 4, 1),
1068                datetime(2012, 1, 31): datetime(2015, 4, 1),
1069            },
1070        )
1071    )
1072
1073    offset_cases.append(
1074        (
1075            YearBegin(-1, month=4),
1076            {
1077                datetime(2007, 4, 1): datetime(2006, 4, 1),
1078                datetime(2007, 3, 1): datetime(2006, 4, 1),
1079                datetime(2007, 12, 15): datetime(2007, 4, 1),
1080                datetime(2012, 1, 31): datetime(2011, 4, 1),
1081            },
1082        )
1083    )
1084
1085    offset_cases.append(
1086        (
1087            YearBegin(-3, month=4),
1088            {
1089                datetime(2007, 4, 1): datetime(2004, 4, 1),
1090                datetime(2007, 3, 1): datetime(2004, 4, 1),
1091                datetime(2007, 12, 15): datetime(2005, 4, 1),
1092                datetime(2012, 1, 31): datetime(2009, 4, 1),
1093            },
1094        )
1095    )
1096
1097    @pytest.mark.parametrize("case", offset_cases)
1098    def test_offset(self, case):
1099        offset, cases = case
1100        for base, expected in cases.items():
1101            assert_offset_equal(offset, base, expected)
1102
1103    on_offset_cases = [
1104        (YearBegin(), datetime(2007, 1, 3), False),
1105        (YearBegin(), datetime(2008, 1, 1), True),
1106        (YearBegin(), datetime(2006, 12, 31), False),
1107        (YearBegin(), datetime(2006, 1, 2), False),
1108    ]
1109
1110    @pytest.mark.parametrize("case", on_offset_cases)
1111    def test_is_on_offset(self, case):
1112        offset, dt, expected = case
1113        assert_is_on_offset(offset, dt, expected)
1114
1115
1116class TestYearEnd(Base):
1117    _offset = YearEnd
1118
1119    def test_misspecified(self):
1120        with pytest.raises(ValueError, match="Month must go from 1 to 12"):
1121            YearEnd(month=13)
1122
1123    offset_cases = []
1124    offset_cases.append(
1125        (
1126            YearEnd(),
1127            {
1128                datetime(2008, 1, 1): datetime(2008, 12, 31),
1129                datetime(2008, 6, 30): datetime(2008, 12, 31),
1130                datetime(2008, 12, 31): datetime(2009, 12, 31),
1131                datetime(2005, 12, 30): datetime(2005, 12, 31),
1132                datetime(2005, 12, 31): datetime(2006, 12, 31),
1133            },
1134        )
1135    )
1136
1137    offset_cases.append(
1138        (
1139            YearEnd(0),
1140            {
1141                datetime(2008, 1, 1): datetime(2008, 12, 31),
1142                datetime(2008, 6, 30): datetime(2008, 12, 31),
1143                datetime(2008, 12, 31): datetime(2008, 12, 31),
1144                datetime(2005, 12, 30): datetime(2005, 12, 31),
1145            },
1146        )
1147    )
1148
1149    offset_cases.append(
1150        (
1151            YearEnd(-1),
1152            {
1153                datetime(2007, 1, 1): datetime(2006, 12, 31),
1154                datetime(2008, 6, 30): datetime(2007, 12, 31),
1155                datetime(2008, 12, 31): datetime(2007, 12, 31),
1156                datetime(2006, 12, 29): datetime(2005, 12, 31),
1157                datetime(2006, 12, 30): datetime(2005, 12, 31),
1158                datetime(2007, 1, 1): datetime(2006, 12, 31),
1159            },
1160        )
1161    )
1162
1163    offset_cases.append(
1164        (
1165            YearEnd(-2),
1166            {
1167                datetime(2007, 1, 1): datetime(2005, 12, 31),
1168                datetime(2008, 6, 30): datetime(2006, 12, 31),
1169                datetime(2008, 12, 31): datetime(2006, 12, 31),
1170            },
1171        )
1172    )
1173
1174    @pytest.mark.parametrize("case", offset_cases)
1175    def test_offset(self, case):
1176        offset, cases = case
1177        for base, expected in cases.items():
1178            assert_offset_equal(offset, base, expected)
1179
1180    on_offset_cases = [
1181        (YearEnd(), datetime(2007, 12, 31), True),
1182        (YearEnd(), datetime(2008, 1, 1), False),
1183        (YearEnd(), datetime(2006, 12, 31), True),
1184        (YearEnd(), datetime(2006, 12, 29), False),
1185    ]
1186
1187    @pytest.mark.parametrize("case", on_offset_cases)
1188    def test_is_on_offset(self, case):
1189        offset, dt, expected = case
1190        assert_is_on_offset(offset, dt, expected)
1191
1192
1193class TestYearEndDiffMonth(Base):
1194    offset_cases = []
1195    offset_cases.append(
1196        (
1197            YearEnd(month=3),
1198            {
1199                datetime(2008, 1, 1): datetime(2008, 3, 31),
1200                datetime(2008, 2, 15): datetime(2008, 3, 31),
1201                datetime(2008, 3, 31): datetime(2009, 3, 31),
1202                datetime(2008, 3, 30): datetime(2008, 3, 31),
1203                datetime(2005, 3, 31): datetime(2006, 3, 31),
1204                datetime(2006, 7, 30): datetime(2007, 3, 31),
1205            },
1206        )
1207    )
1208
1209    offset_cases.append(
1210        (
1211            YearEnd(0, month=3),
1212            {
1213                datetime(2008, 1, 1): datetime(2008, 3, 31),
1214                datetime(2008, 2, 28): datetime(2008, 3, 31),
1215                datetime(2008, 3, 31): datetime(2008, 3, 31),
1216                datetime(2005, 3, 30): datetime(2005, 3, 31),
1217            },
1218        )
1219    )
1220
1221    offset_cases.append(
1222        (
1223            YearEnd(-1, month=3),
1224            {
1225                datetime(2007, 1, 1): datetime(2006, 3, 31),
1226                datetime(2008, 2, 28): datetime(2007, 3, 31),
1227                datetime(2008, 3, 31): datetime(2007, 3, 31),
1228                datetime(2006, 3, 29): datetime(2005, 3, 31),
1229                datetime(2006, 3, 30): datetime(2005, 3, 31),
1230                datetime(2007, 3, 1): datetime(2006, 3, 31),
1231            },
1232        )
1233    )
1234
1235    offset_cases.append(
1236        (
1237            YearEnd(-2, month=3),
1238            {
1239                datetime(2007, 1, 1): datetime(2005, 3, 31),
1240                datetime(2008, 6, 30): datetime(2007, 3, 31),
1241                datetime(2008, 3, 31): datetime(2006, 3, 31),
1242            },
1243        )
1244    )
1245
1246    @pytest.mark.parametrize("case", offset_cases)
1247    def test_offset(self, case):
1248        offset, cases = case
1249        for base, expected in cases.items():
1250            assert_offset_equal(offset, base, expected)
1251
1252    on_offset_cases = [
1253        (YearEnd(month=3), datetime(2007, 3, 31), True),
1254        (YearEnd(month=3), datetime(2008, 1, 1), False),
1255        (YearEnd(month=3), datetime(2006, 3, 31), True),
1256        (YearEnd(month=3), datetime(2006, 3, 29), False),
1257    ]
1258
1259    @pytest.mark.parametrize("case", on_offset_cases)
1260    def test_is_on_offset(self, case):
1261        offset, dt, expected = case
1262        assert_is_on_offset(offset, dt, expected)
1263
1264
1265class TestBYearBegin(Base):
1266    _offset = BYearBegin
1267
1268    def test_misspecified(self):
1269        msg = "Month must go from 1 to 12"
1270        with pytest.raises(ValueError, match=msg):
1271            BYearBegin(month=13)
1272        with pytest.raises(ValueError, match=msg):
1273            BYearEnd(month=13)
1274
1275    offset_cases = []
1276    offset_cases.append(
1277        (
1278            BYearBegin(),
1279            {
1280                datetime(2008, 1, 1): datetime(2009, 1, 1),
1281                datetime(2008, 6, 30): datetime(2009, 1, 1),
1282                datetime(2008, 12, 31): datetime(2009, 1, 1),
1283                datetime(2011, 1, 1): datetime(2011, 1, 3),
1284                datetime(2011, 1, 3): datetime(2012, 1, 2),
1285                datetime(2005, 12, 30): datetime(2006, 1, 2),
1286                datetime(2005, 12, 31): datetime(2006, 1, 2),
1287            },
1288        )
1289    )
1290
1291    offset_cases.append(
1292        (
1293            BYearBegin(0),
1294            {
1295                datetime(2008, 1, 1): datetime(2008, 1, 1),
1296                datetime(2008, 6, 30): datetime(2009, 1, 1),
1297                datetime(2008, 12, 31): datetime(2009, 1, 1),
1298                datetime(2005, 12, 30): datetime(2006, 1, 2),
1299                datetime(2005, 12, 31): datetime(2006, 1, 2),
1300            },
1301        )
1302    )
1303
1304    offset_cases.append(
1305        (
1306            BYearBegin(-1),
1307            {
1308                datetime(2007, 1, 1): datetime(2006, 1, 2),
1309                datetime(2009, 1, 4): datetime(2009, 1, 1),
1310                datetime(2009, 1, 1): datetime(2008, 1, 1),
1311                datetime(2008, 6, 30): datetime(2008, 1, 1),
1312                datetime(2008, 12, 31): datetime(2008, 1, 1),
1313                datetime(2006, 12, 29): datetime(2006, 1, 2),
1314                datetime(2006, 12, 30): datetime(2006, 1, 2),
1315                datetime(2006, 1, 1): datetime(2005, 1, 3),
1316            },
1317        )
1318    )
1319
1320    offset_cases.append(
1321        (
1322            BYearBegin(-2),
1323            {
1324                datetime(2007, 1, 1): datetime(2005, 1, 3),
1325                datetime(2007, 6, 30): datetime(2006, 1, 2),
1326                datetime(2008, 12, 31): datetime(2007, 1, 1),
1327            },
1328        )
1329    )
1330
1331    @pytest.mark.parametrize("case", offset_cases)
1332    def test_offset(self, case):
1333        offset, cases = case
1334        for base, expected in cases.items():
1335            assert_offset_equal(offset, base, expected)
1336
1337
1338class TestBYearEnd(Base):
1339    _offset = BYearEnd
1340
1341    offset_cases = []
1342    offset_cases.append(
1343        (
1344            BYearEnd(),
1345            {
1346                datetime(2008, 1, 1): datetime(2008, 12, 31),
1347                datetime(2008, 6, 30): datetime(2008, 12, 31),
1348                datetime(2008, 12, 31): datetime(2009, 12, 31),
1349                datetime(2005, 12, 30): datetime(2006, 12, 29),
1350                datetime(2005, 12, 31): datetime(2006, 12, 29),
1351            },
1352        )
1353    )
1354
1355    offset_cases.append(
1356        (
1357            BYearEnd(0),
1358            {
1359                datetime(2008, 1, 1): datetime(2008, 12, 31),
1360                datetime(2008, 6, 30): datetime(2008, 12, 31),
1361                datetime(2008, 12, 31): datetime(2008, 12, 31),
1362                datetime(2005, 12, 31): datetime(2006, 12, 29),
1363            },
1364        )
1365    )
1366
1367    offset_cases.append(
1368        (
1369            BYearEnd(-1),
1370            {
1371                datetime(2007, 1, 1): datetime(2006, 12, 29),
1372                datetime(2008, 6, 30): datetime(2007, 12, 31),
1373                datetime(2008, 12, 31): datetime(2007, 12, 31),
1374                datetime(2006, 12, 29): datetime(2005, 12, 30),
1375                datetime(2006, 12, 30): datetime(2006, 12, 29),
1376                datetime(2007, 1, 1): datetime(2006, 12, 29),
1377            },
1378        )
1379    )
1380
1381    offset_cases.append(
1382        (
1383            BYearEnd(-2),
1384            {
1385                datetime(2007, 1, 1): datetime(2005, 12, 30),
1386                datetime(2008, 6, 30): datetime(2006, 12, 29),
1387                datetime(2008, 12, 31): datetime(2006, 12, 29),
1388            },
1389        )
1390    )
1391
1392    @pytest.mark.parametrize("case", offset_cases)
1393    def test_offset(self, case):
1394        offset, cases = case
1395        for base, expected in cases.items():
1396            assert_offset_equal(offset, base, expected)
1397
1398    on_offset_cases = [
1399        (BYearEnd(), datetime(2007, 12, 31), True),
1400        (BYearEnd(), datetime(2008, 1, 1), False),
1401        (BYearEnd(), datetime(2006, 12, 31), False),
1402        (BYearEnd(), datetime(2006, 12, 29), True),
1403    ]
1404
1405    @pytest.mark.parametrize("case", on_offset_cases)
1406    def test_is_on_offset(self, case):
1407        offset, dt, expected = case
1408        assert_is_on_offset(offset, dt, expected)
1409
1410
1411class TestBYearEndLagged(Base):
1412    _offset = BYearEnd
1413
1414    def test_bad_month_fail(self):
1415        msg = "Month must go from 1 to 12"
1416        with pytest.raises(ValueError, match=msg):
1417            BYearEnd(month=13)
1418        with pytest.raises(ValueError, match=msg):
1419            BYearEnd(month=0)
1420
1421    offset_cases = []
1422    offset_cases.append(
1423        (
1424            BYearEnd(month=6),
1425            {
1426                datetime(2008, 1, 1): datetime(2008, 6, 30),
1427                datetime(2007, 6, 30): datetime(2008, 6, 30),
1428            },
1429        )
1430    )
1431
1432    offset_cases.append(
1433        (
1434            BYearEnd(n=-1, month=6),
1435            {
1436                datetime(2008, 1, 1): datetime(2007, 6, 29),
1437                datetime(2007, 6, 30): datetime(2007, 6, 29),
1438            },
1439        )
1440    )
1441
1442    @pytest.mark.parametrize("case", offset_cases)
1443    def test_offset(self, case):
1444        offset, cases = case
1445        for base, expected in cases.items():
1446            assert_offset_equal(offset, base, expected)
1447
1448    def test_roll(self):
1449        offset = BYearEnd(month=6)
1450        date = datetime(2009, 11, 30)
1451
1452        assert offset.rollforward(date) == datetime(2010, 6, 30)
1453        assert offset.rollback(date) == datetime(2009, 6, 30)
1454
1455    on_offset_cases = [
1456        (BYearEnd(month=2), datetime(2007, 2, 28), True),
1457        (BYearEnd(month=6), datetime(2007, 6, 30), False),
1458    ]
1459
1460    @pytest.mark.parametrize("case", on_offset_cases)
1461    def test_is_on_offset(self, case):
1462        offset, dt, expected = case
1463        assert_is_on_offset(offset, dt, expected)
1464