Skip to main content

Jalali (Shamsi/Persian) date and datetime with Persian digits and character utilities

Project description

PersianTools

PyPI test workflow codecov PyPI - Python Version PyPI - License

PersianTools provides Jalali (Shamsi) dates and datetimes that work just like Python's datetime — plus handy tools for Persian text: digit conversion between Persian, Arabic, and English, character normalization, and numbers to Persian words.

If you know datetime.date and datetime.datetime, you already know JalaliDate and JalaliDateTime. They support the same operations: comparison, arithmetic with timedelta, timezones, strftime/strptime and formatting, hashing, and pickling.

Installation

pip install persiantools

Requires Python 3.9 or newer. No dependencies, except tzdata on Windows for timezone data.

Quick start

>>> from persiantools.jdatetime import JalaliDate, JalaliDateTime
>>> import datetime

>>> JalaliDate.today()
JalaliDate(1405, 4, 12, Jomeh)

>>> JalaliDate(datetime.date(1988, 5, 4))       # Gregorian → Jalali
JalaliDate(1367, 2, 14, Chaharshanbeh)

>>> JalaliDate(1367, 2, 14).to_gregorian()      # Jalali → Gregorian
datetime.date(1988, 5, 4)

>>> JalaliDateTime.now().strftime("%A %d %B %Y, %H:%M")
'Jomeh 12 Tir 1405, 14:30'

Dates

Create a JalaliDate from Jalali values, a Gregorian date, an ISO string, or a timestamp:

>>> from persiantools.jdatetime import JalaliDate
>>> import datetime

>>> JalaliDate(1367, 2, 14)
JalaliDate(1367, 2, 14, Chaharshanbeh)

>>> JalaliDate.to_jalali(2013, 9, 16)
JalaliDate(1392, 6, 25, Doshanbeh)

>>> JalaliDate.fromisoformat("1404-01-01")
JalaliDate(1404, 1, 1, Jomeh)

>>> JalaliDate.fromtimestamp(578707200)
JalaliDate(1367, 2, 14, Chaharshanbeh)

>>> JalaliDate(1400, 1, 1).replace(month=2, day=10)
JalaliDate(1400, 2, 10, Jomeh)

The week starts on Shanbeh (Saturday). weekday() counts from 0 (Shanbeh) to 6 (Jomeh), and isoweekday() from 1 to 7:

>>> d = JalaliDate(1367, 2, 14)  # a Chaharshanbeh (Wednesday)
>>> d.weekday()
4
>>> d.isoweekday()
5
>>> d.isocalendar()
IsoCalendarDate(year=1367, week=7, weekday=5)
>>> d.isoformat()
'1367-02-14'

Datetimes

JalaliDateTime adds time and timezone support on top of JalaliDate:

>>> from persiantools.jdatetime import JalaliDateTime
>>> from zoneinfo import ZoneInfo
>>> import datetime

>>> JalaliDateTime.now(ZoneInfo("Asia/Tehran"))
JalaliDateTime(1405, 4, 12, 14, 30, 7, 907909, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))

>>> JalaliDateTime(datetime.datetime(1988, 5, 4, 14, 30, 15))
JalaliDateTime(1367, 2, 14, 14, 30, 15)

>>> JalaliDateTime(1367, 2, 14, 14, 30, 15).to_gregorian()
datetime.datetime(1988, 5, 4, 14, 30, 15)

>>> JalaliDateTime(1367, 2, 14, 14, 30, tzinfo=datetime.timezone.utc).isoformat(timespec="minutes")
'1367-02-14T14:30+00:00'

Formatting and parsing

Both classes support strftime and strptime with the familiar directives, in English or Persian:

>>> from persiantools.jdatetime import JalaliDate, JalaliDateTime

>>> JalaliDate(1367, 2, 14).strftime("%A %d %B %Y")
'Chaharshanbeh 14 Ordibehesht 1367'

>>> JalaliDateTime(1367, 2, 14, 14, 30).strftime("%c", locale="fa")
'چهارشنبه ۱۴ اردیبهشت ۱۳۶۷ ۱۴:۳۰:۰۰'

>>> JalaliDate.strptime("1367-02-14", "%Y-%m-%d")
JalaliDate(1367, 2, 14, Chaharshanbeh)

>>> JalaliDateTime.strptime("1367/02/14 14:30", "%Y/%m/%d %H:%M")
JalaliDateTime(1367, 2, 14, 14, 30)

A date created with locale="fa" renders itself with Persian digits and names everywhere:

>>> JalaliDate(1367, 2, 14, locale="fa").isoformat()
'۱۳۶۷-۰۲-۱۴'

Comparison and arithmetic

Jalali objects compare and do arithmetic with each other, with timedelta, and directly with their Gregorian counterparts:

>>> from persiantools.jdatetime import JalaliDate, JalaliDateTime
>>> import datetime

