UNPKG

persidate

Version:

persidate is a lightweight package for converting and managing Shamsi (Jalali) and Gregorian dates in JavaScript/TypeScript.

438 lines (437 loc) 16.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.jalaliWeekdayNames = exports.jalaliMonthNames = exports.isLeapYearJalali = exports.isBeforeDate = exports.addDaysToDate = exports.getTimeAgo = exports.getJalaliTimeStamp = exports.getDaysFromNow = exports.getTimeFromDate = exports.getToday = exports.formatToLocalizedDate = exports.formatToJalaliDatePadded = exports.formatToGregorianDateTime = exports.formatToGregorianDate = exports.convertToJalaliDate = exports.convertToGregorianDateString = exports.convertToGregorianDate = exports.convertToISODateTime = exports.convertToStandardDateTime = void 0; const parse_arabic_1 = require("./parse-arabic"); // Extending Date prototype const DT = Date.prototype; /** * Locale setting for Persian (Iran) format. * @constant {string} locale - Locale code for Persian (Iran). */ const locale = "fa-IR"; /** * Converts date to ISO format in local time. * @param {Date} date - The input date. * @returns {string} Local ISO date string. */ const convertToStandardDateTime = (date) => { var _a, _b; const tzoffset = (date === null || date === void 0 ? void 0 : date.getTimezoneOffset()) * 60000; // Offset in milliseconds const localISOTime = (_b = (_a = new Date(date.getTime() - tzoffset)) === null || _a === void 0 ? void 0 : _a.toISOString()) === null || _b === void 0 ? void 0 : _b.slice(0, -1); return localISOTime; }; exports.convertToStandardDateTime = convertToStandardDateTime; /** * Converts date to ISO format with a timezone offset adjustment. * @param {Date | string | number} date - The input date. * @returns {string} Adjusted ISO date string. */ const convertToISODateTime = (date) => { const formattedDate = typeof date === "string" || typeof date === "number" ? new Date(date) : date; const tzoffset = (formattedDate.getTimezoneOffset() - 60) * 60000; const localISOTime = new Date(formattedDate.getTime() - tzoffset) .toISOString() .slice(0, -1); return localISOTime; }; exports.convertToISODateTime = convertToISODateTime; /** * Converts Jalali date string to Gregorian Date object. * @param {string} jalaliDate - Jalali date string in the format YYYY/MM/DD or YYYY-MM-DD. * @returns {Date} Gregorian Date object. */ const convertToGregorianDate = (jalaliDate) => { const [year, month, day] = jalaliDate.split(/[/-]/).map(Number); const [gYear, gMonth, gDay] = toGregorian(year, month, day); return new Date(gYear, gMonth - 1, gDay); // JS months are 0-indexed }; exports.convertToGregorianDate = convertToGregorianDate; /** * Converts Jalali date string to Gregorian date string in the format YYYY/MM/DD. * @param {string} jalaliDate - Jalali date string in the format YYYY/MM/DD or YYYY-MM-DD. * @returns {string} Gregorian date string in the format YYYY/MM/DD. */ const convertToGregorianDateString = (jalaliDate) => { const [year, month, day] = jalaliDate.split(/[/-]/).map(Number); const [gYear, gMonth, gDay] = toGregorian(year, month, day); return `${gYear}/${gMonth.toString().padStart(2, "0")}/${gDay .toString() .padStart(2, "0")}`; }; exports.convertToGregorianDateString = convertToGregorianDateString; /** * Converts a Gregorian date to a Jalali date in a specified format. * * @param {Date | string | number} date - The Gregorian date input. * @param { "day" | "weekday" | "month" | "dayMonth" | "dayMonthYear" | "weekdayDayMonth" | "weekdayDayMonthYear" } [format] - * Optional format for the output: * - If omitted, returns "YYYY-MM-DD" * - "day": Returns day (e.g. "26") * - "weekday": Returns weekday (e.g. "جمعه") * - "month": Returns month (e.g. "مهر") * - "dayMonth": Returns day and month (e.g. "26 مهر") * - "dayMonthYear": Returns full date (e.g. "26 مهر 1403") * - "weekdayDayMonth": Returns weekday + day + month (e.g. "جمعه 26 مهر") * - "weekdayDayMonthYear": Full format (e.g. "جمعه 26 مهر 1403") * * @returns {string} Jalali date in desired format or "YYYY-MM-DD" by default. * * @example * convertToJalaliDate("2024-10-18"); // → "1403-07-27" * convertToJalaliDate("2024-10-18", "dayMonthYear"); // → "27 مهر 1403" * convertToJalaliDate(new Date(), "weekday"); // → "دوشنبه" */ const convertToJalaliDate = (date, format) => { const parsedDate = typeof date === "number" || typeof date === "string" ? new Date(date) : date; const parts = (0, parse_arabic_1.parseArabic)(parsedDate.toLocaleDateString("fa-IR")).split(/[-\/]/); const [year, month, day] = parts; const weekday = jalaliWeekdayNamesGregorianFormat[parsedDate.getDay()]; const persianMonth = exports.jalaliMonthNames[month - 1]; // Default fallback: YYYY-MM-DD if (!format) { return `${year}-${month}-${day}`; } switch (format) { case "day": return `${day}`; case "weekday": return `${weekday}`; case "month": return `${persianMonth}`; case "year": return `${year}`; case "dayMonth": return `${day} ${persianMonth}`; case "dayMonthYear": return `${day} ${persianMonth} ${year}`; case "weekdayDayMonth": return `${weekday} ${day} ${persianMonth}`; case "weekdayDayMonthYear": return `${weekday} ${day} ${persianMonth} ${year}`; default: return `${year}-${month}-${day}`; } }; exports.convertToJalaliDate = convertToJalaliDate; /** * Converts a given timestamp or Date object to a Gregorian date string in the format YYYY-MM-DD. * @param {number | Date} date - Unix timestamp or Date object. * @returns {string} Gregorian date string in the format YYYY-MM-DD. */ const formatToGregorianDate = (date) => { const formattedDate = typeof date === "number" ? new Date(date) : date; const year = formattedDate.getFullYear(); const month = formattedDate.getMonth() + 1; const day = formattedDate.getDate(); return `${year}-${month.toString()}-${day.toString()}`; }; exports.formatToGregorianDate = formatToGregorianDate; /** * Converts Jalali date and time to Gregorian date string with time. * @param {number | Date} date - Unix timestamp or Date object. * @returns {string} Gregorian date string with time in the format YYYY-MM-DDTHH:mm. */ const formatToGregorianDateTime = (date, time) => { const formattedDate = (0, exports.formatToGregorianDate)(date); return `${formattedDate}T${time}`; }; exports.formatToGregorianDateTime = formatToGregorianDateTime; /** * Converts a Gregorian date to a formatted Jalali date with padded month and day. * @param {Date | string | number} date - Gregorian date object. * @returns {string} Jalali date in the format YYYY-MM-DD with zero-padded month and day. */ const formatToJalaliDatePadded = (date) => { var _a, _b; const formattedDate = typeof date === "string" || typeof date === "number" ? new Date(date) : date; const parts = (0, parse_arabic_1.parseArabic)(formattedDate.toLocaleDateString(locale)).split(/[/-]/); let month = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.length) < 2 ? `0${parts[1]}` : parts[1]; let day = ((_b = parts[2]) === null || _b === void 0 ? void 0 : _b.length) < 2 ? `0${parts[2]}` : parts[2]; return `${parts[0]}-${month}-${day}`; }; exports.formatToJalaliDatePadded = formatToJalaliDatePadded; /** * Formats a date string according to the specified format. * @param {string | Date} date - The input date string or Date object. * @param {SupportedDateFormats} format - The desired output format. * @returns {string | null} Formatted date string or null if invalid. */ const formatToLocalizedDate = (date, format) => { var _a, _b, _c, _d, _e, _f; if (!date) return null; if (date instanceof Date) { date = date.toISOString(); } if (format === "jYYYY-jM-jD") { return (0, exports.convertToJalaliDate)(date); } if (format === "jYYYY-jMM-jDD") { return (0, exports.formatToJalaliDatePadded)(date); } if (format === "jMMMM") { return (0, exports.convertToJalaliDate)(date, "month"); } if (format === "jD") { return (0, exports.convertToJalaliDate)(date, "day"); } if (format === "jDDD") { return (0, exports.convertToJalaliDate)(date, "dayMonth"); } if (format === "jDDD-jMM-jYY") { return (0, exports.convertToJalaliDate)(date, "dayMonthYear"); } if (typeof date === "string") { if (date.includes("/")) date = date.replace(/\//g, "-"); } const spited = (_a = (0, exports.convertToISODateTime)(date)) === null || _a === void 0 ? void 0 : _a.split("T"); const clockSpited = (_b = spited[1]) === null || _b === void 0 ? void 0 : _b.split(":"); if (format === "YYYY-MM-DD") return spited[0]; if (format === "YYYY/MM/DD") return (_c = spited[0]) === null || _c === void 0 ? void 0 : _c.replace(/-/g, "/"); if (format === "YYYY/MM/DD HH:mm") return (((_d = spited[0]) === null || _d === void 0 ? void 0 : _d.replace(/-/g, "/")) + " " + clockSpited[0] + ":" + clockSpited[1]); if (format === "HH:mm") return clockSpited[0] + ":" + clockSpited[1]; if (format === "YYYY/MM/DDTHH:mm:ss") return (((_e = spited[0]) === null || _e === void 0 ? void 0 : _e.replace(/-/g, "/")) + "T" + clockSpited[0] + ":" + clockSpited[1] + ":" + ((_f = clockSpited[2]) === null || _f === void 0 ? void 0 : _f.split(".")[0])); return null; }; exports.formatToLocalizedDate = formatToLocalizedDate; /** * Gets today's date in ISO format (YYYY-MM-DD). * @returns {string} Today's date in "YYYY-MM-DD" format. */ const getToday = () => { const date = new Date().toISOString(); const splitDate = date.split("T")[0]; return splitDate; }; exports.getToday = getToday; /** * Extracts time from a date string or Date object in the format HH:mm. * @param {string | number | Date} date - Date as string (YYYY-MM-DDTHH:mm:ss) or Date object. * @returns {string} Time in the format HH:mm. */ const getTimeFromDate = (date = new Date()) => { const dateObj = typeof date === "string" || typeof date === "number" ? new Date(date) : date; if (!isNaN(dateObj.getTime())) { // Check if date is valid const hours = String(dateObj.getHours()).padStart(2, "0"); const minutes = String(dateObj.getMinutes()).padStart(2, "0"); const seconds = String(dateObj.getSeconds()).padStart(2, "0"); return `${hours}:${minutes}:${seconds}`; } return ""; }; exports.getTimeFromDate = getTimeFromDate; /** * Calculates the number of days between now and a given date. * @param {string | Date | number} inputDate - A Date object or a string parsable by `new Date() or timeStamp`. * @returns {number} Number of days until the date (can be negative if in the past). */ const getDaysFromNow = (inputDate) => { const targetDate = typeof inputDate === "string" || typeof inputDate === "number" ? new Date(inputDate) : inputDate; if (isNaN(targetDate.getTime())) { throw new Error("Invalid date format. Use ISO format or Date object."); } const now = new Date(); const msDiff = targetDate.getTime() - now.getTime(); const daysDiff = Math.ceil(msDiff / (1000 * 60 * 60 * 24)); return daysDiff; }; exports.getDaysFromNow = getDaysFromNow; /** * Get Jalali (Persian) date string to a Unix timestamp in milliseconds. * @param {string} jalaliDate - Jalali date in the format "YYYY-MM-DD" * @returns {number} Unix timestamp (milliseconds since 1970-01-01) */ const getJalaliTimeStamp = (jalaliDate) => { const gregorianDate = (0, exports.convertToGregorianDate)(jalaliDate); // "2025-03-20" const timestamp = new Date(gregorianDate).getTime(); //timestamp in milliseconds return timestamp; }; exports.getJalaliTimeStamp = getJalaliTimeStamp; /** * Returns a string indicating how long ago the given date was, * in Persian language format. * * @param {Date | string | number} date - The input date, either a Date object or a string parsable by `new Date()`. * @param {string} [suffix='پیش'] - Optional string to append, like 'پیش', 'قبل', or custom. Defaults to 'پیش'. * @returns {string} A Persian relative time string such as "۵ دقیقه پیش" */ const getTimeAgo = (date, suffix = "پیش") => { const d = typeof date === "string" || typeof date === "number" ? new Date(date) : date; const now = new Date(); const diffMs = now.getTime() - d.getTime(); const diffSec = Math.floor(diffMs / 1000); const diffMin = Math.floor(diffSec / 60); const diffHr = Math.floor(diffMin / 60); const diffDay = Math.floor(diffHr / 24); const diffMonth = Math.floor(diffDay / 30); const diffYear = Math.floor(diffDay / 365); if (diffSec < 60) return `لحظاتی ${suffix}`; if (diffMin < 60) return `${diffMin} دقیقه ${suffix}`; if (diffHr < 24) return `${diffHr} ساعت ${suffix}`; if (diffDay < 30) return `${diffDay} روز ${suffix}`; if (diffMonth < 12) return `${diffMonth} ماه ${suffix}`; return `${diffYear} سال ${suffix}`; }; exports.getTimeAgo = getTimeAgo; /** * Adds days to the Date object. * @param {number} days - Number of days to add. * @returns {Date} Updated date with added days. */ DT.addDaysToDate = function (days) { const date = new Date(this.valueOf()); date.setDate(date.getDate() + days); return date; }; /** * Adds a specific number of days to the given date. * @param {Date} date - Input date. * @param {number} daysCount - Number of days to add. * @returns {Date} Updated date. */ const addDaysToDate = (date, daysCount) => { return date.addDaysToDate(daysCount); }; exports.addDaysToDate = addDaysToDate; /** * Compares two date strings and checks if the first date is before the second. * @param {string} first - First date string. * @param {string} second - Second date string. * @returns {boolean} True if first date is before second date. */ const isBeforeDate = (first, second) => { const firstTime = new Date(first).getTime(); const secondTime = new Date(second).getTime(); return firstTime < secondTime; }; exports.isBeforeDate = isBeforeDate; /** * Check if the given Jalali year is a leap year. * @param {number} jalaliYear - Jalali year. * @returns {boolean} True if the Jalali year is a leap year. */ const isLeapYearJalali = (jalaliYear) => { const [gy] = toGregorian(jalaliYear, 1, 1); return (gy % 4 === 0 && gy % 100 !== 0) || gy % 400 === 0; }; exports.isLeapYearJalali = isLeapYearJalali; // Define arrays for Jalali months and days exports.jalaliMonthNames = [ "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", ]; exports.jalaliWeekdayNames = [ "شنبه", "یکشنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنج‌شنبه", "جمعه", ]; const jalaliWeekdayNamesGregorianFormat = [ "یکشنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنج‌شنبه", "جمعه", "شنبه", ]; /** * Converts Jalali date to Gregorian date. * @param {number} jy - Jalali year. * @param {number} jm - Jalali month. * @param {number} jd - Jalali day. * @returns {[number, number, number]} Gregorian year, month, and day. */ const toGregorian = (jy, jm, jd) => { let gy = jy <= 979 ? 621 : 1600; jy -= jy <= 979 ? 0 : 979; let days = 365 * jy + Math.floor(jy / 33) * 8 + Math.floor(((jy % 33) + 3) / 4) + 78 + jd + (jm < 7 ? (jm - 1) * 31 : (jm - 7) * 30 + 186); gy += 400 * Math.floor(days / 146097); days %= 146097; if (days > 36524) { gy += 100 * Math.floor(--days / 36524); days %= 36524; if (days >= 365) days++; } gy += 4 * Math.floor(days / 1461); days %= 1461; gy += Math.floor((days - 1) / 365); if (days > 365) days = (days - 1) % 365; let gd = days + 1; const sal_a = [ 0, 31, (gy % 4 === 0 && gy % 100 !== 0) || gy % 400 === 0 ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, ]; let gm = 0; for (gm = 0; gm < 13; gm++) { if (gd <= sal_a[gm]) break; gd -= sal_a[gm]; } return [gy, gm, gd]; };