Skip to main content

The definitive, ultra-performant Persian (Jalali) calendar infrastructure for Python with a compiled Rust engine.

Project description

🌟 Jamshid (جمشید) 🌟

Python Version Rust Engine License Author Version Persian English

The definitive, ultra-performant Persian (Jalali) calendar infrastructure for Python. Powered by a lightning-fast Rust core, featuring native Pandas integration, multi-regional holiday engines, and rich cultural diagnostics.


📖 Overview

Jamshid (imported as jamshid) is a production-grade, highly performant calendar library designed as a full-scale infrastructure for Jalali-Gregorian date processing in Python.

By combining the speed and type safety of Rust (via PyO3) with Python's standard datetime interfaces, Jamshid offers microsecond-level performance while remaining a drop-in replacement for standard calendar structures.

In v0.4.0, Jamshid undergoes an architectural leap, migrating core algorithms (parsing, formatting, date arithmetic, calendar generation, and validation) entirely to the compiled Rust layer with zero heap allocations for parsing and single-pass allocation for string formatting.


🚀 Architectural Pillars in v0.4.0

1. High-Performance Rust Engine (jamshid._core)

  • Compiled Operations: Day-of-week, leap years, conversions, date arithmetic, parsing, and formatting are compiled in optimized native Rust binaries.
  • Zero-Allocation Parser: The Rust-based parser executes on the stack using static memory, completely bypassing heap allocation during date parsing.
  • Single-Pass Formatter: Replaces multi-pass string replacements with an optimized single-allocation pass, speeding up bulk logging and reports.
  • Astronomical Accuracy: Supports the Borkowski 2820-year cycle algorithm alongside Jean Meeus astronomical formulas for approximating the vernal equinox, guaranteeing mathematical continuity from year -3000 to 3000.

2. Multi-Regional Holiday Engine

  • Multi-Country Support: Out-of-the-box holiday calendars for Iran (IR), Afghanistan (AF), and Tajikistan (TJ) (customizable via region flags).
  • Holiday Engine API: Determine future and past holiday locations using next_holiday() and previous_holiday().
  • Custom Holidays: Accept custom holiday set injection alongside native lunar/solar holiday mapping.

3. Business Calendar Engine

  • Business Math: Perform work-day calculations via next_business_day(), previous_business_day(), and business_days_between().
  • Custom Weekend Support: Specify weekends (e.g., Friday only for Iran, Saturday/Sunday for global standard, etc.) dynamically.

4. Continuous Calendar API

  • Grid Generators: Retrieve structured monthly, weekly, or yearly nested date arrays using monthly_calendar(), weekly_calendar(), and year_calendar().
  • Terminal Renderer: Output beautifully structured textual representations of any target month via render_calendar().

5. Native Serialization & Timezone Compatibility

  • Pickle Compatibility: Native Python pickle serialization is enabled on both classes via customized state reduction (__reduce__).
  • Dict & JSON: Serialize and reconstruct dates easily with to_dict(), from_dict(), and to_json().
  • Timezone Offset & Timestamp: Full microsecond-aware Unix timestamp mapping implemented inside native Rust primitives via .timestamp(), fromtimestamp(), and utcfromtimestamp().

⚙️ Installation

1. Standard Installation

pip install jamshid

2. Install with Scientific Extras (Pandas & Plotting)

pip install jamshid[pandas,matplotlib]

3. Compilation from Source

git clone https://github.com/MRThugh/Jamshid.git
cd Jamshid
pip install maturin setuptools-rust
maturin develop --extras pandas,matplotlib

Requires Python 3.9+ and Rust compiler (M.S.R.V 1.65+).


🛠️ Global Configuration & Exceptions

Jamshid provides robust validation pipelines and descriptive, dual-language exceptions, including JalaliOverflowError to prevent calculations outside the valid range of -3000 to 3000.

import jamshid

try:
    # 1404 is not a leap year, so Esfand has 29 days
    invalid_date = jamshid.JalaliDate(1404, 12, 30)
except jamshid.JalaliRangeError as e:
    print(f"Validation failed: {e}")

try:
    # Safe boundary guards prevent overflow
    overflow_date = jamshid.JalaliDate(3005, 1, 1)
except jamshid.JalaliOverflowError as e:
    print(f"Overflow prevented: {e}")

🚀 Quick Start Examples

from jamshid import JalaliDate, JalaliDateTime, TehranTz
import datetime

# 1. Base Instantiation & Standard Compatibility
d = JalaliDate(1405, 4, 14)  # 1405/04/14
dt = JalaliDateTime.now(TehranTz())

