Pandas Holiday Calendars
When working with time series data, accounting for holidays and special days is crucial for accurate analysis, particularly in business and financial applications. Pandas provides powerful tools to handle holidays through its integration with the holidays
package.
Introduction to Holiday Calendars
Holiday calendars in Pandas allow you to:
- Identify business days while excluding holidays
- Create date ranges that skip holidays
- Perform calculations that account for holiday schedules
- Customize calendars for different countries or business rules
This functionality is especially useful for financial analysis, business forecasting, and any application where special days affect your data.
Setting Up Your Environment
Before we start, let's make sure you have the necessary packages installed:
pip install pandas numpy holidays
Now let's import the libraries we'll need:
import pandas as pd
import numpy as np
from pandas.tseries.holiday import USFederalHolidayCalendar, Holiday, nearest_workday
from pandas.tseries.offsets import CustomBusinessDay
import holidays
Using Built-in Holiday Calendars
The USFederalHolidayCalendar
Pandas comes with built-in support for US federal holidays through the USFederalHolidayCalendar
class.
# Create a calendar instance
cal = USFederalHolidayCalendar()
# Get holidays for a specific date range
start_date = '2023-01-01'
end_date = '2023-12-31'
holiday_list = cal.holidays(start=start_date, end=end_date)
print("US Federal Holidays in 2023:")
print(holiday_list)
Output:
US Federal Holidays in 2023:
DatetimeIndex(['2023-01-02', '2023-01-16', '2023-02-20', '2023-05-29',
'2023-06-19', '2023-07-04', '2023-09-04', '2023-10-09',
'2023-11-10', '2023-11-23', '2023-12-25'],
dtype='datetime64[ns]', freq=None)
Creating Business Day Ranges with Holiday Calendars
One of the most common uses for holiday calendars is to create date ranges that only include business days:
# Create a business day calendar that excludes US federal holidays
us_business_day = CustomBusinessDay(calendar=USFederalHolidayCalendar())
# Create a date range of business days
business_days = pd.date_range(start='2023-12-20',
end='2024-01-10',
freq=us_business_day)
print("Business days excluding US federal holidays:")
print(business_days)
Output:
Business days excluding US federal holidays:
DatetimeIndex(['2023-12-20', '2023-12-21', '2023-12-22', '2023-12-26',
'2023-12-27', '2023-12-28', '2023-12-29', '2024-01-02',
'2024-01-03', '2024-01-04', '2024-01-05', '2024-01-08',
'2024-01-09', '2024-01-10'],
dtype='datetime64[ns]', freq='C')
Notice that weekends and Christmas Day (December 25, 2023) and New Year's Day (January 1, 2024) are excluded from the range.
Creating Custom Holiday Calendars
Sometimes you need to define your own calendar for specific business rules or countries. Let's see how to create a custom holiday calendar:
Option 1: Extending the AbstractHolidayCalendar Class
from pandas.tseries.holiday import AbstractHolidayCalendar, Holiday, USMartinLutherKingJr
from pandas.tseries.offsets import DateOffset, Day
class MyBusinessCalendar(AbstractHolidayCalendar):
rules = [
Holiday('New Year', month=1, day=1),
USMartinLutherKingJr, # Reusing an existing holiday definition
Holiday('Company Foundation Day', month=3, day=15),
Holiday('Extra Holiday', year=2023, month=8, day=21),
Holiday('Christmas Eve', month=12, day=24),
Holiday('Christmas', month=12, day=25)
]
# Create an instance of our custom calendar
my_calendar = MyBusinessCalendar()
# Get holidays for 2023
custom_holidays = my_calendar.holidays(start='2023-01-01', end='2023-12-31')
print("Custom Business Calendar Holidays for 2023:")
print(custom_holidays)
Output:
Custom Business Calendar Holidays for 2023:
DatetimeIndex(['2023-01-01', '2023-01-16', '2023-03-15', '2023-08-21',
'2023-12-24', '2023-12-25'],
dtype='datetime64[ns]', freq=None)
Option 2: Using the holidays
Package
The holidays
package provides pre-defined holiday calendars for many countries:
import holidays
# Create a Canadian holiday calendar for 2023
ca_holidays = holidays.Canada(years=2023)
# Convert to a pandas DatetimeIndex
ca_holidays_index = pd.DatetimeIndex(ca_holidays.keys())
print("Canadian Holidays in 2023:")
print(ca_holidays_index)
# Check if a specific date is a holiday
date_to_check = pd.Timestamp('2023-07-01')
is_holiday = date_to_check in ca_holidays
print(f"Is {date_to_check.date()} a Canadian holiday? {is_holiday}")
if is_holiday:
print(f"It's {ca_holidays.get(date_to_check)}")
Output:
Canadian Holidays in 2023:
DatetimeIndex(['2023-01-01', '2023-01-02', '2023-02-20', '2023-04-07',
'2023-04-10', '2023-05-22', '2023-07-01', '2023-08-07',
'2023-09-04', '2023-09-30', '2023-10-09', '2023-11-11',
'2023-12-25', '2023-12-26'],
dtype='datetime64[ns]', freq=None)
Is 2023-07-01 a Canadian holiday? True
It's Canada Day
Creating Custom Business Days with Holiday Calendars
You can create a custom business day frequency that accounts for your specific holiday calendar:
# Create a custom business day with Canadian holidays
ca_holidays_list = holidays.Canada(years=[2023, 2024])
ca_business_day = CustomBusinessDay(holidays=ca_holidays_list)
# Create a range of Canadian business days
ca_business_days = pd.date_range(start='2023-12-20',
end='2024-01-10',
freq=ca_business_day)
print("Canadian business days (excluding weekends and Canadian holidays):")
print(ca_business_days)
Output:
Canadian business days (excluding weekends and Canadian holidays):
DatetimeIndex(['2023-12-20', '2023-12-21', '2023-12-22', '2023-12-27',
'2023-12-28', '2023-12-29', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-08', '2024-01-09', '2024-01-10'],
dtype='datetime64[ns]', freq='C')
Notice that December 25-26, 2023 (Christmas and Boxing Day) and January 1-2, 2024 (New Year's Day and the observed holiday) are excluded.
Practical Business Applications
Example 1: Calculating Business Days Between Dates
Let's say you want to calculate how many business days it will take to deliver a product:
def business_days_between(start_date, end_date, country='US'):
"""Calculate business days between two dates accounting for holidays."""
if country == 'US':
cal = USFederalHolidayCalendar()
holidays_list = cal.holidays(start=start_date, end=end_date)
elif country == 'CA':
holidays_list = holidays.Canada(years=range(start_date.year, end_date.year + 1))
else:
raise ValueError(f"Country {country} not supported")
business_day = CustomBusinessDay(holidays=holidays_list)
return len(pd.date_range(start=start_date, end=end_date, freq=business_day)) - 1
order_date = pd.Timestamp('2023-12-15')
expected_delivery = pd.Timestamp('2024-01-05')
us_days = business_days_between(order_date, expected_delivery, 'US')
ca_days = business_days_between(order_date, expected_delivery, 'CA')
print(f"Order placed on {order_date.date()}, expected delivery on {expected_delivery.date()}")
print(f"Business days for delivery in US: {us_days}")
print(f"Business days for delivery in Canada: {ca_days}")
Output:
Order placed on 2023-12-15, expected delivery on 2024-01-05
Business days for delivery in US: 14
Business days for delivery in Canada: 13
Example 2: Financial Date Calculations for Payment Terms
Many financial calculations depend on business days. Let's calculate a payment due date based on net-30 terms:
def calculate_due_date(invoice_date, terms_days, country='US'):
"""Calculate the due date given invoice date and payment terms in business days."""
if country == 'US':
holidays_list = holidays.US(years=range(invoice_date.year, invoice_date.year + 2))
elif country == 'CA':
holidays_list = holidays.Canada(years=range(invoice_date.year, invoice_date.year + 2))
else:
raise ValueError(f"Country {country} not supported")
business_day = CustomBusinessDay(holidays=holidays_list)
return invoice_date + terms_days * business_day
invoice_date = pd.Timestamp('2023-12-10')
us_due_date = calculate_due_date(invoice_date, 30, 'US')
ca_due_date = calculate_due_date(invoice_date, 30, 'CA')
print(f"Invoice date: {invoice_date.date()}")
print(f"Due date (US holidays): {us_due_date.date()}")
print(f"Due date (Canadian holidays): {ca_due_date.date()}")
Output:
Invoice date: 2023-12-10
Due date (US holidays): 2024-01-24
Due date (Canadian holidays): 2024-01-25
Working with Multiple Calendars
Sometimes you may need to combine multiple holiday calendars for international business:
# Create a combined holiday calendar for a company with offices in US and UK
us_holidays = holidays.US(years=[2023, 2024])
uk_holidays = holidays.UK(years=[2023, 2024])
# Combine the holiday dates
combined_holidays = set(us_holidays.keys()).union(set(uk_holidays.keys()))
combined_holidays = pd.DatetimeIndex(sorted(combined_holidays))
# Create a custom business day with combined holidays
international_business_day = CustomBusinessDay(holidays=combined_holidays)
# Create a date range with the combined business days
international_days = pd.date_range(start='2023-12-20',
end='2024-01-10',
freq=international_business_day)
print("Business days excluding both US and UK holidays:")
print(international_days)
Output:
Business days excluding both US and UK holidays:
DatetimeIndex(['2023-12-20', '2023-12-21', '2023-12-22', '2023-12-27',
'2023-12-28', '2023-12-29', '2024-01-02', '2024-01-03',
'2024-01-04', '2024-01-05', '2024-01-08', '2024-01-09',
'2024-01-10'],
dtype='datetime64[ns]', freq='C')
Summary
Holiday calendars in Pandas provide a flexible system for working with business days while accounting for holidays. This functionality is essential for:
- Creating accurate business date ranges
- Calculating correct delivery times or project schedules
- Financial modeling with proper accounting for non-business days
- International business operations that need to account for multiple holiday calendars
You've learned how to:
- Use built-in holiday calendars
- Create custom holiday calendars
- Use the
holidays
package for country-specific holidays - Create custom business day frequencies
- Apply holiday calendars to practical business problems
By leveraging these tools, you can create more accurate and reliable time series analyses that account for real-world business conditions.
Practice Exercises
- Create a custom holiday calendar for your country or region if it's not already supported by the
holidays
package. - Calculate the number of business days in each month of 2024 for a country of your choice.
- Develop a function that calculates shipping dates based on processing time (in business days) and different shipping services.
- Create a visualization showing the distribution of holidays across different countries throughout the year.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)