Skip to main content

PyCalendar API: Official Python Client for Moroccan Holidays & Business Days

Release PyPI version Python versions PyPI downloads License

PyCalendar API is the official, fully-typed Python client wrapper for the Calendar-API.ma platform. It allows developers to programmatically fetch Moroccan public holidays, track Hijri calendar events, and compute local business day data with minimal dependencies.

🔗 Quick Links: 📝 Register for Free | 📚 Documentation | ⚡ Live API Docs | 🟢 Health Check

📑 Table of Contents

✨ Key Features

  • Moroccan Public Holidays: Dynamically fetch national, religious, and exceptional holidays.
  • Dual Calendar Support: Track Religious and Exceptional holidays for accurate calculation and history sanitization.
  • Business Day Calculations: Calculate working days, skipping custom weekends and local banking closures.
  • Modern Python Design: Built with dataclasses, fully typed, and automatic JSON-to-Python object conversion.
  • Minimal Dependencies: Lightweight and fast.
  • Advanced Configuration: Supports .toml files for timeout, proxy, and certificate management.

📦 Installation

Install the latest version from PyPI:

pip install pycalendar-api

Quick Start & Usage Examples

Ensure that you are registered, if not, you can Register for free

Instanciate the API Client by providing one the active APIKeys from your console

from pycalendar_api import CalendarApi, to_date  # Util function for date creation

>>> api = CalendarApi('YOUR_API_KEY')
>>> print(api.health())
ApiHealth(api_status="UP", appname="calendar-api", timestamp=datetime.datetime.now())

Using the environment variable PYCALENDAR_APIKEY

# Ensure that the environment variable is defined
# export PYCALENDAR_APIKEY = YOUR_API_KEY
from pycalendar_api import CalendarApi, to_date  # Util function for date creation

>>> api = CalendarApi.from_env()
>>> print(api.health())
ApiHealth(api_status="UP", appname="calendar-api", timestamp=datetime.datetime.now())

🌙 Holidays API

Holidays domain of Calendar API.

  • Check if a date is a holiday
from pycalendar_api import CalendarApi, to_date

api = CalendarApi('YOUR_API_KEY') # or api = CalendarApi.from_env()

# Check if a date is a Holiday
>>> result = api.holidays.is_holiday(to_date('14/01/2025'))
>>> print(result)
HolidayCheckResult(
    date=datetime.date(2025, 1, 14), is_holiday=True,
    description="Nouvel An Amazigh", holiday_type=<CalHolidayType.NATIONAL: 'National'>,
    status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'
)
  • List holidays of a year or many years
