retailcalendar
A Python package for working with the NRF 4-5-4 Retail Calendar and public holiday calendars for Brazil and the United States.
The retail calendar groups weeks into months following a 4-5-4 week pattern per quarter, giving retailers a consistent structure for fiscal year reporting. Some years have 53 weeks (a "53-week year") — this package handles that automatically.
Installation
pip install retailcalendar
CLI Usage
# Display the 4-5-4 calendar for the current year
454cal
# Display for a specific year
454cal 2025
# Use a different fiscal year start month (default is January)
454cal --start_month 2 2025
# Disable today and holiday highlights
454cal -d 2025
# Use a color theme
454cal -t ocean 2025
454cal -t sunset 2025
# Use a different holiday region
454cal -r US 2025
454cal -r BR-SP-SAO 2025
# Combine options
454cal -t matrix -r US 2025
The output is a color-formatted calendar printed to the terminal, organized with 3 months per row and week numbers on the left. Public holidays and today's date are highlighted using the active color theme.
CLI Options
| Option | Default | Description |
|---|---|---|
-s / --start_month |
1 |
Fiscal year start month (1–12) |
-d / --days_highlight_off |
off | Disable today and holiday highlights |
-t / --theme |
default |
Color theme (see Themes) |
-r / --region |
BR-PR-CWB |
Holiday region (see Supported Regions) |
YEAR |
current year | Fiscal year to display |
Themes
| Theme | Description |
|---|---|
default |
Classic terminal colors — red, yellow, green, purple |
ocean |
Blues and teals |
sunset |
Warm oranges and golds |
monokai |
Editor-inspired — magentas, chartreuse, purple |
retro |
Amber CRT monitor — warm monochrome |
matrix |
Green phosphor terminal — monochrome green |
sakura |
Japanese cherry blossom — soft pinks |
ice |
Arctic frost — crisp whites and pale blues |
volcano |
Volcanic lava — deep reds and glowing yellows |
Python API
Cal454 — NRF 4-5-4 Retail Calendar
from retailcalendar import Cal454, CalendarTheme
# Create a calendar for fiscal year 2025 (starts February 2025)
cal = Cal454(year=2025, s_month=2)
# Display the full calendar (holidays highlighted by default)
cal.format_year()
cal.format_year(highlight_today=False, highlight_holidays=False)
# Use a built-in color theme
cal.format_year(theme="ocean")
cal.format_year(theme="volcano", region="US")
# Define a custom theme
my_theme = CalendarTheme(
year_title="bold blue",
month_name="cyan",
day_header="grey50",
week_number="bright_green",
today="bold white on dark_blue",
holiday="bold white on dark_green",
)
cal.format_year(theme=my_theme)
# Get month start/end dates (list of 12 dates)
cal.month_start_dates()
cal.month_end_dates()
# Get quarter start/end dates (list of 4 dates)
cal.quarter_start_dates()
cal.quarter_end_dates()
# Get all weeks in a given month (1-indexed)
cal.month_days_by_week(month=1)
# Get all weeks for the entire year
cal.year_days_by_week()
# Check if a year has 53 weeks
Cal454.has_43_weeks(year=2023) # True
Cal454.has_43_weeks(year=2023, s_month=1) # False
Cal454 Parameters
| Parameter | Default | Description |
|---|---|---|
year |
current year | Fiscal year to calculate |
s_month |
2 |
Fiscal year start month (1–12) |
format_year() Parameters
| Parameter | Default | Description |
|---|---|---|
w_col |
2 |
Column width per day (min 2) |
space_month |
3 |
Space between month columns (min 3) |
line_months |
3 |
Number of months per row (min 3) |
highlight_today |
True |
Highlight today's date |
highlight_holidays |
True |
Highlight public holidays |
theme |
"default" |
Color theme name or CalendarTheme instance |
region |
"BR-PR-CWB" |
Holiday region code |
HolidayCalendar — Public Holiday Calculator
Calculates public holidays for a given region and year. Regions are defined in holidays.yaml and support inheritance — a city-level region automatically includes state and national holidays.
from retailcalendar import HolidayCalendar
cal = HolidayCalendar("BR-PR-CWB", 2025)
# Full list of holidays as dicts, sorted by date
for h in cal.holidays():
print(h["date"], h["name"])
# Just the canonical holiday dates
cal.dates() # list[date]
# Observed (legally effective) dates after weekend shifts
cal.observed_dates() # list[date]
Each dict returned by holidays() contains:
| Key | Type | Description |
|---|---|---|
date |
date |
Canonical holiday date |
observed |
date |
Effective date after weekend adjustment (next_monday / nearest_weekday) |
name |
str |
Local name |
name_en |
str | None |
English name |
type |
str |
Rule type: fixed, relative, offset, or complex |
region |
str |
Region code used for the lookup |
Supported Regions
| Code | Description |
|---|---|
BR |
Brazil — national holidays |
BR-PR |
Paraná state (inherits BR) |
BR-PR-CWB |
Curitiba city (inherits BR-PR) |
BR-SP |
São Paulo state (inherits BR) |
BR-SP-SAO |
São Paulo city (inherits BR-SP) |
US |
United States — federal holidays |
Holiday rule types
| Type | Description | Example |
|---|---|---|
fixed |
Same day/month every year | Christmas (Dec 25) |
relative |
Nth weekday of a given month | Thanksgiving (4th Thursday of November) |
offset |
N days before/after a base algorithm | Good Friday (Easter − 2 days) |
complex |
Full algorithm | Easter Sunday |
since field
Holidays with a since year are excluded for earlier years. For example, Brazil's Dia da Consciência Negra (since: 2024) does not appear for 2023 and earlier.
How the 4-5-4 Calendar Works
Each fiscal quarter follows a 4-5-4 week pattern:
| Month in Quarter | Weeks |
|---|---|
| First | 4 |
| Second | 5 |
| Third | 4 |
The fiscal year normally has 52 weeks. Per NRF rules, a 53rd week is added to the last month of the year when the last day of a standard 52-week year has 4 or more days remaining in the start month. Known 53-week years (February start): 2000, 2006, 2012, 2017, 2023, 2028.
The fiscal year starts on the Sunday on or before February 1 (or the configured start month).
Development
git clone https://github.com/thig0w/454calendar.git
cd 454calendar
# Set up development environment (venv, dev deps, pre-commit hooks)
make devenv
# Run formatter, linter, and tests
make precommit
# Run tests only
uv run pytest
# Build distribution package
make build
# Clean everything
make clean
Requirements: Python 3.10+
License
GNU General Public License v3.0 — see LICENSE.
Release files for retailcalendar 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| retailcalendar-1.0.0.tar.gz | 30.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| retailcalendar-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.1 kB
Release files / retailcalendar-1.0.0.tar.gz
| Download URL | retailcalendar-1.0.0.tar.gz |
|---|---|
| Size | 30.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fc7496bd2b405f8edcbb1f1e1b847a63a05e21e9b615aeabff49be9c8c18980c
|
|
BLAKE2b-256 checksum How to use checksums |
0fb37ba77e808232d87c057f9912f070e34fb666f32131709b18727d9a867433
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|
Release files / retailcalendar-1.0.0-py3-none-any.whl
| Download URL | retailcalendar-1.0.0-py3-none-any.whl |
|---|---|
| Size | 26.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
36cd11e61f6ffb06dc176c2e7b6b5ad8b67d80c0fa16f282e7ea65b26241727d
|
|
BLAKE2b-256 checksum How to use checksums |
a1bbc6e51791666c94271891851078ecd8d2473a57e7041ad412a9bb3e22fc60
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|