>>> JalaliDate(1367, 2, 14) == datetime.date(1988, 5, 4)
True

>>> JalaliDate(1395, 2, 14) + datetime.timedelta(days=38)
JalaliDate(1395, 3, 21, Jomeh)

>>> JalaliDateTime(1395, 12, 30) - JalaliDateTime(1395, 1, 1)
datetime.timedelta(days=365)

>>> JalaliDate(1399, 12, 30) > JalaliDate(1399, 12, 29)   # leap-year Esfand 30
True

They are also hashable (usable as dict keys) and picklable, like the standard library types.

Digits

Convert digits between English, Persian, and Arabic:

>>> from persiantools import digits

>>> digits.en_to_fa("0987654321")
'۰۹۸۷۶۵۴۳۲۱'

>>> digits.ar_to_fa("٠٩٨٧٦٥٤٣٢١")
'۰۹۸۷۶۵۴۳۲۱'

>>> digits.fa_to_en("۰۹۸۷۶۵۴۳۲۱")
'0987654321'

>>> digits.fa_to_ar("۰۹۸۷۶۵۴۳۲۱")
'٠٩٨٧٦٥٤٣٢١'

And spell numbers out in Persian — integers, floats, and negatives:

>>> digits.to_word(9512026)
'نه میلیون و پانصد و دوازده هزار و بیست و شش'

>>> digits.to_word(15.007)
'پانزده و هفت هزارم'

>>> digits.to_word(-123.45)
'منفی یکصد و بیست و سه و چهل و پنج صدم'

Characters

Arabic and Persian share letters that look alike but have different Unicode code points (ك vs ک, ي vs ی) — a common source of failed string matching and broken search. Normalize them in either direction:

>>> from persiantools import characters

>>> characters.ar_to_fa("كيك")
'کیک'

>>> characters.fa_to_ar("کیک")
'كيك'

AI Agent Skill

Need your AI assistant to convert Persian (Shamsi/Jalali) dates accurately? Install the convert-persian-dates — it teaches the agent to convert between Shamsi and Gregorian (Miladi) without guessing calendar math.

npx skills add majiidd/persiantools --skill convert-persian-dates

Add --global to enable it across all projects. OpenAI Codex and Cursor also pick it up automatically when this repo is open. After install, ask naturally:

امروز چندمه؟
What is today's date in Shamsi?
Convert 1405-01-01 Shamsi to Gregorian.

The skill needs pip install persiantools in the environment where the agent runs Python.

Support this project

If persiantools saves you time, you can support its development with a donation:

Coin Address
Bitcoin (BTC) bc1qg5rp7ymznc98wmhltzvpwl2dvfuvjr33m4hy77
Ethereum (ETH) 0xC7D6bf306E456632764D0aD111C8dBBb43a3B9ad
Tron (TRX) TDd63bVWZDBHmwVNFgJ6T2WdWmk9z7PBLg
Stellar (XLM) GDSFPPLY34QSAOTOP4DQDXAI2YDRNRIADZHTN3HCGMQXRLIGPYOEH7L5
USDT (BSC) 0xC7D6bf306E456632764D0aD111C8dBBb43a3B9ad

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

persiantools-6.1.0.tar.gz (48.5 kB view details)

Uploaded Source

Built Distribution

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

persiantools-6.1.0-py3-none-any.whl (27.3 kB view details)

Uploaded Python 3

File details

Details for the file persiantools-6.1.0.tar.gz.

File metadata

  • Download URL: persiantools-6.1.0.tar.gz
  • Upload date:
  • Size: 48.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for persiantools-6.1.0.tar.gz
Algorithm Hash digest
SHA256 881bd9a80ca7851249f7cbab885cc625e010ca5c9ce91e77f197741a1aa438fc
MD5 b39caf06b352997c23d3565a5120a733
BLAKE2b-256 6672db141bf2f7bff1a98181baeba3b9953cc851010d3a2485e2ce8f80b6582e

See more details on using hashes here.

Provenance

The following attestation bundles were made for persiantools-6.1.0.tar.gz:

Publisher: ci.yml on majiidd/persiantools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file persiantools-6.1.0-py3-none-any.whl.

File metadata

  • Download URL: persiantools-6.1.0-py3-none-any.whl
  • Upload date:
  • Size: 27.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for persiantools-6.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5fbcce719abf512b43e63955636e083deeb5d272b6aa1dca2c80c283cca4677c
MD5 c1063ac368fe1c6a8a6ef89f650d9b59
BLAKE2b-256 6a896770ff912e3c067d7f87b5e97594d355ef092b36137fb913f2729597f133

See more details on using hashes here.

Provenance

The following attestation bundles were made for persiantools-6.1.0-py3-none-any.whl:

Publisher: ci.yml on majiidd/persiantools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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