A highly accurate and modern Persian (Jalali) calendar library written in Rust and Python.
Reason this release was yanked:
For new version
Project description
🌟 Jamshid (جمشید) 🌟
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.
Whether you are building astronomical utilities, high-frequency financial platforms using Pandas, or localized web services, Jamshid provides the mathematical precision, localized text processors, and cultural database required for modern Persian software engineering.
🚀 Key Architectural Pillars in v0.3.0
1. High-Performance Rust Core (jamshid._core)
- Compiled Mathematical Operations: Transformation algorithms (Jalali ↔ Gregorian), day-of-the-week determination, and leap-year verifications are processed entirely in natively compiled Rust binaries.
- Astronomical Accuracy: Supports the highly accurate Borkowski 2820-year cycle algorithm alongside Jean Meeus astronomical formulas for approximating the vernal equinox, guaranteeing mathematical continuity from year
-3000to3000.
2. Multi-Regional Cultural Engine (jamshid.core)
- Multi-Country Support: Out-of-the-box holiday calendars for Iran, Afghanistan, and Tajikistan (customizable via region flags).
- Categorized Events Database: Appropriate classification of events into
official,cultural,historical, andreligiouscategories, drawing from both solar and lunar calendars (with tabular fallback systems for distant years).
3. Native Data Science Toolchain (jamshid.pandas_ext)
- JalaliIndex: A custom Pandas index subclassing the standard Pandas Index layer, permitting native slice filtering, year/month/day properties, and flawless conversions.
- Custom Frequency Offsets: Native date offsets like
JalaliMonthEnd(JME) andJalaliYearEnd(JYE) to streamline Jalali-based financial and accounting resamples.
4. Advanced Persian Linguistic Diagnostics
- Iterative Digit Converters: Ultra-fast bidirectional converters supporting Persian, English, and Arabic digit scripts.
- Iterative Num-To-Words: A highly optimized, non-recursive, memory-safe algorithm converting numbers up to Quadrillions into Persian text representation.
- Text Normalizer: Clean Persian script layouts, fixing non-breaking spaces, semi-spaces (ZWNJs), and Arabic glyph issues.
⚙️ Installation
1. Standard Installation
pip install jamshid
2. Install with Scientific Extras (Pandas & Plotting)
pip install jamshid[pandas,matplotlib]
3. Compilation from Source
For custom optimizations or local contributions, compile directly using maturin:
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 exception triggers to ensure validation issues are caught early in the development lifecycle.
import jamshid
# Custom exceptions tailored for Clean Architecture
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}")
# Output: Validation failed: روز 30 برای ماه 12 در سال 1404 (غیرکبیسه) نامعتبر است.
# [Day 30 is invalid for month 12 in year 1404 (غیرکبیسه). Max allowed days: 29].
🚀 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. Seamless Gregorian Conversion
g_date = d.to_gregorian() # Returns standard datetime.date(2026, 7, 5)
jd = JalaliDate.from_date(g_date)
# 3. Simple Spacing Arithmetic
tomorrow = d + datetime.timedelta(days=1)
days_between = JalaliDate(1405, 4, 20) - d # Returns datetime.timedelta(days=6)
# 4. Humanized Interval Text
birth_date = JalaliDate(1375, 6, 15)
print(birth_date.humanize()) # Output: ۲۹ سال پیش (approx relative to 2026)
# 5. Fast Digit conversion & Formatting
print(d.strftime("امروز %A، %d %B سال %Y", locale='fa'))
# Output: امروز یکشنبه، ۱۴ تیر سال ۱۴۰۵
📖 Deep API Reference
1. JalaliDate & JalaliDateTime
Inheriting directly from datetime.date and datetime.datetime respectively, these classes act as drop-in replacements with overridden date properties.
from jamshid import JalaliDate, JalaliDateTime
# Static validation checking
is_ok = JalaliDate.is_valid(1404, 12, 30) # False
# RTL formatting support (Prevents crooked outputs in mixed LTR/RTL terminals)
d = JalaliDate(1405, 4, 14)
print(repr(d.strftime_rtl("%Y/%m/%d"))) # Includes \u200f right-to-left marks
# Exact Moon Phase Calculations
phase_name, illumination = d.get_moon_phase()
print(f"Moon Phase: {phase_name} | Illumination: {illumination:.2f}%")
# Output: Moon Phase: هلال کاهنده (Waning Crescent) | Illumination: 78.43%
2. Timezones & Tehran Historical DST (TehranTz)
The official Iranian Daylight Saving Time (DST) was legally abolished from 1402 خورشیدی (2023 CE). Jamshid's TehranTz implements correct historical DST offsets (24:00 of 1 Farvardin to 24:00 of 30 Shahrivar) up to 1401 and shuts off DST dynamically starting from 1402.
from jamshid import JalaliDateTime, TehranTz
tz = TehranTz()
# Before 1402 (DST Applied)
dt_1400 = JalaliDateTime(1400, 2, 15, 12, 0, tzinfo=tz)
print(dt_1400.tzname()) # IRDT (+04:30)
# After 1402 (DST Abolished)
dt_1405 = JalaliDateTime(1405, 2, 15, 12, 0, tzinfo=tz)
print(dt_1405.tzname()) # IRST (+03:30)
3. Highly Advanced Age Inquiries (SolarAge)
Computes astronomical age based on actual orbital movement, providing the result in days, months, years, exact fraction decimals, and formatted Persian text.
from jamshid import JalaliDate
birth = JalaliDate(1375, 6, 15)
ref_date = JalaliDate(1405, 4, 14)
age = birth.age_to(ref_date)
print(age.years, "Years,", age.months, "Months,", age.days, "Days")
# Output: 29 Years, 9 Months, 29 Days
print(f"Decimal Solar Age: {age.fraction:.4f}")
# Output: Decimal Solar Age: 29.8282
print(age.to_persian())
# Output: ۲۹ سال و ۹ ماه و ۲۹ روز
4. Continuous Date Interval Containers (JalaliPeriod)
from jamshid import JalaliDate, JalaliPeriod
start = JalaliDate(1405, 1, 1)
end = JalaliDate(1405, 1, 31)
period = JalaliPeriod(start, end)
print(JalaliDate(1405, 1, 15) in period) # True
print(period.days) # 30
5. Persian Linguistic Utilities
import jamshid.core as j_utils
# Bidirectional Converters
print(j_utils.to_persian_digits("Calling 09123456789")) # Calling ۰۹۱۲۳۴۵۶۷۸۹
print(j_utils.to_english_digits("تلفن: ۰۹۱۲۳۴۵۶۷۸۹")) # تلفن: 09123456789
# Non-Recursive Number-To-Words (Capable of handling huge integers)
print(j_utils.num_to_words(1405623910))
# Output: یک میلیارد و چهارصد و پنج میلیون و ششصد و بیست و سه هزار و نهصد و ده
# Standardize Mixed Spacing & Unicode Glyphs
dirty = "كتاب ها ميباشد"
print(j_utils.normalize_persian(dirty)) # کتابها میباشد
📈 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 an regular Jalali Index range
idx = jalali_date_range(start="1405/01/01", end="1405/03/31", freq="D")
print(idx)
# Output: JalaliIndex([1405/01/01, 1405/01/02, ..., 1405/03/31], dtype='object')
# Extract custom properties
print(idx.year) # pd.Index([1405, 1405, ...])
print(idx.month) # pd.Index([1, 1, 1, ...])
# 2. DataFrame Integration & Series Accessor
df = pd.DataFrame({
"g_date": pd.date_range("2026-03-21", "2026-06-21", freq="D")
})
# Convert Gregorian column to JalaliDate objects using accessor
df["j_date"] = df["g_date"].jalali.to_jalali()
# Map properties directly through Series Accessor
df["is_holiday"] = df["j_date"].jalali.is_holiday
df["daily_events"] = df["j_date"].jalali.events
# 3. Monthly Financial Resampling using Jalali Month End (JME) offsets
df_financial = pd.DataFrame({"revenue": [1000, 1500, 2000]}, index=idx[:3])
# Resample on custom monthly boundaries
monthly_resampled = df_financial.resample(JalaliMonthEnd()).sum()
🖼️ Graphical Visualization (plot_calendar)
For reporting, UI rendering, or data notebooks, plot localized monthly calendars in high definition with a single call:
from jamshid import JalaliDate
# Select any day inside the target month
d = JalaliDate(1405, 4, 14)
# Plots Farvardin 1405 grid with today highlighted
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
Outputs current Jalali date, Gregorian representation, localized week name, time, and active holidays.
2. Calculate Complex Date Differences
jamshid diff 1405/01/01 1406/05/12 --human
Prints: Difference: ۱ سال و ۵ ماه و ۱۱ روز بعد
3. Display Terminal Calendar Grids with Holiday Highlighting
jamshid calendar 1405 --highlight-holidays
Outputs the complete grid of 1405 with holidays colored in red.
4. Fetch Public Holidays & Export to Standards (JSON, CSV, iCal)
# Export official holidays to iCal format for Google Calendar/Outlook import
jamshid holidays 1405 --filter official --export ical > holidays_1405.ics
# Export to JSON
jamshid holidays 1405 --filter cultural --export json
📊 Feature Comparison Matrix
| Feature | Jamshid (v0.3.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 |
| Graphical Plotting | Matplotlib Integration | ❌ None | ❌ None | ❌ None |
| Linguistic Utilities | Words, Digits, Normalize | ❌ None | Moderate | ❌ None |
| Interactive CLI | Comprehensive JSON/ICS | ❌ None | ❌ None | ❌ None |
🧪 Technical Benchmarks & Performance
Due to calculations being processed natively on the Rust stack, conversions, indexing, and arithmetic steps in Jamshid achieve massive throughput improvements compared to traditional pure-Python solutions:
# Simple Benchmark comparison test (Converting 100,000 Dates)
import time
import jdatetime
import jamshid
# jdatetime baseline
t0 = time.time()
for _ in range(100000):
_ = jdatetime.date.fromgregorian(day=5, month=7, year=2026)
print(f"jdatetime: {time.time() - t0:.4f} seconds")
# Jamshid (Rust PyO3 engine)
t0 = time.time()
for _ in range(100000):
_ = jamshid.JalaliDate.from_gregorian(2026, 7, 5)
print(f"Jamshid: {time.time() - t0:.4f} 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.
🤝 Contributing
Contributions 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.
Make sure to run the unit tests prior to opening requests:
python -m unittest discover -s tests
👨💻 Author & Contact
Ali Kamrani
- GitHub: @MRThugh
- Email: kamrani.exe@gmail.com
📄 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jamshid-0.3.1.tar.gz.
File metadata
- Download URL: jamshid-0.3.1.tar.gz
- Upload date:
- Size: 32.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
759db4bf2787a344e07708c6cb7ec896a739a1ea03a4d549b2b5a6dfb7cb422b
|
|
| MD5 |
89af37f221a25dd261bb34193bfc46a9
|
|
| BLAKE2b-256 |
0f0c87a69c86aa2fb5c9b209654a8be8134511387b03e5967c77424d01cc17c2
|
File details
Details for the file jamshid-0.3.1-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: jamshid-0.3.1-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 616.6 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa9fcad0fe43f85c85eab879c0beec338af2d0739a523f8297fb446331e44d50
|
|
| MD5 |
85ee82121e35e6602db188ccd7ebb930
|
|
| BLAKE2b-256 |
99df4aa4a66cc7031053f5b5a883f3bbbf5276eb68a6b0978e79c531a63652d6
|