Skip to main content

A modern Python library for multi-calendar date conversions (Jalali, Hijri, Gregorian)

Project description

🗓️ Waxt

PyPI version Python Versions License Code style: black Typed

A modern Python library for converting dates between Jalali (Persian/Solar), Hijri (Islamic/Lunar), and Gregorian calendars with full timezone support.


📦 Installation

pip install waxt

Requires Python 3.10+ and pytz.


✨ Features

Feature Description
🔄 Multi-Calendar Jalali (Persian/Solar), Hijri (Islamic/Lunar), Gregorian
🌍 Timezone Aware Full pytz timezone support — convert, localize, compare
📅 Date Arithmetic Add days/months with calendar-aware month lengths and leap years
🎨 Flexible Formatting Custom format strings (%Y, %m, %d, %H, %M, %S)
📝 Parsing Parse date strings back to datetime from any calendar
🌐 Localized Month Names Persian (fa), Arabic (ar), English (en)
🧪 Well Tested Comprehensive test suite with round-trip integrity checks
🎯 Type Hints Fully typed for great IDE support
🪶 Lightweight Only dependency: pytz

🚀 Quick Start

Create a Date

Date is the main entry point. Configure it with a timezone and calendar type.

from waxt.date_service import Date

# Jalali (Persian) calendar in Tehran
svc = Date(timezone="Asia/Tehran", calendar="jalali")

# Hijri (Islamic) calendar in Riyadh
svc = Date(timezone="Asia/Riyadh", calendar="hijri")

# Gregorian calendar in UTC (default-like)
svc = Date(timezone="UTC", calendar="gregorian")

Calendar options: "jalali", "hijri", "gregorian".


Current Date & Time

svc = Date(timezone="Asia/Tehran", calendar="jalali")

now = svc.now()                     # current datetime in Tehran
now_utc = svc.now_utc()            # current datetime in UTC

Get Date Components (Year, Month, Day)

Returns components in the configured calendar:

from datetime import datetime

svc = Date(timezone="Asia/Tehran", calendar="jalali")

dt = datetime(2025, 6, 15)
year, month, day = svc.get_date_components(dt)
# (1404, 3, 25) — Jalali equivalent

Format Dates

svc = Date(timezone="Asia/Tehran", calendar="jalali")
dt = datetime(2025, 6, 15, 14, 30, 0)

# Default format: YYYY/MM/DD
svc.format_date(dt)                        # "1404/03/25"

# With time
svc.format_date(dt, include_time=True)     # "1404/03/25 14:30:00"

# Custom format string
svc.format_date(dt, format_str="%Y-%m-%d") # "1404-03-25"
svc.format_date(dt, format_str="%d/%m/%Y %H:%M")  # "25/03/1404 14:30"

Format specifiers: %Y (year), %m (month), %d (day), %H (hour), %M (minute), %S (second).


Parse Date Strings

Parse a date string into a datetime object. Input is interpreted in the configured calendar.

svc = Date(timezone="Asia/Tehran", calendar="jalali")

dt = svc.parse_date("1404/03/25")
# datetime(2025, 6, 15, 0, 0, 0) — Gregorian equivalent

dt = svc.parse_date("1404-03-25 14:30:00")
# datetime(2025, 6, 15, 14, 30, 0)

Timezone Conversion

from datetime import datetime
import pytz

svc = Date(timezone="Asia/Tehran", calendar="gregorian")

utc_dt = datetime(2025, 6, 15, 10, 0, 0, tzinfo=pytz.UTC)

# UTC → Tehran
local_dt = svc.to_local(utc_dt)
# datetime(2025, 6, 15, 13, 30, 0, tzinfo=...)

# Tehran → UTC
back_to_utc = svc.to_utc(local_dt)
# datetime(2025, 6, 15, 10, 0, 0, tzinfo=UTC)

Date Arithmetic

from datetime import datetime

svc = Date(timezone="UTC", calendar="jalali")
dt = datetime(2025, 6, 15)

