Beginner
Determining the current date is a public holiday can be tricky when holidays change and it of course changes from country to country. From system time of servers & machines running to timestamps for tracking the transactions and events in e-commerce platforms, the date and time play a major role. There are a variety of use cases related to manipulating date and time that can be solved using the inbuilt datetime module in Python3, such as
- Finding if a given year is a leap year or an ordinary year
- Finding the number of days between the two mentioned dates
- Convert between different date or time formats
What if you were to check if a given date is a public holiday? There isn’t any specific formula or logic to determine that, do we? Holidays can be pre-defined or uncalled for.
Here, we will be exploring the two ways to detect if a date is a holiday or not.
Checking For Public Holiday With Holidays Module
Although Python3 doesn’t provide any modules to detect if a date is a holiday or not, there are some of the external modules that help in detecting this. One of those modules is Holidays.
In your terminal, type in the following to get the module installed.
sudo pip3 install holidays

Now that our module is ready, let’s understand a bit about what the module and what it is capable of. Have a look at the following code snippet.
'''
Snippet to check if a given date is a holiday
'''
from datetime import date # Step 1
import holidays
us_holidays = holidays.UnitedStates() # Step 2
input_date = input("Enter the date as YYYY-MM-DD: ") # Step 3
holiday_name = us_holidays .get(input_date) # Step 4
if holiday_name != None:
output = "{} is a US Holiday - It's {}".format(input_date, holiday_name)
else:
output = "{} is not a US Holiday".format(input_date)
# Step 5
print (output)
In the above snippet,
- Step 1: Imports the required modules
- Step 2: Initializes the us_holidays object, so that the corresponding
getfunction can be invoked at step 3 - Step 3: Gets
dateinput from the user - Step 4: Invokes the get function of the
holidaysmodule. This returns the name of the holiday if the date is a holiday or returnsNonein case if it isn’t. This gets assigned to the variable –holiday_name. - Step 5: Based on the variable –
holiday_name, using theifclause the string formatting is done. Can you make this if clause even leaner? Read this article to know about the One line if else statements.
Here’s what the output looks like.

Checking For Holidays With API Call to Calendarific
The above method is suitable for simple projects; however, it can never be used to provide an enterprise-grade solution. Let’s say, you are building a web application for a holiday and travel startup, building an enterprise-grade application requires an enterprise-grade solution. If you haven’t noticed, the holidays module is pretty simple and if you consider state-wise or newly announced holidays, then this solution doesn’t simply cut for a large-scale application.
Enterprise requirements such as these can be satisfied by using external APIs such as Calendarific which provides the API as a service for such applications to consume. They keep updating the holidays of states and countries constantly, and the applications may consume these APIs. Of course, enterprise solutions don’t always come free, but the developer account has a limit of 1000API requests per month.
Locate to https://calendarific.com/ on your favorite browser and follow the steps as shown in the following images to get yourself a free account and an API key for this exercise.




