JalaliDate
A Kotlin Multiplatform library for Jalali (Persian) date handling, conversion, formatting and parsing.
Install / Use
/learn @amirroid/JalaliDateREADME
JalaliDate
📆 JalaliDate is a Kotlin Multiplatform library for handling Persian (Jalali) dates, with support for formatting, parsing, and calendar conversions.
Features
- Supports Kotlin Multiplatform (
android,jvm,ios,js,wasmJs) - Accurate conversion between Jalali and Gregorian calendars
- Two built-in calendar conversion algorithms
- Powerful and flexible formatting and parsing system
- Inspired by
SimpleDateFormatbut tailored for Jalali date logic
📦 Installation
// build.gradle.kts
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.github.amirroid:jalalidate:x.y.z")
}
}
}
🔁 Conversion Algorithms
This library includes two built-in algorithms for converting between Jalali and Gregorian calendars:
| Algorithm Name | Description |
|--------------------|--------------------------------------------------------------------------------------------|
| BirashkAlgorithm | Based on the astronomical method by Dr. Ahmad Birashk — accurate and reliable |
| KhayyamAlgorithm | Based on Khayyam–Jalali calendar rules — lightweight and approximate (used as the default) |
You can change the default algorithm globally:
JalaliDateGlobalConfiguration.convertAlgorithm = BirashkAlgorithm
Or specify per-instance:
val date =
JalaliDateTime(jalaliYear = 1402, jalaliMonth = 5, jalaliDay = 9, algorithm = BirashkAlgorithm)
🛠️ Formatting
Format any JalaliDateTime instance using pattern strings:
val date = JalaliDateTime(1402, 5, 9, 14, 3, 7)
val formatted = date.format {
byUnicodePattern("yyyy/MM/dd HH:mm:ss")
}
println(formatted) // 1402/05/09 14:03:07
You can also use manual formatting:
val formatted = date.format {
year()
chars("/")
month()
chars("/")
dayTwoDigit()
}
⏱️ Parsing
Parse back a string into a JalaliDateTime:
val formatter = JalaliDateTime.Format { byUnicodePattern("yyyy-MM-dd HH:mm:ss") }
// Or
val formatter = JalaliDateTimeFormatter().byUnicodePattern("yyyy MMM dd")
val date = formatter.parse("1402/05/09")
println(date.jalaliYear) // 1402
Any missing field (like time) will default to current system time.
🧾 Pattern Reference
| Symbol | Description | Example (value) |
|--------|---------------------|---------------------|
| yyyy | Full year | 1402 |
| yy | Last two digits | 02 |
| MMMM | Full month name | مرداد / Mordad |
| MMM | Short month name | مرد / Mor |
| MM | 2-digit month | 05 |
| M | 1 or 2-digit month | 5 |
| EEEE | Full weekday name | شنبه / Saturday |
| EEE | Short weekday name | ش / Sat |
| E | Weekday number | 1 |
| dd | 2-digit day | 09 |
| d | 1 or 2-digit day | 9 |
| HH | Hour (24h, 2-digit) | 14 |
| H | Hour (24h) | 14 |
| hh | Hour (12h, 2-digit) | 09 |
| h | Hour (12h) | 9 |
| mm | Minutes (2-digit) | 03 |
| m | Minutes | 3 |
| ss | Seconds (2-digit) | 07 |
| s | Seconds | 7 |
You can also combine static characters using chars(...):
val formatter = JalaliDateTimeFormatter()
.year()
.chars(" year - ")
.dayOneDigit()
.chars(" - ")
.monthFullName()
Output:
1402 year - مرداد - 9
Note:
You can change thelocalein two ways:
- Globally (the default locale is Persian):
JalaliDateGlobalConfiguration.formatterLocale = Locale.ENGLISH
- Locally when formatting a date:
date.format { applyLocale(Locale.ENGLISH) byUnicodePattern("MMMM yyyy") }
📚 Examples
<details> <summary>Format with month name</summary>val date = JalaliDateTime(1402, 5, 9)
val formatted = date.format {
byUnicodePattern("yyyy dd MMMM")
}
// Output: 1402 مرداد 09
</details>
<details> <summary>Parse with short month name</summary>
val input = "1402 مرد 09"
val formatter = JalaliDateTimeFormatter().byUnicodePattern("yyyy dd MMM")
val date = formatter.parse(input)
println(date.jalaliMonth) // 5
</details>
<details> <summary>Using plus and minus operators with DateTimeInterval</summary>
val date = JalaliDateTime(1402, 5, 10, 12, 30, 15)
date + 5.days - 2.months // JalaliDateTime with Jalali date 1402/03/15 and time 12:30:15
date - 1.years + 10.days // JalaliDateTime with Jalali date 1401/05/20 and time 12:30:15
</details>
<details> <summary>Using copyGregorian and copyJalali</summary>
JalaliDateTime(1402, 5, 10, 14, 45, 30).copyGregorian(year = 2023, month = 8, day = 1)
// Returns JalaliDateTime corresponding to Gregorian 2023/08/01
JalaliDateTime(1402, 5, 10, 14, 45, 30).copyJalali(year = 1403, month = 6, day = 20)
// JalaliDateTime(year=1403, month=6, day=20, hour=14, minute=45, second=30)
</details>
<details> <summary>Main properties of JalaliDateTime</summary>
val date = JalaliDateTime(1402, 7, 15, 10, 20, 30)
date.gregorianYear // 2023
date.gregorianMonth // 10
date.gregorianDay // 7
date.jalaliYear // 1402
date.jalaliMonth // 7
date.jalaliDay // 15
date.algorithm::class.simpleName // "KhayyamAlgorithm" or "BirashkAlgorithm"
date.hour // 10
date.minute // 20
date.second // 30
date.weekOfYear // 29
date.isJalaliLeapYear // false
date.isGregorianLeapYear // false
date.monthLength // 30
date.monthName.english // "Mehr"
date.monthName.persian // "مهر"
date.dayOfWeek() // DayOfWeek.SATURDAY
date.dayOfWeek(weekStartDay = DayOfWeek.SUNDAY) // DayOfWeek.SATURDAY
date.dayOfWeekNumber() // 1 (if week starts on Saturday)
</details>
📜 License
MIT
For any suggestions or issues, feel free to open an Issue or contribute via PR.
