import { format, type Locale } from 'date-fns' import { toJalaali } from 'jalaali-js' const JALALI_MONTHS_FA = [ 'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند', ] as const const PERSIAN_DIGITS = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'] as const /** Western digits → Persian (Extended Arabic-Indic) numerals, e.g. 1405 → ۱۴۰۵ */ export function toPersianDigits(input: string): string { return input.replace(/\d/g, (ch) => PERSIAN_DIGITS[Number(ch)] ?? ch) } function pad2(n: number): string { return n < 10 ? `0${n}` : `${n}` } function formatJalaliAbsolute(date: Date, pattern: string): string { const { jy, jm, jd } = toJalaali(date) const monthName = JALALI_MONTHS_FA[jm - 1] const h = pad2(date.getHours()) const min = pad2(date.getMinutes()) let s: string switch (pattern) { case 'd MMM yyyy': s = `${jd} ${monthName} ${jy}` break case 'd MMM yyyy · HH:mm': s = `${jd} ${monthName} ${jy} · ${h}:${min}` break case 'd MMM yyyy HH:mm': s = `${jd} ${monthName} ${jy} ${h}:${min}` break case 'd MMM · HH:mm': s = `${jd} ${monthName} · ${h}:${min}` break case 'MMM d, yyyy': s = `${monthName} ${jd}، ${jy}` break default: s = `${jd} ${monthName} ${jy}` } return toPersianDigits(s) } /** * Absolute calendar dates for Persian (`fa`) use the Solar Hijri (Jalali / هجری شمسی) calendar. * Times remain in the user's local timezone. For relative phrases, keep using `formatDistanceToNow` with `faIR`. */ export function formatAbsoluteDateLocalized( date: Date | string, language: string, pattern: string, locale: Locale ): string { const d = typeof date === 'string' ? new Date(date) : date if (language === 'fa') { return formatJalaliAbsolute(d, pattern) } return format(d, pattern, { locale }) }