Understanding the Calendarific REST API
Before we could dive into using the API KEY, get yourself a REST API client – Insomnia or Postman. We are about to test our API key if we are able to retrieve the holiday information. Plugin the following URL by replacing [APIKEY] text with your API KEY received from above on your REST client.
https://calendarific.com/api/v2/holidays?api_key=[APIKEY]&country=us-ny&type=national&year=2020&month=1&day=1
In the above URL:
- https://calendarific.com/api/v2 is the API Base URL
- /holidays is the API route
- api_key, country, type, year, month, day are URL Parameters
- Each parameter has a value allocated to it with an = (equal sign)
- Each parameter and value pair is split by an & (ampersand)
For the above API call, the following response will be received; the value corresponding to the code key under the meta tag as ‘200’ corresponds to a successful response.
{
"meta": {
"code": 200
},
"response": {
"holidays": [
{
"name": "New Year's Day",
"description": "New Year's Day is the first day of the Gregorian calendar, which is widely used in many countries such as the USA.",
"country": {
"id": "us",
"name": "United States"
},
"date": {
"iso": "2020-01-01",
"datetime": {
"year": 2020,
"month": 1,
"day": 1
}
},
"type": [
"National holiday"
],
"locations": "All",
"states": "All"
}
]
}
}
The REST API call has returned some useful info about the National holiday on the 1st of January. Let’s see if it’s able to detect for the 2nd of January. Plugin the following URL again by replacing the text [APIKEY] with your API Key.
https://calendarific.com/api/v2/holidays?api_key=[APIKEY]&country=us-ny&type=national&year=2020&month=1&day=2
The above URL should be returning a response similar to below.
{
"meta": {
"code": 200
},
"response": {
"holidays": []
}
}
Indeed, the 2nd of January is not a public holiday and hence, the holidays list inside the response nested JSON key turns out to be an empty list.
Now we know that our API works very well, it is now time to incorporate Calendarific REST API into our Python code. We will be using the requests module in order to make this happen. Here’s how it is done.
'''
Snippet to check if a given date is a holiday using an external API - Calendarific
'''
import requests # Step 1
api_key = '[APIKEY]' # Step 2
base_url = 'https://calendarific.com/api/v2'
api_route = '/holidays'
location = input("Enter Country & State code - E.g.: us-ny: ")
date_inpt = input("Enter the date as YYYY-MM-DD: ") # Step 3
y, m, d = date_inpt.split('-')
full_url = '{}{}?api_key={}&country={}&type=national&year={}&month={}&day={}'\
.format(base_url, api_route, api_key, location, str(int(y)), str(int(m)), str(int(d))) # Step 4
response = requests.get(full_url).json() # Step 5
if response['response']['holidays'] != []:
print ("{} is a holiday - {}".format(date_inpt, response['response']['holidays'][0]['name']))
else: # Step 6
print ("{} is not a holiday".format(date_inpt))
In the above snippet,
- Step 1: Import requests module – you will be needing this module to invoke the REST API.
- Step 2: Replace ‘[APIKEY]’ with your own API key from Calendarific
- Step 3: The user inputs the corresponding location and date for which the holiday needs to be detected
- Step 4: String formatting in order to frame the URL
- Step 5: Invoke the API and convert the response to a JSON; i.e.) a dictionary
- Step 6: If clause checks for the presence of an empty list or with a returned response.
Here’s what the output looks like.

