From 605c8f5f0731f3135f9c71fa628695a75cd33169 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 28 Nov 2017 09:10:41 -0800 Subject: [PATCH 1/4] bugfix case with bunched yearends closed #14774 --- pandas/tests/tseries/offsets/test_fiscal.py | 15 +++++++++++++++ pandas/tseries/offsets.py | 13 +++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_fiscal.py b/pandas/tests/tseries/offsets/test_fiscal.py index 45f12c6931fd9..3eeea6b4c7a2a 100644 --- a/pandas/tests/tseries/offsets/test_fiscal.py +++ b/pandas/tests/tseries/offsets/test_fiscal.py @@ -9,6 +9,7 @@ import pandas.util.testing as tm +from pandas import Timestamp from pandas.tseries.frequencies import get_offset, _INVALID_FREQ_ERROR from pandas.tseries.offsets import FY5253Quarter, FY5253 from pandas._libs.tslibs.offsets import WeekDay @@ -604,3 +605,17 @@ def test_offset(self): assert_offset_equal(offset2, datetime(2013, 1, 15), datetime(2013, 3, 30)) + + +def test_bunched_yearends(): + # GH#14774 cases with two fiscal year-ends in the same calendar-year + fy = FY5253(n=1, weekday=5, startingMonth=12, variation='nearest') + dt = Timestamp('2004-01-01') + assert fy.rollback(dt) == Timestamp('2002-12-28') + assert (-fy).apply(dt) == Timestamp('2002-12-28') + assert dt - fy == Timestamp('2002-12-28') + + assert fy.rollforward(dt) == Timestamp('2004-01-03') + assert fy.apply(dt) == Timestamp('2004-01-03') + assert fy + dt == Timestamp('2004-01-03') + assert dt + fy == Timestamp('2004-01-03') diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index a3cddaa19dc17..6a0c20023b793 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1869,21 +1869,26 @@ def apply(self, other): elif n > 0: if other < prev_year: n -= 2 - # TODO: Not hit in tests - elif other < cur_year: + elif prev_year < other < cur_year: n -= 1 - elif other < next_year: + elif cur_year < other < next_year: pass else: assert False else: if other > next_year: n += 2 - # TODO: Not hit in tests + # TODO: Not hit in tests; UPDATE: looks impossible elif other > cur_year: n += 1 elif other > prev_year: pass + elif (other.year == prev_year.year and other < prev_year and + prev_year - other <= timedelta(6)): + # GH#14774, error when next_year.year == cur_year.year + # e.g. prev_year == datetime(2004, 1, 3), + # other == datetime(2004, 1, 1) + n -= 1 else: assert False From edb8b8596b73323dd49e27c310a55fbbbc77ea81 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 28 Nov 2017 09:14:31 -0800 Subject: [PATCH 2/4] use < uniformly --- pandas/tseries/offsets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 6a0c20023b793..25f085ce98577 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1876,12 +1876,12 @@ def apply(self, other): else: assert False else: - if other > next_year: + if next_year < other: n += 2 # TODO: Not hit in tests; UPDATE: looks impossible - elif other > cur_year: + elif cur_year < other < next_year: n += 1 - elif other > prev_year: + elif prev_year < other < cur_year: pass elif (other.year == prev_year.year and other < prev_year and prev_year - other <= timedelta(6)): From 6ef93682adb80ec87c45fc38edf406c4c0e65db1 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 28 Nov 2017 17:06:54 -0800 Subject: [PATCH 3/4] add whatsnew note --- doc/source/whatsnew/v0.22.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index 1eb1b548788b9..13077eed0fe07 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -208,4 +208,4 @@ Other - Improved error message when attempting to use a Python keyword as an identifier in a numexpr query (:issue:`18221`) - Fixed a bug where creating a Series from an array that contains both tz-naive and tz-aware values will result in a Series whose dtype is tz-aware instead of object (:issue:`16406`) -- +- Fixed a bug where ``FY5253`` date offsets could incorrectly raise an ``AssertionError`` in arithmetic operatons (:issue:`14774`) From 0596c21672bc2e8579c5a7646860f86130b58ce7 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Sun, 3 Dec 2017 10:12:03 -0800 Subject: [PATCH 4/4] add issue-specific test case --- pandas/tests/tseries/offsets/test_fiscal.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pandas/tests/tseries/offsets/test_fiscal.py b/pandas/tests/tseries/offsets/test_fiscal.py index 3eeea6b4c7a2a..2dd061dcc6f9e 100644 --- a/pandas/tests/tseries/offsets/test_fiscal.py +++ b/pandas/tests/tseries/offsets/test_fiscal.py @@ -619,3 +619,9 @@ def test_bunched_yearends(): assert fy.apply(dt) == Timestamp('2004-01-03') assert fy + dt == Timestamp('2004-01-03') assert dt + fy == Timestamp('2004-01-03') + + # Same thing, but starting from a Timestamp in the previous year. + dt = Timestamp('2003-12-31') + assert fy.rollback(dt) == Timestamp('2002-12-28') + assert (-fy).apply(dt) == Timestamp('2002-12-28') + assert dt - fy == Timestamp('2002-12-28')