Persian Date

A single set of date utilities that works across the Jalali (Solar Hijri) and Gregorian calendars: format and parse dates, convert between calendars, do calendar-aware arithmetic, and validate reservation-style ranges — all built on date-fns and date-fns-jalali.

Last updated August 12, 2026

Overview

Installation

$ npx shadcn@latest add https://ui.persian-labs.ir/r/persian-date.json

Usage

Every function that reads or manipulates calendar fields (months, years, week boundaries) accepts an optional calendarType — the Jalali calendar is the default, since this library is Iran-first.

import { formatDate, addDays, today } from "@/lib/persian-date"
 
const checkIn = today()
const checkOut = addDays(checkIn, 3)
 
formatDate(checkIn, "yyyy/MM/dd") // "1404/06/01" (Jalali by default)
formatDate(checkOut, "d MMMM", { calendarType: "miladi" }) // Gregorian

Examples

Parsing

parseDate normalizes Persian/Arabic-Indic digits before parsing, and returns null instead of an invalid Date on failure.

Shamsi ↔ Miladi conversion

toParts/fromParts (and their toShamsi/toMiladi/fromShamsi/fromMiladi shorthands) round-trip a Date through calendar fields without losing precision.

Calendar-aware arithmetic

addMonths and addYears respect the active calendar's month lengths — adding a month to the end of Esfand behaves differently than adding one to the Gregorian February.

Start / end of week, month, year

startOfWeek/endOfWeek default to a Saturday-start week for shamsi (Sunday for miladi); startOfMonth/endOfMonth and startOfYear/endOfYear follow the same calendar-aware pattern.

Leap year & days in month

isLeapYear and daysInMonth resolve Esfand's 29 vs. 30 days for the Jalali calendar.

Comparisons

isToday, isPast, and isFuture classify a date relative to the current moment.

Date range

eachDayOfRange lists every day in an inclusive range; isWithinRange checks whether a given date falls inside it.

Range validation (reservation form)

validateRange is built for hospital/hotel-style booking forms: it checks ordering, minimum/maximum stay length, past dates, and specific blocked dates, returning a machine-readable reason you can map to a message.

RTL

formatDate already outputs Persian digits and Persian month/weekday names by default in the shamsi calendar, so the formatted string reads naturally inside right-to-left content with no extra direction handling.

API Reference

Formatting & Parsing

Conversion

Arithmetic

Comparisons & Ranges

Digits

DateOptions