summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Eendebak <pieter.eendebak@gmail.com>2023-03-20 08:59:59 +0100
committerGitHub <noreply@github.com>2023-03-20 08:59:59 +0100
commit1cf882248961a5d411c55d75bff190d7f7eb30e2 (patch)
treee38f6322e7ab3d5c92c4334d8c62a0e2e96165f5
parentee12ff3228d0d800dc25004bc57c78814a48df47 (diff)
downloadnumpy-1cf882248961a5d411c55d75bff190d7f7eb30e2.tar.gz
BUG: Fix busday_count for reversed dates (#23229)
Fixes #23197
-rw-r--r--doc/release/upcoming_changes/23229.compatibility.rst3
-rw-r--r--numpy/core/src/multiarray/datetime_busday.c5
-rw-r--r--numpy/core/tests/test_datetime.py24
3 files changed, 29 insertions, 3 deletions
diff --git a/doc/release/upcoming_changes/23229.compatibility.rst b/doc/release/upcoming_changes/23229.compatibility.rst
new file mode 100644
index 000000000..284cc06ab
--- /dev/null
+++ b/doc/release/upcoming_changes/23229.compatibility.rst
@@ -0,0 +1,3 @@
+- The ``busday_count`` method now correctly handles cases where the ``begindates`` is later in time
+ than the ``enddates``. Previously, the ``enddates`` was included, even though the documentation states
+ it is always excluded.
diff --git a/numpy/core/src/multiarray/datetime_busday.c b/numpy/core/src/multiarray/datetime_busday.c
index d3e9e1451..93ed0972e 100644
--- a/numpy/core/src/multiarray/datetime_busday.c
+++ b/numpy/core/src/multiarray/datetime_busday.c
@@ -365,6 +365,7 @@ apply_business_day_count(npy_datetime date_begin, npy_datetime date_end,
npy_datetime *holidays_begin, npy_datetime *holidays_end)
{
npy_int64 count, whole_weeks;
+
int day_of_week = 0;
int swapped = 0;
@@ -386,6 +387,10 @@ apply_business_day_count(npy_datetime date_begin, npy_datetime date_end,
date_begin = date_end;
date_end = tmp;
swapped = 1;
+ // we swapped date_begin and date_end, so we need to correct for the
+ // original date_end that should not be included. gh-23197
+ date_begin++;
+ date_end++;
}
/* Remove any earlier holidays */
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 2b56d4824..547ebf9d6 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -2330,16 +2330,23 @@ class TestDateTime:
assert_equal(np.busday_count('2011-01-01', dates, busdaycal=bdd),
np.arange(366))
# Returns negative value when reversed
+ # -1 since the '2011-01-01' is not a busday
assert_equal(np.busday_count(dates, '2011-01-01', busdaycal=bdd),
- -np.arange(366))
+ -np.arange(366) - 1)
+ # 2011-12-31 is a saturday
dates = np.busday_offset('2011-12-31', -np.arange(366),
roll='forward', busdaycal=bdd)
+ # only the first generated date is in the future of 2011-12-31
+ expected = np.arange(366)
+ expected[0] = -1
assert_equal(np.busday_count(dates, '2011-12-31', busdaycal=bdd),
- np.arange(366))
+ expected)
# Returns negative value when reversed
+ expected = -np.arange(366)+1
+ expected[0] = 0
assert_equal(np.busday_count('2011-12-31', dates, busdaycal=bdd),
- -np.arange(366))
+ expected)
# Can't supply both a weekmask/holidays and busdaycal
assert_raises(ValueError, np.busday_offset, '2012-01-03', '2012-02-03',
@@ -2352,6 +2359,17 @@ class TestDateTime:
# Returns negative value when reversed
assert_equal(np.busday_count('2011-04', '2011-03', weekmask='Mon'), -4)
+ sunday = np.datetime64('2023-03-05')
+ monday = sunday + 1
+ friday = sunday + 5
+ saturday = sunday + 6
+ assert_equal(np.busday_count(sunday, monday), 0)
+ assert_equal(np.busday_count(monday, sunday), -1)
+
+ assert_equal(np.busday_count(friday, saturday), 1)
+ assert_equal(np.busday_count(saturday, friday), 0)
+
+
def test_datetime_is_busday(self):
holidays = ['2011-01-01', '2011-10-10', '2011-11-11', '2011-11-24',
'2011-12-25', '2011-05-30', '2011-02-21', '2011-01-17',