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.
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.
- 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
-3000to3000.
- 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()andprevious_holiday(). - Custom Holidays: Accept custom holiday set injection alongside native lunar/solar holiday mapping.
- Business Math: Perform work-day calculations via
next_business_day(),previous_business_day(), andbusiness_days_between(). - Custom Weekend Support: Specify weekends (e.g., Friday only for Iran, Saturday/Sunday for global standard, etc.) dynamically.
- Grid Generators: Retrieve structured monthly, weekly, or yearly nested date arrays using
monthly_calendar(),weekly_calendar(), andyear_calendar(). - Terminal Renderer: Output beautifully structured textual representations of any target month via
render_calendar().
- 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(), andto_json(). - Timezone Offset & Timestamp: Full microsecond-aware Unix timestamp mapping implemented inside native Rust primitives via
.timestamp(),fromtimestamp(), andutcfromtimestamp().
pip install jamshidpip install jamshid[pandas,matplotlib]git clone https://github.com/MRThugh/Jamshid.git
cd Jamshid
pip install maturin setuptools-rust
maturin develop --extras pandas,matplotlibRequires Python 3.9+ and Rust compiler (M.S.R.V 1.65+).
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}")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: ΩΎΩΨ¬βΨ΄ΩΨ¨ΩΨ Ϋ³Ϋ° Ψ§Ψ³ΩΩΨ― Ϋ±Ϋ΄Ϋ°Ϋ³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 marksTimestamp 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:30Manage 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}")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)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)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}'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()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")Jamshid comes equipped with a comprehensive terminal user interface featuring ANSI colors, export options, and localized reporting.
jamshid todayjamshid diff 1405/01/01 1406/05/12 --humanjamshid calendar 1405 --highlight-holidaysjamshid holidays 1405 --filter official --export ical > holidays_1405.ics| 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 |
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.
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.
cargo testpython -m unittest tests/test_jamshid.pyContributions to Jamshid are highly welcome!
- Fork the Project.
- Create your Feature Branch (
git checkout -b feature/AmazingFeature). - Commit your Changes (
git commit -m 'Add some AmazingFeature'). - Push to the Branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
Ali Kamrani
- GitHub: @MRThugh
- Email: kamrani.exe@gmail.com
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.