>>> result = api.holidays.year(2025)
>>> print(result)
[
    Holiday(description="Jour de l'AN", day=1, month=1, date=datetime.date(2025, 1, 1), holiday_type=<CalHolidayType.NATIONAL: 'National'>, status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'),
    Holiday(description="Manifeste de l'Indépendance", day=11, month=1, date=datetime.date(2025, 1, 11), holiday_type=<CalHolidayType.NATIONAL: 'National'>, status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'),
    Holiday(description="Nouvel An Amazigh", day=14, month=1, date=datetime.date(2025, 1, 14), holiday_type=<CalHolidayType.NATIONAL: 'National'>, status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'),
    ...,
]

# List Holidays of many years
>>> result = api.holidays.years(list(range(2017, 2027)))
>>> print(result)
[
    Holiday(description="Jour de l'AN", day=1, month=1, date=datetime.date(2025, 1, 1), holiday_type=<CalHolidayType.NATIONAL: 'National'>, status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'),
    Holiday(description="Manifeste de l'Indépendance", day=11, month=1, date=datetime.date(2025, 1, 11), holiday_type=<CalHolidayType.NATIONAL: 'National'>, status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'),
    Holiday(description="Nouvel An Amazigh", day=14, month=1, date=datetime.date(2025, 1, 14), holiday_type=<CalHolidayType.NATIONAL: 'National'>, status=<CalHolidayStatus.OFFICIAL: 'Official'>, country_code='MA'),
    ...,
]

🏢 Business Days API

Business days domain of Calendar API.

Bdays operations

  • Fetch the next or previous Business day
# Next Business day
result = api.bdays.next_date(to_date('13/01/2025'))
>>> print(result)
NextDate(date=datetime.date(2025, 1, 13), next_date=datetime.date(2025, 1, 15))

# Previous Business day
result = api.bdays.previous_date(to_date('15/01/2025'))
>>> print(result)
PreviousDate(date=datetime.date(2025, 1, 15), previous_date=datetime.date(2025, 1, 13))
  • List Business days of a year or a month
# Business days of a year
result = api.bdays.bdays_of(2025)
>>> print(result)
DateSeries(
   ref='bdays-2025', min_date='2025-01-02', max_date='2025-12-31', freq=<CalFreq.DAILY: 'D'>, nitems=247,
   serie=SortedSet([datetime.date(2025, 1, 2), datetime.date(2025, 1, 3), datetime.date(2025, 1, 6), ..., datetime.date(2025, 12, 29), datetime.date(2025, 12, 30), datetime.date(2025, 12, 31)])
)

# Business days of a month
result = api.bdays.bdays_of(2025, month=6)
>>> print(result)
DateSeries(
   ref='bdays-2025-06', min_date='2025-06-02', max_date='2025-06-30', freq=<CalFreq.DAILY: 'D'>, nitems=19,
   serie=SortedSet([datetime.date(2025, 6, 2), datetime.date(2025, 6, 3), datetime.date(2025, 6, 4), datetime.date(2025, 6, 5), ..., datetime.date(2025, 6, 25), datetime.date(2025, 6, 26), datetime.date(2025, 6, 30)])
)
  • Count or List Business days between 2 dates
# Count Business days between 2 dates
>>> count = api.bdays.count(to_date('02/01/2025'), to_date('31/12/2025'))
>>> print(count)
DaysCount(start_date=datetime.date(2025, 1, 2), end_date=datetime.date(2025, 12, 31), count=247, freq=<CalFreq.DAILY: 'D'>)

# List Business days between 2 dates
>>> between = api.bdays.between(to_date('02/01/2025'), to_date('31/12/2025'))
>>> print(between)
DateSeries(
   ref='bdays', min_date='2025-01-02', max_date='2025-12-31', freq=<CalFreq.DAILY: 'D'>, nitems=247,
   serie=SortedSet([datetime.date(2025, 1, 2), datetime.date(2025, 1, 3), datetime.date(2025, 1, 6), ..., datetime.date(2025, 12, 29), datetime.date(2025, 12, 30), datetime.date(2025, 12, 31)])
)

Spans: Start/End of periods

Calculate the interval composed of the start and end dates of a given period. The start and end dates are open business days.

Successive intervals can be linked

# =============== SPANS: Start/End of periods ===============
# Year 2025 span
>>> span_year = api.bdays.span(2025)
>>> print(span_year)
CalSpan(start_date=datetime.date(2024, 12, 31), end_date=datetime.date(2025, 12, 31), year=2025, semester=None, quarter=None, month=None, country_code='MA')

# 1st Semester of year 2025
>>> span_s1 = api.bdays.span(2025, semester=1)
>>> print(span_s1)
CalSpan(start_date=datetime.date(2024, 12, 31), end_date=datetime.date(2025, 6, 30), year=2025, semester=1, quarter=None, month=None, country_code='MA')

# 3rd Quarter of year 2025
>>> span_quarter = api.bdays.span(2025, quarter=3)
>>> print(span_quarter)
CalSpan(start_date=datetime.date(2025, 6, 30), end_date=datetime.date(2025, 9, 30), year=2025, semester=None, quarter=3, month=None, country_code='MA')

# Month 7 of year 2025 (July) 
>>> span_month = api.bdays.span(2025, month=7)
>>> print(span_month)
CalSpan(start_date=datetime.date(2025, 6, 30), end_date=datetime.date(2025, 7, 31), year=2025, semester=None, quarter=None, month=7, country_code='MA')

🏷️ Enum Properties

Those properties are present in the Response objects and are used as query parameters.

🗂️ Holiday Type (StrEnum)

A Holiday has one of those types

Value Description
National The date is a national Holiday
Religious The date is a Religious Holiday (Check the status if it's Confirmed or not)
Exceptional The date is an exceptional or bridge Holiday

🌕 Holiday Status (StrEnum)

Those properties concern the religious holidays which are Estimated before the moon sighting, once confirmed their status change to Official.

Consider using polling (Every Hour) for religious holidays which are estimated.

Value Description
Official The Holiday is Official
Estimated Religious Holidays are estimated before the moon sighting

🛠️ Support

If you encounter any bugs or have questions, we are here to help:

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pycalendar_api-0.6.0.tar.gz (245.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pycalendar_api-0.6.0-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

Details for the file pycalendar_api-0.6.0.tar.gz.

File metadata

  • Download URL: pycalendar_api-0.6.0.tar.gz
  • Upload date:
  • Size: 245.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.12.11

File hashes

Hashes for pycalendar_api-0.6.0.tar.gz
Algorithm Hash digest
SHA256 4a1ed788e953602608c02ef3132a32e3d3478c80dc0d63f5ea6f65b3d4e14f39
MD5 14717743d7bce79fccee940c70192b16
BLAKE2b-256 eb4c62728d18b558c0579fafd9524d4ab4c7138e77ef360e7d60305b0f2e86f3

See more details on using hashes here.

File details

Details for the file pycalendar_api-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: pycalendar_api-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 26.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.12.11

File hashes

Hashes for pycalendar_api-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f862f999c8a552244b231658395ba6ff49dfb1de136ff46eb136e98c674dfc14
MD5 2f6831f6fb75dcc4524beaa6c88a2867
BLAKE2b-256 e7f628ab451248c2e84fc5a256bd69d6befdf8296ff05c12952f818063ac6cff

See more details on using hashes here.

Release history Release notifications | RSS feed

0.7.0

2 files

This release

0.6.0 This release

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page