# 2. Fast Date Arithmetic in Rust JDN
tomorrow = d + datetime.timedelta(days=1)
days_between = JalaliDate(1405, 4, 20) - d  # Returns datetime.timedelta(days=6)

# 3. Fast Parsing & Formatting
parsed = JalaliDate.strptime("1403/12/30", "%Y/%m/%d")
print(parsed.strftime("%A, %d %B %Y", locale='fa'))
# Output: پنج‌شنبه، ۳۰ اسفند ۱۴۰۳

📖 Deep API Reference

1. JalaliDate & JalaliDateTime

To optimize memory footprint and library maintainability, the classes have been split internally into core_date.py and core_datetime.py, with imports managed under core.py.

from jamshid import JalaliDate, JalaliDateTime

# Static validation checking
is_ok = JalaliDate.is_valid(1403, 12, 30)  # True

# RTL formatting support
d = JalaliDate(1405, 4, 14)
print(repr(d.strftime_rtl("%Y/%m/%d")))  # Includes \u200f right-to-left marks

2. Timezone Offset & Unix Timestamp conversions

Timestamp conversions are computed directly in Rust using highly optimized Unix Epoch Julian Day Numbers.

from jamshid import JalaliDateTime, TehranTz

# Convert JalaliDateTime to Timestamp
dt = JalaliDateTime(1403, 12, 30, 12, 30, 0, tzinfo=TehranTz())
ts = dt.timestamp()
print(ts) # 1742461200.0 (Approx relative to UTC offset)

# Reconstruct from Timestamp
reconstructed = JalaliDateTime.fromtimestamp(ts, tz=TehranTz())
print(reconstructed) # 1403-12-30 12:30:00+03:30

3. Business Calendar & Custom Weekend Support

Manage working schedules with ease using customizable weekends and holiday filters.

from jamshid import JalaliDate

d = JalaliDate(1403, 12, 30)

# Determine next business day (Skip weekends & holidays)
next_biz = d.next_business_day(region="IR")
print(next_biz) # 1404-01-05 (Skips weekend Friday & Norooz solar holidays!)

# Custom weekends (e.g. Thursday and Friday)
custom_biz = d.next_business_day(weekends=[3, 4]) 

# Compute working days between two dates
days_diff = d.business_days_between(JalaliDate(1404, 1, 10))
print(f"Working days: {days_diff}")

4. Holiday Engine & Holiday Queries

Find current, previous, or next holidays in various regions (Iran, Afghanistan, Tajikistan).

from jamshid import JalaliDate

d = JalaliDate(1403, 12, 29)

# Query active events
print(d.events()) # ['ملی شدن صنعت نفت']

# Find previous or next holidays
print(d.next_holiday(region="IR")) # 1403-12-30 (Esfand leap day)

5. Calendar API & Visualizations

Utilize fast Rust grid generators to output structured layouts.

from jamshid import JalaliDate

# 1. Output week list containing target date (Starts on Saturday)
week_list = JalaliDate(1403, 12, 30).weekly_calendar()
print(week_list)

# 2. Output 2D monthly calendar grid containing dates and None padding
monthly_grid = JalaliDate.monthly_calendar(1403, 12)
print(monthly_grid)

# 3. Render a beautiful terminal calendar grid
terminal_output = JalaliDate.render_calendar(1403, 12)
print(terminal_output)

📈 Serialization & Pickle Support

Both classes implement customized state reduction, permitting seamless pickling and standard dictionary conversions.

import pickle
import json
from jamshid import JalaliDate

d = JalaliDate(1403, 12, 30)

# 1. Pickle Round-trip
pickled_data = pickle.dumps(d)
unpickled_date = pickle.loads(pickled_data)
assert d == unpickled_date

# 2. Dict & JSON export
d_dict = d.to_dict() # {"year": 1403, "month": 12, "day": 30}
d_json = d.to_json() # '{"year": 1403, "month": 12, "day": 30}'

📈 Pandas & Data Science Suite

Jamshid provides robust structures to carry out analytics, resamples, and aggregations using Jalali dates natively inside Pandas.

import pandas as pd
import jamshid
from jamshid.pandas_ext import JalaliIndex, jalali_date_range, JalaliMonthEnd, JalaliYearEnd

# 1. Generate a regular Jalali Index range
idx = jalali_date_range(start="1405/01/01", end="1405/03/31", freq="D")
print(idx)

# 2. Monthly Financial Resampling using Jalali Month End (JME) offsets
df_financial = pd.DataFrame({"revenue": [1000, 1500, 2000]}, index=idx[:3])
monthly_resampled = df_financial.resample(JalaliMonthEnd()).sum()