And there you have it, a working example for detecting if a given date is a holiday using an external API.
Summary
From an overall perspective, there could be multiple ways to solve a given problem, and here, we have portrayed two of those ways in detecting if a given date is a holiday or not. One is a straight forward out-of-the-box solution and the other one is an enterprise-ready solution, which one would you choose?
Subscribe to our newsletter
How To Use Python prettytable for ASCII Table Output
Beginner
When you print a list of dictionaries or a set of results in a Python script, you get a wall of text that is hard to read. You can spend time manually formatting columns with str.ljust() and calculating widths, or you can use PrettyTable and have a properly aligned table in three lines. It is one of those small libraries that makes CLI tools and scripts significantly more professional-looking with almost no effort.
PrettyTable is a Python library for printing formatted ASCII tables to the terminal. It handles column alignment, sorting, padding, and borders automatically. You just add your headers and rows. Beyond basic display, it can export tables to CSV, JSON, and HTML — so the same table you print in the terminal can become a web page element without any reformatting.
This article covers installation, building tables by rows and columns, sorting, selecting specific columns, border styles, and exporting to other formats. It ends with a real-world example — a system report script that formats multiple metrics into a clean terminal display. By the end you will have a reusable pattern for any script that needs to display structured data cleanly.
Printing a Python Table with PrettyTable: Quick Example
Here is the minimal path from data to formatted table:
# quick_prettytable.py
from prettytable import PrettyTable
table = PrettyTable()
table.field_names = ["Name", "Language", "Stars"]
table.add_row(["Flask", "Python", 67000])
table.add_row(["Django", "Python", 78000])
table.add_row(["FastAPI", "Python", 74000])
table.add_row(["Express", "JavaScript", 62000])
print(table)
Output:
+---------+------------+-------+
| Name | Language | Stars |
+---------+------------+-------+
| Flask | Python | 67000 |
| Django | Python | 78000 |
| FastAPI | Python | 74000 |
| Express | JavaScript | 62000 |
+---------+------------+-------+
PrettyTable calculates column widths automatically, aligns text left and numbers right, and draws the border. No manual padding, no f-string gymnastics. The sections below show sorting, filtering columns, styling borders, and exporting to HTML and JSON.
What Is PrettyTable and When Should You Use It?
PrettyTable is a pure-Python library for generating formatted plain-text tables. It is designed for command-line tools, scripts, and any situation where you want to display tabular data without the weight of a full terminal UI framework. The tables it produces are plain ASCII, making them compatible with any terminal, log file, or text-based report.
| Library | Output | Sorting | Export | Best For |
|---|---|---|---|---|
| print() + f-strings | Manual alignment | Manual | Manual | Simple one-off output |
| PrettyTable | ASCII table, auto-align | Built-in | CSV, HTML, JSON | CLI tools, scripts, reports |
| tabulate | Many formats (grid, pipe, markdown) | No | Limited | Markdown docs, pandas output |
| rich Table | Color, styled, unicode | No | No | Colorful terminal apps |
PrettyTable is the right choice when you want a simple, dependency-light table with sorting and export capabilities. Use the rich library instead when you need color and visual styling. Use tabulate when you need Markdown or pipe-delimited output for documentation.
Installing PrettyTable
# terminal
pip install prettytable
Output:
Successfully installed prettytable-3.10.0 wcwidth-0.2.13
PrettyTable has no heavy dependencies. It installs in seconds and works with Python 3.7 and above. Import it with from prettytable import PrettyTable.
Building Tables Row by Row and Column by Column
You can build a PrettyTable either row by row (the most common approach) or column by column. Column-by-column is useful when your data is already organized in lists per field:
# build_methods.py
from prettytable import PrettyTable
# Method 1: Add rows one at a time
table1 = PrettyTable(["City", "Country", "Population"])
table1.add_row(["Tokyo", "Japan", 13960000])
table1.add_row(["Delhi", "India", 32940000])
table1.add_row(["Shanghai", "China", 28516000])
table1.add_row(["Sao Paulo", "Brazil", 22430000])
print("Row method:")
print(table1)
print()
# Method 2: Add all rows at once with add_rows()
table2 = PrettyTable(["Product", "Price", "Stock"])
table2.add_rows([
["Widget A", 9.99, 150],
["Widget B", 24.99, 45],
["Widget C", 4.49, 500],
])
print("add_rows() method:")
print(table2)
Output:
Row method:
+-----------+---------+------------+
| City | Country | Population |
+-----------+---------+------------+
| Tokyo | Japan | 13960000 |
| Delhi | India | 32940000 |
| Shanghai | China | 28516000 |
| Sao Paulo | Brazil | 22430000 |
+-----------+---------+------------+
add_rows() method:
+----------+-------+-------+
| Product | Price | Stock |
+----------+-------+-------+
| Widget A | 9.99 | 150 |
| Widget B | 24.99 | 45 |
| Widget C | 4.49 | 500 |
+----------+-------+-------+
Notice that PrettyTable automatically right-aligns numeric columns and left-aligns text columns. The Population and Price columns are right-aligned without any configuration. You can override alignment per column with table.align["City"] = "r" if needed.
Sorting Tables
PrettyTable sorts on any column by name. You can also reverse the order and sort at print time or at data-entry time:
# sorting_tables.py
from prettytable import PrettyTable
table = PrettyTable(["Package", "Version", "Downloads/Month"])
table.add_rows([
["requests", "2.31", "450000000"],
["numpy", "1.26", "180000000"],
["pandas", "2.1", "150000000"],
["boto3", "1.34", "120000000"],
["setuptools", "69.0", "380000000"],
])
# Sort by downloads descending
table.sortby = "Downloads/Month"
table.reversesort = True
print("Sorted by downloads (desc):")
print(table)
print()
# Sort at print time with get_string()
print("Sorted by Package name:")
print(table.get_string(sortby="Package"))
Output:
Sorted by downloads (desc):
+------------+---------+-----------------+
| Package | Version | Downloads/Month |
+------------+---------+-----------------+
| requests | 2.31 | 450000000 |
| setuptools | 69.0 | 380000000 |
| numpy | 1.26 | 180000000 |
| pandas | 2.1 | 150000000 |
| boto3 | 1.34 | 120000000 |
+------------+---------+-----------------+
Sorted by Package name:
+------------+---------+-----------------+
| Package | Version | Downloads/Month |
+------------+---------+-----------------+
| boto3 | 1.34 | 120000000 |
| numpy | 1.26 | 180000000 |
| pandas | 2.1 | 150000000 |
| requests | 2.31 | 450000000 |
| setuptools | 69.0 | 380000000 |
+------------+---------+-----------------+
Setting table.sortby makes the sort persistent — subsequent print(table) calls will always use that sort. Using get_string(sortby=...) applies a one-time sort without changing the table’s default. This is useful when you want different views of the same data without modifying the table object.
Selecting Specific Columns and Rows
The get_string() method accepts fields to show only selected columns, and start/end to paginate rows:
# filter_display.py
from prettytable import PrettyTable
table = PrettyTable(["ID", "Name", "Department", "Salary", "Start Date"])
table.add_rows([
[1, "Alice Chen", "Engineering", 95000, "2021-03-15"],
[2, "Bob Torres", "Marketing", 72000, "2020-07-01"],
[3, "Carol White", "Engineering", 88000, "2022-01-10"],
[4, "David Kim", "HR", 65000, "2019-11-20"],
[5, "Eva Martinez", "Engineering", 102000, "2023-06-01"],
])
# Show only selected columns
print("Engineering salary view:")
print(table.get_string(fields=["Name", "Department", "Salary"],
sortby="Salary", reversesort=True))
print()
# Paginate: show rows 1-3 only
print("First 3 rows only:")
print(table.get_string(start=0, end=3))
Output:
Engineering salary view:
+--------------+-------------+--------+
| Name | Department | Salary |
+--------------+-------------+--------+
| Eva Martinez | Engineering | 102000 |
| Alice Chen | Engineering | 95000 |
| Carol White | Engineering | 88000 |
| Bob Torres | Marketing | 72000 |
| David Kim | HR | 65000 |
+--------------+-------------+--------+
First 3 rows only:
+----+-------------+-------------+--------+------------+
| ID | Name | Department | Salary | Start Date |
+----+-------------+-------------+--------+------------+
| 1 | Alice Chen | Engineering | 95000 | 2021-03-15 |
| 2 | Bob Torres | Marketing | 72000 | 2020-07-01 |
| 3 | Carol White | Engineering | 88000 | 2022-01-10 |
+----+-------------+-------------+--------+------------+
Border Styles
PrettyTable includes several built-in junction characters for different visual styles. You can also disable the border entirely for tab-separated output:
# border_styles.py
from prettytable import PrettyTable, SINGLE_BORDER, DOUBLE_BORDER, MARKDOWN
table = PrettyTable(["Name", "Score"])
table.add_rows([["Alice", 95], ["Bob", 87], ["Carol", 92]])
print("Default (classic ASCII):")
print(table)
print("\nSingle line border:")
table.set_style(SINGLE_BORDER)
print(table)
print("\nDouble line border:")
table.set_style(DOUBLE_BORDER)
print(table)
print("\nMarkdown format:")
table.set_style(MARKDOWN)
print(table)
Output:
Default (classic ASCII):
+-------+-------+
| Name | Score |
+-------+-------+
| Alice | 95 |
| Bob | 87 |
| Carol | 92 |
+-------+-------+
Single line border:
+-------+-------+
| Name | Score |
+-------+-------+
...
Markdown format:
| Name | Score |
| ----- | ----- |
| Alice | 95 |
| Bob | 87 |
| Carol | 92 |
The MARKDOWN style is particularly useful when generating documentation or writing to a file that will be rendered as Markdown. SINGLE_BORDER and DOUBLE_BORDER use Unicode box-drawing characters for a more polished look in terminals that support them.
Exporting Tables to HTML, JSON, and CSV
PrettyTable can render the same data as HTML, JSON, or CSV with no extra code:
# export_formats.py
from prettytable import PrettyTable
table = PrettyTable(["Country", "Capital", "Population"])
table.add_rows([
["Germany", "Berlin", 3677000],
["France", "Paris", 2148000],
["Italy", "Rome", 2873000],
["Spain", "Madrid", 3305000],
])
# Export to HTML
html_output = table.get_html_string()
print("HTML output (first 300 chars):")
print(html_output[:300])
print()
# Export to JSON
json_output = table.get_json_string()
print("JSON output (first 200 chars):")
print(json_output[:200])
print()
# Export to CSV
csv_output = table.get_csv_string()
print("CSV output:")
print(csv_output)
Output:
HTML output (first 300 chars):
<table>
<thead>
<tr>
<th>Country</th>
<th>Capital</th>
<th>Population</th>
</tr>
</thead>
<tbody>
<tr>
<td>Germany</td>
...
JSON output (first 200 chars):
[{"Country": "Germany", "Capital": "Berlin", "Population": 3677000},
{"Country": "France", "Capital": "Paris", "Population": 2148000},
...
CSV output:
Country,Capital,Population
Germany,Berlin,3677000
France,Paris,2148000
Italy,Rome,2873000
Spain,Madrid,3305000
All three export methods respect the current sort order and selected fields from sortby and field_names. This means you can build one table, display it in the terminal, write the HTML version to a report file, and save the CSV for further processing — all from the same object without any duplication.
Real-Life Example: System Resource Monitor Report
Here is a practical script that collects system metrics and formats them into a terminal report using PrettyTable:
# system_report.py
import os
import shutil
from prettytable import PrettyTable, SINGLE_BORDER
def get_disk_usage():
"""Return disk usage for common paths."""
paths = ["/", "/tmp"] if os.name != "nt" else ["C:\\", "D:\\"]
rows = []
for path in paths:
if os.path.exists(path):
total, used, free = shutil.disk_usage(path)
pct = (used / total) * 100
rows.append([
path,
f"{total // (1024**3)} GB",
f"{used // (1024**3)} GB",
f"{free // (1024**3)} GB",
f"{pct:.1f}%",
])
return rows
def make_env_table(keys):
"""Show selected environment variables."""
table = PrettyTable(["Variable", "Value"])
table.set_style(SINGLE_BORDER)
table.align["Variable"] = "l"
table.align["Value"] = "l"
table.max_width["Value"] = 40
for key in keys:
val = os.environ.get(key, "(not set)")
table.add_row([key, val])
return table
# Disk usage table
disk_table = PrettyTable(["Mount", "Total", "Used", "Free", "Usage %"])
disk_table.set_style(SINGLE_BORDER)
for row in get_disk_usage():
disk_table.add_row(row)
# Environment variables table
env_table = make_env_table(["HOME", "PATH", "SHELL", "LANG", "USER"])
# Python info table
py_table = PrettyTable(["Setting", "Value"])
py_table.set_style(SINGLE_BORDER)
import sys
py_table.add_rows([
["Python version", sys.version.split()[0]],
["Platform", sys.platform],
["Prefix", sys.prefix[:40]],
["Executable", sys.executable[:40]],
])
print("=== Disk Usage ===")
print(disk_table)
print("\n=== Environment Variables ===")
print(env_table)
print("\n=== Python Environment ===")
print(py_table)
Output:
=== Disk Usage ===
+-------+-------+------+------+---------+
| Mount | Total | Used | Free | Usage % |
+-------+-------+------+------+---------+
| / | 500 GB| 120 GB| 380 GB| 24.0% |
| /tmp | 500 GB| 120 GB| 380 GB| 24.0% |
+-------+-------+------+------+---------+
=== Environment Variables ===
+----------+-------------------------------+
| Variable | Value |
+----------+-------------------------------+
| HOME | /home/alice |
| PATH | /usr/local/bin:/usr/bin:/bin |
| SHELL | /bin/bash |
...
=== Python Environment ===
+----------------+----------------------------+
| Setting | Value |
+----------------+----------------------------+
| Python version | 3.12.1 |
| Platform | linux |
...
The max_width property on the Value column prevents long PATH entries from wrecking the table layout. table.align["Variable"] = "l" forces left alignment on a column that PrettyTable might otherwise center. You can extend this example by adding a network interfaces section, a process list, or writing the HTML version to a file for a daily system report.
Frequently Asked Questions
Does PrettyTable handle Unicode characters correctly?
Yes, PrettyTable uses the wcwidth library to calculate the display width of Unicode characters correctly, including CJK double-width characters. This means columns with Chinese, Japanese, or Korean text will align properly in the terminal. Make sure your terminal uses a font that supports the characters you are displaying.
Can I build a PrettyTable directly from a CSV file?
Yes. Use from prettytable import from_csv and pass an open file object: table = from_csv(open("data.csv")). There are similar from_json() and from_html_one() constructors for importing from those formats. This makes PrettyTable useful as a quick display layer for any data file without having to parse it manually.
How do I prevent long text from breaking the table layout?
Set table.max_width["ColumnName"] = N to cap the display width of a specific column at N characters. Content longer than N is truncated with an ellipsis. You can also set a global max width with table.max_width = 30. This is essential for columns that might contain long strings like file paths, URLs, or log messages.
Can I add color to PrettyTable output?
PrettyTable itself does not support ANSI color codes natively — it focuses on structure rather than styling. For colorful tables, use the rich library’s Table class instead, which has full color, bold, italic, and Unicode border support. You can also print PrettyTable output inside a rich.console.Console call without modification if you just want to wrap the ASCII output in color.
How does PrettyTable compare to printing a pandas DataFrame?
Pandas DataFrames print as formatted tables natively when you call print(df), but the output uses spaces for alignment without borders. PrettyTable gives you explicit borders, sorting, and export formats that pandas does not. For data analysis workflows already using pandas, tabulate is often a better companion since it directly accepts DataFrames. Use PrettyTable for scripts that are not already using pandas.
Conclusion
PrettyTable is the fastest path from raw data to a readable terminal table. The API is minimal — create a table, set field names, add rows, print. Sorting, column selection, and export to HTML, JSON, and CSV work out of the box. The border style options give you a professional look with one line change.
Try extending the system report example by adding a table of the top 10 running processes sorted by CPU usage, using the psutil library to get process data. Then export the full report as HTML and open it in a browser. Once you have PrettyTable in your CLI toolkit, your debugging scripts and data reports will never look the same.
See the official PrettyTable GitHub repository for the full API reference and changelog.
Related Articles
Further Reading: For more details, see the Python datetime module documentation.
Pro Tips for Working with Public Holidays in Python
1. Cache Holiday Data to Avoid Repeated API Calls
If you are using the Calendarific API, cache the results locally instead of calling the API every time you check a date. Holiday lists for a given country and year rarely change. Save the API response to a JSON file and only refresh it when the year changes. This reduces API usage and makes your application faster.
# cache_holidays.py
import json
import os
from datetime import date
CACHE_FILE = "holidays_cache.json"
def get_cached_holidays(country, year):
if os.path.exists(CACHE_FILE):
with open(CACHE_FILE, "r") as f:
cache = json.load(f)
key = f"{country}_{year}"
if key in cache:
print(f"Using cached holidays for {country} {year}")
return cache[key]
return None
def save_to_cache(country, year, holidays):
cache = {}
if os.path.exists(CACHE_FILE):
with open(CACHE_FILE, "r") as f:
cache = json.load(f)
cache[f"{country}_{year}"] = holidays
with open(CACHE_FILE, "w") as f:
json.dump(cache, f, indent=2)
print(f"Cached {len(holidays)} holidays for {country} {year}")
Output:
Cached 11 holidays for US 2026
Using cached holidays for US 2026
2. Calculate Business Days Excluding Holidays
One of the most common real-world uses of holiday detection is calculating business days. Combine the holidays library with Python’s datetime to count only working days between two dates, excluding weekends and public holidays. This is essential for shipping estimates, SLA calculations, and payroll processing.
# business_days.py
import holidays
from datetime import date, timedelta
def business_days_between(start, end, country="US"):
us_holidays = holidays.country_holidays(country)
count = 0
current = start
while current <= end:
if current.weekday() < 5 and current not in us_holidays:
count += 1
current += timedelta(days=1)
return count
start = date(2026, 12, 20)
end = date(2026, 12, 31)
days = business_days_between(start, end)
print(f"Business days from {start} to {end}: {days}")
Output:
Business days from 2026-12-20 to 2026-12-31: 7
3. Handle Multiple Countries for International Apps
If your application serves users in different countries, check holidays for each user's country rather than assuming a single country. The holidays library supports 100+ countries. Store each user's country code and pass it when checking holidays. Remember that some countries have regional holidays too -- for example, different states in Australia or provinces in Canada have different public holidays.
4. Build a Holiday-Aware Scheduler
Many applications need to skip processing on holidays. Instead of checking manually every time, create a decorator that wraps scheduled tasks and automatically skips execution on public holidays. This is useful for automated reports, email campaigns, and batch processing jobs that should only run on business days.
# holiday_aware_scheduler.py
import holidays
from datetime import date
from functools import wraps
def skip_on_holidays(country="US"):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
today = date.today()
if today in holidays.country_holidays(country):
name = holidays.country_holidays(country).get(today)
print(f"Skipping {func.__name__}: today is {name}")
return None
return func(*args, **kwargs)
return wrapper
return decorator
@skip_on_holidays("US")
def send_daily_report():
print("Sending daily report...")
return "Report sent"
result = send_daily_report()
print(f"Result: {result}")
Output (on a regular business day):
Sending daily report...
Result: Report sent
5. Display Upcoming Holidays for Better UX
Show your users which holidays are coming up so they can plan ahead. This is valuable for project management tools, delivery estimate pages, and HR applications. Sort the holiday list by date and filter for upcoming dates only to give users a clear view of the next few holidays.
Frequently Asked Questions
How do I check if a date is a public holiday in Python?
Use the holidays library: install it with pip install holidays, then check with date in holidays.country_holidays('US'). It returns True if the date is a recognized public holiday for that country.
What countries does the Python holidays library support?
The holidays library supports over 100 countries and their subdivisions. Major countries include the US, UK, Canada, Australia, Germany, France, India, and many more. Use holidays.list_supported_countries() to see the complete list.
Can I add custom holidays to the holidays library?
Yes. Create a custom holiday class inheriting from the country class, or use the append() method to add individual dates. You can also create entirely custom holiday calendars for company-specific or regional holidays.
How do I get the name of a holiday for a specific date?
Access the holiday name with holidays.country_holidays('US').get(date), which returns the holiday name as a string, or None if it is not a holiday. You can also iterate over the holidays object to list all holidays in a year.
Is the holidays library useful for business day calculations?
Yes. Combine it with numpy.busday_count() or pandas.bdate_range() to calculate working days excluding public holidays. This is useful for project management, payroll calculations, and delivery date estimation.