# Add days (works on Gregorian datetime)
dt2 = svc.add_days(dt, 10)        # datetime(2025, 6, 25)

# Add months (calendar-aware — respects month lengths and leap years)
dt3 = svc.add_months(dt, 3)       # +3 Jalali months from 1404/03/25

# Negative values work too
svc.add_days(dt, -5)
svc.add_months(dt, -2)

Month Names

svc = Date(timezone="UTC", calendar="jalali")
svc.get_month_name(1, locale="fa")  # "فروردین"
svc.get_month_name(1, locale="en")  # "Farvardin"

svc = Date(timezone="UTC", calendar="hijri")
svc.get_month_name(1, locale="ar")  # "محرم"
svc.get_month_name(1, locale="en")  # "Muharram"

svc = Date(timezone="UTC", calendar="gregorian")
svc.get_month_name(1, locale="en")  # "January"
svc.get_month_name(1, locale="fa")  # "ژانویه"

Day Boundaries

svc = Date(timezone="UTC", calendar="gregorian")
dt = datetime(2025, 6, 15, 14, 30, 0)

svc.start_of_day(dt)  # datetime(2025, 6, 15, 0, 0, 0)
svc.end_of_day(dt)    # datetime(2025, 6, 15, 23, 59, 59, 999999)

📚 API Reference

Date(timezone, calendar)

Method Returns Description
now() datetime Current time in configured timezone
now_utc() datetime Current UTC time
to_local(utc_dt) datetime Convert UTC → local timezone
to_utc(local_dt) datetime Convert local → UTC
get_date_components(dt) (year, month, day) Extract date parts in configured calendar
format_date(dt, format_str, include_time) str Format date with calendar-aware year/month/day
parse_date(date_str, format_str, time_component) datetime Parse date string → Gregorian datetime
get_month_name(month, locale) str Month name in fa, ar, or en
add_days(dt, days) datetime Add/subtract days
add_months(dt, months) datetime Add/subtract months (calendar-aware)
get_year_month(dt) (year, month) Get year+month only
start_of_day(dt) datetime Set time to 00:00:00
end_of_day(dt) datetime Set time to 23:59:59.999999

Calendar Constants

Constant Value
Date.CALENDAR_JALALI "jalali"
Date.CALENDAR_HIJRI "hijri"
Date.CALENDAR_GREGORIAN "gregorian"

🧪 Development

Setup

git clone https://github.com/kak-smko/waxt.git
cd waxt
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,test]"

Run tests

pytest           # with coverage
pytest -x -v     # stop on first failure, verbose

Lint & type check

black waxt tests
isort waxt tests
mypy waxt
flake8 waxt tests

📄 License

BSD-3-Clause. See LICENSE.

Project details


Download files

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

Source Distribution

waxt-0.1.3.tar.gz (18.7 kB view details)

Uploaded Source

Built Distribution

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

waxt-0.1.3-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

Details for the file waxt-0.1.3.tar.gz.

File metadata

  • Download URL: waxt-0.1.3.tar.gz
  • Upload date:
  • Size: 18.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for waxt-0.1.3.tar.gz
Algorithm Hash digest
SHA256 6f98b911cc82f357d350e559ef21412eced48914e8e7ad1574ab6a2ae1579f37
MD5 aa47e898442a7e8d4b46d127b5f6de9d
BLAKE2b-256 c39fb23600d0e0c5ffb9a4662022d7e5f2ae479b65e6ed5894c1b37410034c53

See more details on using hashes here.

File details

Details for the file waxt-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: waxt-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 9.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for waxt-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 eb313ae1da63d433c7021652132ab7418c9f6265f68a517168915c40b01eaf9b
MD5 3bd0ddfc158687a416068c9453104a2a
BLAKE2b-256 fdc727fbadf5a245a4332179739284e8f921de67851b53c51ec2e9d7e161a3d8

See more details on using hashes here.

Supported by

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