Skip to content

Repository files navigation

PersianDateMultiplatform

English | فارسی

License: MITKotlinAndroidiOSJVMWASM

PersianDateMultiplatform is a Kotlin Multiplatform library for working with the Persian (Jalali/Shamsi) calendar across Android, iOS, Desktop (JVM), and Web (Kotlin/Wasm). The library provides utilities for conversion, formatting, and manipulation of Persian dates, with support for leap years, month and weekday names, and integration into Compose Multiplatform projects.

kotlin_multiplatform_persian_date_time

Features

  • Persian Date Conversion: Convert between Gregorian and Persian date representations.
  • Date Formatting: Format Persian date/time objects to strings (date, time, date-time).
  • Leap Year Calculations: Accurately determine leap years in the Jalali calendar.
  • Month/Weekday Names: Get Persian month and weekday names.
  • Multiplatform Support: Use in Android, iOS, Desktop (JVM), and Web (Kotlin/Wasm).
  • DSL for Formatting: Easy-to-use builder for custom date/time formats.
  • Integration Samples: Compose Multiplatform project structure for real-world apps.

Getting Started

  • Kotlin Multiplatform Projects (Common Main)

Version

The library is published to Maven Central.

The library is compatible with the Kotlin Standard Library not lower than 2.1.20.

If you target Android devices running below API 26, you need to use Android Gradle plugin 4.0 or newer and enable core library desugaring.

⚠️ Note: This library depends on the latest version of Kotlinx datetime, so make sure to always use the most recent release.

Add the dependency to your commonMain source set in your build.gradle.kts:

kotlin {
sourceSets {
val commonMain by getting {
dependencies {
// Add kotlinx-datetime first
implementation("org.jetbrains.kotlinx:kotlinx-datetime:<version>")
// Then your PersianDateTime library
implementation("io.github.faridsolgi:persianDateTime:<version>")
}
}
}
}
  • Android Native Projects

For Android-native projects, use the dedicated Android artifact:

dependencies {
// Add kotlinx-datetime first
implementation("org.jetbrains.kotlinx:kotlinx-datetime:<version>")
// Then the PersianDateTime Android artifact
implementation("io.github.faridsolgi:persianDateTime:<version>")
}

You can also get the library from Maven Central: PersianDateTime on Maven Central or clone and include the library module directly.

Support for Kotlinx Serialization

If you also add the kotlinx-serialization library to your project, PersianDateTime supports @Serializable.

Usage

Basic Persian Date Representation

importcom.faridsolgi.persiandatemultiplatform.domain.PersianDateTime// Create a date onlyval persianDate =PersianDateTime(year =1402, month =7, day =1)
// Create a date with timeval persianDateTime =PersianDateTime(
year =1402,
month =7,
day =1,
hour =14,
minute =30,
second =45
)

Parsing Persian Dates from String

/** * Parse PersianDateTime from a string. * * Supported formats: * - "yyyy/MM/dd" * - "yyyy-MM-dd" * - "yyyy/MM/dd HH:mm" * - "yyyy-MM-dd HH:mm" * - "yyyy/MM/dd HH:mm:ss" * - "yyyy-MM-dd HH:mm:ss" * - "yyyy-MM-ddTHH:mm:ss" * * @param input The date string to parse. * @return A valid [PersianDateTime] instance. * @throws IllegalArgumentException if the input format is invalid.*/// Parse date onlyval parsedDate =PersianDateTime.parse("1402/07/01")
// Parse date with timeval parsedDateTime =PersianDateTime.parse("1402-07-01 14:30:45")

Parsing Persian Dates from Timestamp

importcom.faridsolgi.persiandatemultiplatform.domain.PersianDateTimeimportkotlinx.datetime.TimeZone// Parse from epoch milliseconds (e.g., 1759323028800 = 01 Oct 2025)val timestamp =1759323028800Lval persianDateTime =PersianDateTime.parse(timestamp, TimeZone.currentSystemDefault())
println(persianDateTime.year) // 1404println(persianDateTime.month) // 7println(persianDateTime.day) // 9println(persianDateTime.hour) // 16

Additional Examples

// Accessing date componentsprintln(parsedDate.year) // 1402println(parsedDate.month) // 7println(parsedDate.day) // 1// Formatting a Persian date to stringval formatted = parsedDateTime.toString()
println(formatted) // Example: "1402-07-01 14:30:45"

Extension Functions Usage

Conversion Extensions

Convert LocalDate or LocalDateTime to a Persian date:

importcom.faridsolgi.persiandatemultiplatform.converter.toPersianDateTimeimportkotlinx.datetime.LocalDateimportkotlinx.datetime.LocalDateTimeval gregorianDate =LocalDate(2023, 9, 24)
val persianDate = gregorianDate.toPersianDateTime() // PersianDateTime instanceval gregorianDateTime =LocalDateTime(2023, 9, 24, 15, 20, 0)
val persianDateTime = gregorianDateTime.toPersianDateTime()

Convert Persian date back to Gregorian:

importcom.faridsolgi.persiandatemultiplatform.converter.toGregorianval gregorian = persianDate.toLocalDate()
val gregorianWithTime = persianDate.toLocalDateTime()

Current Date/Time Utilities

You can get the current Persian date for a specific time zone:

