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("کیک")
'كيك'

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.0.2.tar.gz (47.8 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.0.2-py3-none-any.whl (26.9 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for persiantools-6.0.2.tar.gz
Algorithm Hash digest
SHA256 5d043329456f36fbd34c676c82d24a40a9e17fdfce49b0d8c151b2cc0cc81b76
MD5 c4d8b25f1a01f7dd7fc3c7e7c5f4314f
BLAKE2b-256 218aea00afcb6527f97dc10529e5ee0b118015af339b1d65a0eb5f875287ed5a

See more details on using hashes here.

Provenance

The following attestation bundles were made for persiantools-6.0.2.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.0.2-py3-none-any.whl.

File metadata

  • Download URL: persiantools-6.0.2-py3-none-any.whl
  • Upload date:
  • Size: 26.9 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.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d89367bb9cacb8f480e87dafdceab50e72a1074845798b48bf360eaf8e979080
MD5 07c84a54a42da1196603c03c725946b2
BLAKE2b-256 1c5414aabad3a5fc184f1eacdb3935a22afc7d6b4c016d2c53a994209af20d59

See more details on using hashes here.

Provenance

The following attestation bundles were made for persiantools-6.0.2-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