Skip to content

bug fix for 7987 and add day of week functionality to Holiday #7988

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2014
Merged
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
3 changes: 2 additions & 1 deletion doc/source/v0.15.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ Enhancements
- ``PeriodIndex`` supports ``resolution`` as the same as ``DatetimeIndex`` (:issue:`7708`)
- ``pandas.tseries.holiday`` has added support for additional holidays and ways to observe holidays (:issue:`7070`)
- ``pandas.tseries.holiday.Holiday`` now supports a list of offsets in Python3 (:issue:`7070`)

- ``pandas.tseries.holiday.Holiday`` now supports a days_of_week parameter (:issue:`7070`)



Expand Down Expand Up @@ -529,6 +529,7 @@ Bug Fixes

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

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



Expand Down
49 changes: 37 additions & 12 deletions pandas/tseries/holiday.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
from pandas.tseries.offsets import Easter, Day


def next_monday(dt):
"""
If holiday falls on Saturday, use following Monday instead;
Expand Down Expand Up @@ -116,7 +117,8 @@ class Holiday(object):
for observance.
"""
def __init__(self, name, year=None, month=None, day=None, offset=None,
observance=None, start_date=None, end_date=None):
observance=None, start_date=None, end_date=None,
days_of_week=None):
"""
Parameters
----------
Expand All @@ -127,6 +129,24 @@ class from pandas.tseries.offsets
computes offset from date
observance: function
computes when holiday is given a pandas Timestamp
days_of_week:
provide a tuple of days e.g (0,1,2,3,) for Monday Through Thursday
Monday=0,..,Sunday=6

Examples
--------
>>> from pandas.tseries.holiday import Holiday, nearest_workday
>>> from pandas import DateOffset
>>> from dateutil.relativedelta import MO
>>> USMemorialDay = Holiday('MemorialDay', month=5, day=24,
offset=DateOffset(weekday=MO(1)))
>>> USLaborDay = Holiday('Labor Day', month=9, day=1,
offset=DateOffset(weekday=MO(1)))
>>> July3rd = Holiday('July 3rd', month=7, day=3,)
>>> NewYears = Holiday('New Years Day', month=1, day=1,
observance=nearest_workday),
>>> July3rd = Holiday('July 3rd', month=7, day=3,
days_of_week=(0, 1, 2, 3))
"""
self.name = name
self.year = year
Expand All @@ -136,6 +156,8 @@ class from pandas.tseries.offsets
self.start_date = start_date
self.end_date = end_date
self.observance = observance
assert (days_of_week is None or type(days_of_week) == tuple)
self.days_of_week = days_of_week

def __repr__(self):
info = ''
Expand Down Expand Up @@ -183,11 +205,15 @@ def dates(self, start_date, end_date, return_name=False):
year_offset = DateOffset(years=1)
base_date = Timestamp(datetime(start_date.year, self.month, self.day))
dates = DatetimeIndex(start=base_date, end=end_date, freq=year_offset)
holiday_dates = list(self._apply_rule(dates))

holiday_dates = self._apply_rule(dates)
if self.days_of_week is not None:
holiday_dates = list(filter(lambda x: x is not None and
x.dayofweek in self.days_of_week,
holiday_dates))
else:
holiday_dates = list(filter(lambda x: x is not None, holiday_dates))
if return_name:
return Series(self.name, index=holiday_dates)

return holiday_dates

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

if not isinstance(self.offset, list):
offsets = [self.offset]
else:
offsets = self.offset

for offset in offsets:
dates = list(map(lambda d: d + offset, dates))

if self.offset is not None:
if not isinstance(self.offset, list):
offsets = [self.offset]
else:
offsets = self.offset
for offset in offsets:
dates = list(map(lambda d: d + offset, dates))
return dates

holiday_calendars = {}
Expand Down
16 changes: 16 additions & 0 deletions pandas/tseries/tests/test_holiday.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ def test_usmemorialday(self):
]
self.assertEqual(list(holidays), holidayList)

def test_non_observed_holiday(self):
july_3rd = Holiday('July 4th Eve', month=7, day=3)
result = july_3rd.dates("2001-01-01", "2003-03-03")
expected = [Timestamp('2001-07-03 00:00:00'),
Timestamp('2002-07-03 00:00:00')]
self.assertEqual(list(result), expected)
july_3rd = Holiday('July 4th Eve', month=7, day=3,
days_of_week=(0, 1, 2, 3))
result = july_3rd.dates("2001-01-01", "2008-03-03")
expected = [Timestamp('2001-07-03 00:00:00'),
Timestamp('2002-07-03 00:00:00'),
Timestamp('2003-07-03 00:00:00'),
Timestamp('2006-07-03 00:00:00'),
Timestamp('2007-07-03 00:00:00')]
self.assertEqual(list(result), expected)

def test_easter(self):
holidays = EasterMonday.dates(self.start_date,
self.end_date)
Expand Down