|
|
|
@@ -0,0 +1,342 @@
|
|
|
|
|
import jalaliPlugin from '@zoomit/dayjs-jalali-plugin';
|
|
|
|
|
import dayjs, { Dayjs } from 'dayjs';
|
|
|
|
|
import 'dayjs/locale/fa';
|
|
|
|
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
|
|
|
|
|
|
|
|
// Extend dayjs with plugins
|
|
|
|
|
dayjs.extend(jalaliPlugin);
|
|
|
|
|
dayjs.extend(relativeTime);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Common date format patterns for Jalali calendar
|
|
|
|
|
*/
|
|
|
|
|
export const JALALI_DATE_FORMATS = {
|
|
|
|
|
/** Full date with weekday: "پنجشنبه، ۱۳ شهریور ۱۳۹۷" */
|
|
|
|
|
FULL_WITH_WEEKDAY: 'dddd، DD MMMM YYYY',
|
|
|
|
|
/** Full date: "۱۳ شهریور ۱۳۹۷" */
|
|
|
|
|
FULL: 'DD MMMM YYYY',
|
|
|
|
|
/** Short date with month name: "۱۳ شهریور ۹۷" */
|
|
|
|
|
SHORT: 'DD MMMM YY',
|
|
|
|
|
/** Numeric date: "۱۳۹۷/۰۶/۱۳" */
|
|
|
|
|
NUMERIC: 'YYYY/MM/DD',
|
|
|
|
|
/** Numeric date with time: "۱۳۹۷/۰۶/۱۳ ۱۶:۳۰" */
|
|
|
|
|
NUMERIC_WITH_TIME: 'YYYY/MM/DD HH:mm',
|
|
|
|
|
/** Numeric date with full time: "۱۳۹۷/۰۶/۱۳ ۱۶:۳۰:۱۵" */
|
|
|
|
|
NUMERIC_WITH_FULL_TIME: 'YYYY/MM/DD HH:mm:ss',
|
|
|
|
|
/** Time only: "۱۶:۳۰" */
|
|
|
|
|
TIME: 'HH:mm',
|
|
|
|
|
/** Time with seconds: "۱۶:۳۰:۱۵" */
|
|
|
|
|
TIME_WITH_SECONDS: 'HH:mm:ss',
|
|
|
|
|
/** Month and year: "شهریور ۱۳۹۷" */
|
|
|
|
|
MONTH_YEAR: 'MMMM YYYY',
|
|
|
|
|
/** Day and month: "۱۳ شهریور" */
|
|
|
|
|
DAY_MONTH: 'DD MMMM',
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Common date format patterns for Gregorian calendar
|
|
|
|
|
*/
|
|
|
|
|
export const GREGORIAN_DATE_FORMATS = {
|
|
|
|
|
/** Full date with weekday: "Thursday, September 04 2018" */
|
|
|
|
|
FULL_WITH_WEEKDAY: 'dddd, MMMM DD YYYY',
|
|
|
|
|
/** Full date: "September 04 2018" */
|
|
|
|
|
FULL: 'MMMM DD YYYY',
|
|
|
|
|
/** Short date: "Sep 04 18" */
|
|
|
|
|
SHORT: 'MMM DD YY',
|
|
|
|
|
/** Numeric date: "2018-09-04" */
|
|
|
|
|
NUMERIC: 'YYYY-MM-DD',
|
|
|
|
|
/** Numeric date with time: "2018-09-04 16:30" */
|
|
|
|
|
NUMERIC_WITH_TIME: 'YYYY-MM-DD HH:mm',
|
|
|
|
|
/** Numeric date with full time: "2018-09-04 16:30:15" */
|
|
|
|
|
NUMERIC_WITH_FULL_TIME: 'YYYY-MM-DD HH:mm:ss',
|
|
|
|
|
/** Time only: "16:30" */
|
|
|
|
|
TIME: 'HH:mm',
|
|
|
|
|
/** Time with seconds: "16:30:15" */
|
|
|
|
|
TIME_WITH_SECONDS: 'HH:mm:ss',
|
|
|
|
|
/** Month and year: "September 2018" */
|
|
|
|
|
MONTH_YEAR: 'MMMM YYYY',
|
|
|
|
|
/** Day and month: "September 04" */
|
|
|
|
|
DAY_MONTH: 'MMMM DD',
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format a date as Jalali (Persian) calendar in Farsi locale
|
|
|
|
|
*
|
|
|
|
|
* @param date - Date to format (string, Date, Dayjs, or timestamp)
|
|
|
|
|
* @param format - Format pattern (default: 'YYYY/MM/DD')
|
|
|
|
|
* @returns Formatted date string in Jalali calendar
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* formatJalali('2018-09-04') // '1397/06/13'
|
|
|
|
|
* formatJalali('2018-09-04', JALALI_DATE_FORMATS.FULL) // '۱۳ شهریور ۱۳۹۷'
|
|
|
|
|
* formatJalali(new Date(), JALALI_DATE_FORMATS.FULL_WITH_WEEKDAY) // 'پنجشنبه، ۱۳ شهریور ۱۳۹۷'
|
|
|
|
|
*/
|
|
|
|
|
export function formatJalali(
|
|
|
|
|
date: string | Date | Dayjs | number,
|
|
|
|
|
format: string = JALALI_DATE_FORMATS.NUMERIC,
|
|
|
|
|
): string {
|
|
|
|
|
return dayjs(date).calendar('jalali').locale('fa').format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format a date as Gregorian calendar in English locale
|
|
|
|
|
*
|
|
|
|
|
* @param date - Date to format (string, Date, Dayjs, or timestamp)
|
|
|
|
|
* @param format - Format pattern (default: 'YYYY-MM-DD')
|
|
|
|
|
* @returns Formatted date string in Gregorian calendar
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* formatGregorian('1397/06/13', GREGORIAN_DATE_FORMATS.FULL) // 'September 04 2018'
|
|
|
|
|
* formatGregorian(new Date(), GREGORIAN_DATE_FORMATS.NUMERIC_WITH_TIME) // '2018-09-04 16:30'
|
|
|
|
|
*/
|
|
|
|
|
export function formatGregorian(
|
|
|
|
|
date: string | Date | Dayjs | number,
|
|
|
|
|
format: string = GREGORIAN_DATE_FORMATS.NUMERIC,
|
|
|
|
|
): string {
|
|
|
|
|
return dayjs(date).calendar('gregory').locale('en').format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse a Jalali date string and return a Dayjs instance
|
|
|
|
|
*
|
|
|
|
|
* @param jalaliDate - Jalali date string (e.g., '1398-10-17')
|
|
|
|
|
* @param format - Optional format pattern for parsing
|
|
|
|
|
* @returns Dayjs instance
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* parseJalali('1398-10-17') // Dayjs instance
|
|
|
|
|
* parseJalali('1398/10/17') // Dayjs instance
|
|
|
|
|
*/
|
|
|
|
|
export function parseJalali(jalaliDate: string, format?: string): Dayjs {
|
|
|
|
|
return dayjs(jalaliDate, { jalali: true, ...(format && { format }) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a Gregorian date to Jalali format
|
|
|
|
|
*
|
|
|
|
|
* @param gregorianDate - Gregorian date string, Date object, or Dayjs instance
|
|
|
|
|
* @param format - Optional format pattern (default: 'YYYY/MM/DD')
|
|
|
|
|
* @returns Formatted Jalali date string
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* gregorianToJalali('2018-09-04') // '1397/06/13'
|
|
|
|
|
* gregorianToJalali('2018-09-04', JALALI_DATE_FORMATS.FULL) // '۱۳ شهریور ۱۳۹۷'
|
|
|
|
|
*/
|
|
|
|
|
export function gregorianToJalali(
|
|
|
|
|
gregorianDate: string | Date | Dayjs,
|
|
|
|
|
format: string = JALALI_DATE_FORMATS.NUMERIC,
|
|
|
|
|
): string {
|
|
|
|
|
return dayjs(gregorianDate).calendar('jalali').locale('fa').format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a Jalali date to Gregorian format
|
|
|
|
|
*
|
|
|
|
|
* @param jalaliDate - Jalali date string (e.g., '1398-10-17')
|
|
|
|
|
* @param format - Optional format pattern (default: 'YYYY-MM-DD')
|
|
|
|
|
* @returns Formatted Gregorian date string
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* jalaliToGregorian('1398-10-17') // '2020-01-07'
|
|
|
|
|
* jalaliToGregorian('1397/06/13', GREGORIAN_DATE_FORMATS.FULL) // 'September 04 2018'
|
|
|
|
|
*/
|
|
|
|
|
export function jalaliToGregorian(
|
|
|
|
|
jalaliDate: string,
|
|
|
|
|
format: string = GREGORIAN_DATE_FORMATS.NUMERIC,
|
|
|
|
|
): string {
|
|
|
|
|
return parseJalali(jalaliDate).calendar('gregory').locale('en').format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get current date and time in Jalali format
|
|
|
|
|
*
|
|
|
|
|
* @param format - Optional format pattern (default: 'YYYY/MM/DD HH:mm')
|
|
|
|
|
* @returns Current date and time in Jalali format
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* nowJalali() // '1403/12/05 14:30'
|
|
|
|
|
* nowJalali(JALALI_DATE_FORMATS.FULL_WITH_WEEKDAY) // 'یکشنبه، ۵ اسفند ۱۴۰۳'
|
|
|
|
|
*/
|
|
|
|
|
export function nowJalali(format: string = JALALI_DATE_FORMATS.NUMERIC_WITH_TIME): string {
|
|
|
|
|
return dayjs().calendar('jalali').locale('fa').format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get current date and time in Gregorian format
|
|
|
|
|
*
|
|
|
|
|
* @param format - Optional format pattern (default: 'YYYY-MM-DD HH:mm')
|
|
|
|
|
* @returns Current date and time in Gregorian format
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* nowGregorian() // '2026-02-24 14:30'
|
|
|
|
|
* nowGregorian(GREGORIAN_DATE_FORMATS.FULL_WITH_WEEKDAY) // 'Sunday, February 24 2026'
|
|
|
|
|
*/
|
|
|
|
|
export function nowGregorian(format: string = GREGORIAN_DATE_FORMATS.NUMERIC_WITH_TIME): string {
|
|
|
|
|
return dayjs().calendar('gregory').locale('en').format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format a time duration as a relative time string in Farsi
|
|
|
|
|
*
|
|
|
|
|
* @param date - Date to compare against current time
|
|
|
|
|
* @returns Relative time string in Farsi
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* relativeTimeJalali(dayjs().subtract(2, 'day')) // '۲ روز پیش'
|
|
|
|
|
*/
|
|
|
|
|
export function relativeTimeJalali(date: string | Date | Dayjs | number): string {
|
|
|
|
|
return dayjs(date).locale('fa').fromNow();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if a date string is a valid Jalali date
|
|
|
|
|
*
|
|
|
|
|
* @param jalaliDate - Jalali date string
|
|
|
|
|
* @returns true if valid, false otherwise
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* isValidJalaliDate('1398-10-17') // true
|
|
|
|
|
* isValidJalaliDate('1398-13-17') // false
|
|
|
|
|
*/
|
|
|
|
|
export function isValidJalaliDate(jalaliDate: string): boolean {
|
|
|
|
|
return parseJalali(jalaliDate).isValid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the start of day for a date in Jalali calendar
|
|
|
|
|
*
|
|
|
|
|
* @param date - Date to get start of day for
|
|
|
|
|
* @returns Dayjs instance at start of day
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* startOfDayJalali('1398-10-17') // Dayjs instance at 00:00:00
|
|
|
|
|
*/
|
|
|
|
|
export function startOfDayJalali(date: string | Date | Dayjs | number): Dayjs {
|
|
|
|
|
return dayjs(date).calendar('jalali').startOf('day');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the end of day for a date in Jalali calendar
|
|
|
|
|
*
|
|
|
|
|
* @param date - Date to get end of day for
|
|
|
|
|
* @returns Dayjs instance at end of day
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* endOfDayJalali('1398-10-17') // Dayjs instance at 23:59:59
|
|
|
|
|
*/
|
|
|
|
|
export function endOfDayJalali(date: string | Date | Dayjs | number): Dayjs {
|
|
|
|
|
return dayjs(date).calendar('jalali').endOf('day');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format a date with custom calendar and locale
|
|
|
|
|
*
|
|
|
|
|
* @param date - Date to format
|
|
|
|
|
* @param calendar - Calendar type ('jalali' | 'gregory')
|
|
|
|
|
* @param locale - Locale ('fa' | 'en')
|
|
|
|
|
* @param format - Format pattern
|
|
|
|
|
* @returns Formatted date string
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* formatDate('2018-09-04', 'jalali', 'fa', 'DD MMMM YYYY') // '۱۳ شهریور ۱۳۹۷'
|
|
|
|
|
* formatDate('2018-09-04', 'gregory', 'en', 'MMMM DD YYYY') // 'September 04 2018'
|
|
|
|
|
*/
|
|
|
|
|
export function formatDate(
|
|
|
|
|
date: string | Date | Dayjs | number,
|
|
|
|
|
calendar: 'jalali' | 'gregory',
|
|
|
|
|
locale: 'fa' | 'en',
|
|
|
|
|
format: string,
|
|
|
|
|
): string {
|
|
|
|
|
return dayjs(date).calendar(calendar).locale(locale).format(format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get Jalali month name in Farsi
|
|
|
|
|
*
|
|
|
|
|
* @param monthNumber - Month number (1-12)
|
|
|
|
|
* @returns Month name in Farsi
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* getJalaliMonthName(1) // 'فروردین'
|
|
|
|
|
* getJalaliMonthName(6) // 'شهریور'
|
|
|
|
|
*/
|
|
|
|
|
export function getJalaliMonthName(monthNumber: number): string {
|
|
|
|
|
const monthNames = [
|
|
|
|
|
'فروردین',
|
|
|
|
|
'اردیبهشت',
|
|
|
|
|
'خرداد',
|
|
|
|
|
'تیر',
|
|
|
|
|
'مرداد',
|
|
|
|
|
'شهریور',
|
|
|
|
|
'مهر',
|
|
|
|
|
'آبان',
|
|
|
|
|
'آذر',
|
|
|
|
|
'دی',
|
|
|
|
|
'بهمن',
|
|
|
|
|
'اسفند',
|
|
|
|
|
];
|
|
|
|
|
return monthNames[monthNumber - 1] || '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get Jalali weekday name in Farsi
|
|
|
|
|
*
|
|
|
|
|
* @param dayNumber - Day number (0-6, where 0 is Saturday)
|
|
|
|
|
* @returns Weekday name in Farsi
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* getJalaliWeekdayName(0) // 'شنبه'
|
|
|
|
|
* getJalaliWeekdayName(4) // 'چهارشنبه'
|
|
|
|
|
*/
|
|
|
|
|
export function getJalaliWeekdayName(dayNumber: number): string {
|
|
|
|
|
const weekdayNames = ['شنبه', 'یکشنبه', 'دوشنبه', 'سهشنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'];
|
|
|
|
|
return weekdayNames[dayNumber] || '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function jalaliDiff(
|
|
|
|
|
date1: string | number | Date | Dayjs,
|
|
|
|
|
date2: string | number | Date | Dayjs,
|
|
|
|
|
unit: dayjs.OpUnitType = 'day',
|
|
|
|
|
): number {
|
|
|
|
|
return toJalali(date1).diff(toJalali(date2), unit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isJalaliBefore(
|
|
|
|
|
date1: string | number | Date | Dayjs,
|
|
|
|
|
date2: string | number | Date | Dayjs,
|
|
|
|
|
): boolean {
|
|
|
|
|
return toJalali(date1).isBefore(toJalali(date2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isJalaliAfter(
|
|
|
|
|
date1: string | number | Date | Dayjs,
|
|
|
|
|
date2: string | number | Date | Dayjs,
|
|
|
|
|
): boolean {
|
|
|
|
|
return toJalali(date1).isAfter(toJalali(date2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function toJalali(date: string | number | Date | Dayjs, format = 'YYYY/MM/DD'): Dayjs {
|
|
|
|
|
return dayjs(date).calendar('jalali');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
formatJalali,
|
|
|
|
|
formatGregorian,
|
|
|
|
|
parseJalali,
|
|
|
|
|
gregorianToJalali,
|
|
|
|
|
jalaliToGregorian,
|
|
|
|
|
nowJalali,
|
|
|
|
|
nowGregorian,
|
|
|
|
|
relativeTimeJalali,
|
|
|
|
|
isValidJalaliDate,
|
|
|
|
|
startOfDayJalali,
|
|
|
|
|
endOfDayJalali,
|
|
|
|
|
formatDate,
|
|
|
|
|
getJalaliMonthName,
|
|
|
|
|
getJalaliWeekdayName,
|
|
|
|
|
jalaliDiff,
|
|
|
|
|
isJalaliBefore,
|
|
|
|
|
isJalaliAfter,
|
|
|
|
|
JALALI_DATE_FORMATS,
|
|
|
|
|
GREGORIAN_DATE_FORMATS,
|
|
|
|
|
};
|