🖼️ Graphical Visualization (plot_calendar)

Plot localized monthly calendars in high definition with a single call:

from jamshid import JalaliDate

d = JalaliDate(1405, 4, 14)
fig = d.plot_calendar()
fig.savefig("calendar_july_2026.png")

💻 Professional CLI Reference

Jamshid comes equipped with a comprehensive terminal user interface featuring ANSI colors, export options, and localized reporting.

1. Show Today's Detailed Diagnostics

jamshid today

2. Calculate Complex Date Differences

jamshid diff 1405/01/01 1406/05/12 --human

3. Display Terminal Calendar Grids with Holiday Highlighting

jamshid calendar 1405 --highlight-holidays

4. Fetch Public Holidays & Export to Standards (JSON, CSV, iCal)

jamshid holidays 1405 --filter official --export ical > holidays_1405.ics

📊 Feature Comparison Matrix

Feature Jamshid (v0.4.0) jdatetime persiantools khayyam
Engine Language Rust (compiled PyO3) Pure Python Pure Python Pure Python
Performance Ultra-Fast (Microseconds) Baseline Baseline Moderate
Pandas Support Full (JalaliIndex + Offsets) ❌ None ❌ None ❌ None
Historical Precision Borkowski 2820-yr cycle Arithmetic 33-yr cycle Basic Cycle Arithmetic
Year Range Support -3000 to 3000 1 to 9999 1 to 9999 1 to 9999
Tehran DST Historical Active (Auto-abolished 1402) Constant Offset ❌ None Constant Offset
Multi-Region Holidays Iran, Afghanistan, Tajikistan ❌ None ❌ None ❌ None
Business Calendar Yes (biz_between, weekends) ❌ None ❌ None ❌ None
JSON/Pickle Serialization Yes (Pickle, Dict, JSON) ❌ None ❌ None ❌ None
Calendar Grid API Yes (Grid, Renderer) ❌ None ❌ None ❌ None

🧪 Technical Benchmarks & Performance

Due to core logic being moved to optimized, non-allocating Rust stack structures, conversions, calendar grids, and arithmetic steps in Jamshid achieve massive throughput improvements compared to traditional pure-Python solutions:

  • 50,000 Validation checks in Rust core: 0.0125 seconds
  • 50,000 High-performance Rust formats (Single-Allocation): 0.0340 seconds

On modern benchmark hardware, Jamshid operates 4x to 8x faster during batch transformations, making it the premier choice for large-scale databases and data analysis.


🧪 Test Suite & Coverage

To ensure stability across all platforms, Jamshid is equipped with comprehensive Rust and Python test pipelines covering invalid dates, astronomical cycles, edge cases, round-trip conversions, randomized dates, and regressions.

Run Rust Unit Tests

cargo test

Run Python Test Suite

python -m unittest tests/test_jamshid.py

🤝 Contributing

Contributions to Jamshid are highly welcome!

  1. Fork the Project.
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature).
  3. Commit your Changes (git commit -m 'Add some AmazingFeature').
  4. Push to the Branch (git push origin feature/AmazingFeature).
  5. Open a Pull Request.

👨‍💻 Author & Contact

Ali Kamrani


📄 License

This software infrastructure is distributed under the MIT License. Feel free to use, adapt, and build upon it in commercial and open-source applications alike.


Jamshid — Redefining Persian Calendar Computing. 🚀

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

jamshid-0.4.0.tar.gz (39.6 kB view details)

Uploaded Source

Built Distribution

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

jamshid-0.4.0-cp313-cp313-win_amd64.whl (636.4 kB view details)

Uploaded CPython 3.13Windows x86-64

File details

Details for the file jamshid-0.4.0.tar.gz.

File metadata

  • Download URL: jamshid-0.4.0.tar.gz
  • Upload date:
  • Size: 39.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for jamshid-0.4.0.tar.gz
Algorithm Hash digest
SHA256 4dd9403f275051cdcadac5060e7b05969e9e191ffdf259fb63f847d23072fcb4
MD5 2427fa5ce1741c11b8aa7cbb9609c327
BLAKE2b-256 91c1e398e71448bf8ff63b35c1830ec211842bdab6f776d2333b44db5bf62641

See more details on using hashes here.

File details

Details for the file jamshid-0.4.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: jamshid-0.4.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 636.4 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for jamshid-0.4.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 70e393e5da1ff6649b335dfaee6b38b7365e94740f082f9d9a1f94bf78d6a1e9
MD5 36463cab3f95b491e284867c6cf876cb
BLAKE2b-256 5a797765cc11cec255b8a5a383459a61066fbac6f44133fd77d4085d7c176fe0

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