importkotlinx.datetime.Clockimportkotlinx.datetime.TimeZoneimportcom.faridsolgi.persiandatemultiplatform.converter.nowInTehranimportcom.faridsolgi.persiandatemultiplatform.converter.nowPersianDate// Get the current date in Tehran's timezoneval nowInTehran =Clock.System.nowInTehran
println("Current Persian date in Tehran: ${nowInTehran.toDateString()}")
// Get the current date for a different time zone, e.g., "Europe/Paris"val nowInParis =Clock.System.nowPersianDate(TimeZone.of("Europe/Paris"))
println("Current Persian date in Paris: ${nowInParis.toDateString()}")

Arithmetic Extensions

You can perform date arithmetic on PersianDateTime using plus and minus with DateTimeUnit or DatePeriod.

importcom.faridsolgi.persiandatemultiplatform.converter.plusimportcom.faridsolgi.persiandatemultiplatform.converter.minusimportkotlinx.datetime.DateTimeUnitimportkotlinx.datetime.DatePeriodval nextWeek = persianDate.plus(7, DateTimeUnit.DAY) // add 7 daysval yesterday = persianDate.minus(1, DateTimeUnit.DAY) // subtract 1 dayval nextMonth = persianDate.plus(DatePeriod(months =1)) // add one monthval lastYear = persianDate.minus(DatePeriod(years =1)) // subtract one year

Comparison Extensions

importcom.faridsolgi.persiandatemultiplatform.converter.isBeforeimportcom.faridsolgi.persiandatemultiplatform.converter.isAfterimportcom.faridsolgi.persiandatemultiplatform.converter.isBetweenif (persianDate.isBefore(nextWeek)) { /* ... */ }
if (persianDate.isAfter(yesterday)) { /* ... */ }
if (persianDate.isBetween(yesterday, nextWeek)) { /* ... */ }

Month, Day, Leap Extensions

importcom.faridsolgi.persiandatemultiplatform.converter.isLeapimportcom.faridsolgi.persiandatemultiplatform.converter.monthLengthimportcom.faridsolgi.persiandatemultiplatform.converter.monthNameimportcom.faridsolgi.persiandatemultiplatform.converter.dayOfWeekNameprintln(persianDate.isLeap()) // true/falseprintln(persianDate.monthLength()) // 31, 30, or 29println(persianDate.persianMonth().displayName) // "مهر" (Mehr)println(persianDate.persianDayOfWeek().displayName) // "سه‌شنبه" (Tuesday)

Formatted String Date Extensions

importcom.faridsolgi.persiandatemultiplatform.converter.toDateStringimportcom.faridsolgi.persiandatemultiplatform.converter.toTimeStringimportcom.faridsolgi.persiandatemultiplatform.converter.toDateTimeStringprintln(persianDate.toDateString()) // "1402/07/02"println(persianDate.toTimeString()) // "00:00:00"println(persianDate.toDateTimeString()) // "1402/07/02 00:00:00"

Custom Formatting DSL

The formatting DSL supports full date/time patterns:

importcom.faridsolgi.persiandatemultiplatform.converter.formatval custom = persianDate.format {
day()
char('/')
month()
char('/')
year()
char('')
hour12()
char(':')
minute()
amPm()
}
println(custom) // "02/07/1402 03:45ب.‌ظ"

Formatting DSL Reference

FunctionDescriptionExample Output
year(pad)Year with optional padding (default 4)1402
month(pad)Month number with optional padding (2)07
day(pad)Day of month with optional padding (2)02
hour24(pad)Hour in 24-hour format (00–23)14
hour12(pad)Hour in 12-hour format (01–12)02
minute(pad)Minute with optional padding (2)45
second(pad)Second with optional padding (2)09
amPm()AM/PM markerب.‌ظ,ق.‌ظ
char(c)Literal character/
monthName()Persian month nameمهر
dayOfWeekName()Persian weekday nameسه‌شنبه

Validation and Exceptions

All PersianDateTime instances are automatically validated. If you try to create a date or time that is invalid, the library will throw an IllegalArgumentException. Users do not need to call any validator—it happens internally.

Rules Checked

  • Month: Must be between 1 and 12.
  • Day: Must be valid for the given month and year (including leap years for month 12).
  • Time: Hours must be 0–23, minutes 0–59, seconds 0–59.

Example Usage

importcom.faridsolgi.persiandatemultiplatform.domain.PersianDateTime// ✅ Valid dateval validDate =PersianDateTime(1402, 7, 15)
// ❌ Invalid monthtry {
PersianDateTime(1402, 13, 5)
} catch (e:IllegalArgumentException) {
println(e.message) // "ماه نامعتبر: 13"
}
// ❌ Invalid daytry {
PersianDateTime(1402, 7, 32)
} catch (e:IllegalArgumentException) {
println(e.message) // "روز نامعتبر: 32 برای ماه 7"
}
// ❌ Invalid timetry {
PersianDateTime(1402, 7, 15, 25, 0, 0)
} catch (e:IllegalArgumentException) {
println(e.message) // "ساعت نامعتبر: 25"
}
// ✅ Parsing a date stringval parsedDate =PersianDateTime.parse("1402/07/01 14:30:45")
// ❌ Parsing an invalid stringtry {
PersianDateTime.parse("1402/13/01")
} catch (e:IllegalArgumentException) {
println(e.message) // "ماه نامعتبر: 13"
}

⚠️Tip: Always catch IllegalArgumentException when accepting user input or parsing strings to safely handle invalid dates.

License

MIT License

Copyright (c) 2024 Farid Solgi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

References

About

A Kotlin Multiplatform library for working with Persian (Jalali) dates across Android, iOS, Wasm,and desktop .

Topics

Resources

Stars

12 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages