Skip to content

Commit 931b466

Browse files
committed
Merge pull request #7988 from MichaelWS/master
bug fix for 7987 and add day of week functionality to Holiday
2 parents 1d5cb4a + b9633f6 commit 931b466

File tree

3 files changed

+55
-13
lines changed

3 files changed

+55
-13
lines changed

doc/source/v0.15.0.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ Enhancements
431431
- ``PeriodIndex`` supports ``resolution`` as the same as ``DatetimeIndex`` (:issue:`7708`)
432432
- ``pandas.tseries.holiday`` has added support for additional holidays and ways to observe holidays (:issue:`7070`)
433433
- ``pandas.tseries.holiday.Holiday`` now supports a list of offsets in Python3 (:issue:`7070`)
434-
434+
- ``pandas.tseries.holiday.Holiday`` now supports a days_of_week parameter (:issue:`7070`)
435435

436436

437437

@@ -595,6 +595,7 @@ Bug Fixes
595595

596596
- ``Period`` and ``PeriodIndex`` addition/subtraction with ``np.timedelta64`` results in incorrect internal representations (:issue:`7740`)
597597

598+
- ``Holiday`` bug in Holiday with no offset or observance (:issue:`7987`)
598599

599600

600601

pandas/tseries/holiday.py

+37-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
55
from pandas.tseries.offsets import Easter, Day
66

7+
78
def next_monday(dt):
89
"""
910
If holiday falls on Saturday, use following Monday instead;
@@ -116,7 +117,8 @@ class Holiday(object):
116117
for observance.
117118
"""
118119
def __init__(self, name, year=None, month=None, day=None, offset=None,
119-
observance=None, start_date=None, end_date=None):
120+
observance=None, start_date=None, end_date=None,
121+
days_of_week=None):
120122
"""
121123
Parameters
122124
----------
@@ -127,6 +129,24 @@ class from pandas.tseries.offsets
127129
computes offset from date
128130
observance: function
129131
computes when holiday is given a pandas Timestamp
132+
days_of_week:
133+
provide a tuple of days e.g (0,1,2,3,) for Monday Through Thursday
134+
Monday=0,..,Sunday=6
135+
136+
Examples
137+
--------
138+
>>> from pandas.tseries.holiday import Holiday, nearest_workday
139+
>>> from pandas import DateOffset
140+
>>> from dateutil.relativedelta import MO
141+
>>> USMemorialDay = Holiday('MemorialDay', month=5, day=24,
142+
offset=DateOffset(weekday=MO(1)))
143+
>>> USLaborDay = Holiday('Labor Day', month=9, day=1,
144+
offset=DateOffset(weekday=MO(1)))
145+
>>> July3rd = Holiday('July 3rd', month=7, day=3,)
146+
>>> NewYears = Holiday('New Years Day', month=1, day=1,
147+
observance=nearest_workday),
148+
>>> July3rd = Holiday('July 3rd', month=7, day=3,
149+
days_of_week=(0, 1, 2, 3))
130150
"""
131151
self.name = name
132152
self.year = year
@@ -136,6 +156,8 @@ class from pandas.tseries.offsets
136156
self.start_date = start_date
137157
self.end_date = end_date
138158
self.observance = observance
159+
assert (days_of_week is None or type(days_of_week) == tuple)
160+
self.days_of_week = days_of_week
139161

140162
def __repr__(self):
141163
info = ''
@@ -183,11 +205,15 @@ def dates(self, start_date, end_date, return_name=False):
183205
year_offset = DateOffset(years=1)
184206
base_date = Timestamp(datetime(start_date.year, self.month, self.day))
185207
dates = DatetimeIndex(start=base_date, end=end_date, freq=year_offset)
186-
holiday_dates = list(self._apply_rule(dates))
187-
208+
holiday_dates = self._apply_rule(dates)
209+
if self.days_of_week is not None:
210+
holiday_dates = list(filter(lambda x: x is not None and
211+
x.dayofweek in self.days_of_week,
212+
holiday_dates))
213+
else:
214+
holiday_dates = list(filter(lambda x: x is not None, holiday_dates))
188215
if return_name:
189216
return Series(self.name, index=holiday_dates)
190-
191217
return holiday_dates
192218

193219
def _apply_rule(self, dates):
@@ -207,14 +233,13 @@ def _apply_rule(self, dates):
207233
if self.observance is not None:
208234
return map(lambda d: self.observance(d), dates)
209235

210-
if not isinstance(self.offset, list):
211-
offsets = [self.offset]
212-
else:
213-
offsets = self.offset
214-
215-
for offset in offsets:
216-
dates = list(map(lambda d: d + offset, dates))
217-
236+
if self.offset is not None:
237+
if not isinstance(self.offset, list):
238+
offsets = [self.offset]
239+
else:
240+
offsets = self.offset
241+
for offset in offsets:
242+
dates = list(map(lambda d: d + offset, dates))
218243
return dates
219244

220245
holiday_calendars = {}

pandas/tseries/tests/test_holiday.py

+16
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ def test_usmemorialday(self):
7272
]
7373
self.assertEqual(list(holidays), holidayList)
7474

75+
def test_non_observed_holiday(self):
76+
july_3rd = Holiday('July 4th Eve', month=7, day=3)
77+
result = july_3rd.dates("2001-01-01", "2003-03-03")
78+
expected = [Timestamp('2001-07-03 00:00:00'),
79+
Timestamp('2002-07-03 00:00:00')]
80+
self.assertEqual(list(result), expected)
81+
july_3rd = Holiday('July 4th Eve', month=7, day=3,
82+
days_of_week=(0, 1, 2, 3))
83+
result = july_3rd.dates("2001-01-01", "2008-03-03")
84+
expected = [Timestamp('2001-07-03 00:00:00'),
85+
Timestamp('2002-07-03 00:00:00'),
86+
Timestamp('2003-07-03 00:00:00'),
87+
Timestamp('2006-07-03 00:00:00'),
88+
Timestamp('2007-07-03 00:00:00')]
89+
self.assertEqual(list(result), expected)
90+
7591
def test_easter(self):
7692
holidays = EasterMonday.dates(self.start_date,
7793
self.end_date)

0 commit comments

Comments
 (0)