Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ Datetimelike
- Bug in constructing arrays with :class:`ArrowDtype` with ``timestamp`` type incorrectly allowing ``Decimal("NaN")`` (:issue:`61773`)
- Bug in constructing arrays with a timezone-aware :class:`ArrowDtype` from timezone-naive datetime objects incorrectly treating those as UTC times instead of wall times like :class:`DatetimeTZDtype` (:issue:`61775`)
- Bug in setting scalar values with mismatched resolution into arrays with non-nanosecond ``datetime64``, ``timedelta64`` or :class:`DatetimeTZDtype` incorrectly truncating those scalars (:issue:`56410`)
- Bug in :class:`CustomBusinessDay` where calendar parameter validation was not enforced, now requires ``numpy.busdaycalendar`` objects (:issue:`60647`)


Timedelta
Expand Down
10 changes: 10 additions & 0 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,16 @@ cdef _get_calendar(weekmask, holidays, calendar):
pass
return calendar, holidays

# GH#60647
# Enforce that when a calendar is provided, it must be a numpy.busdaycalendar
if calendar is not None and 'pandas_market_calendars' in str(type(calendar)):
raise TypeError(
"CustomBusinessDay.calendar must be a numpy.busdaycalendar; "
f"got {type(calendar).__name__}. "
"For pandas_market_calendars please pass the result of "
".holidays() (a DatetimeIndex) instead."
)

if holidays is None:
holidays = []
try:
Expand Down
16 changes: 16 additions & 0 deletions pandas/tests/tseries/offsets/test_custom_business_day.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ def test_calendar(self):
dt = datetime(2014, 1, 17)
assert_offset_equal(CDay(calendar=calendar), dt, datetime(2014, 1, 21))

def test_calendar_validation(self):
"""Test CustomBusinessDay calendar parameter validation (GH#60647)"""
# Valid numpy.busdaycalendar should work
calendar = np.busdaycalendar(weekmask="1111100") # Monday-Friday
cbd = CDay(calendar=calendar)
assert cbd.calendar is calendar

# Test error message for pandas_market_calendars scenario
class pandas_market_calendars:
def __init__(self):
self.name = "pandas_market_calendars"

mock_calendar = pandas_market_calendars()
with pytest.raises(TypeError):
CDay(calendar=mock_calendar)

def test_roundtrip_pickle(self, offset, offset2):
def _check_roundtrip(obj):
unpickled = tm.round_trip_pickle(obj)
Expand Down
Loading