Files

152 lines
4.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
const toEnglishDigits = (value) =>
String(value ?? '')
.replace(/[۰-۹]/g, (d) => '۰۱۲۳۴۵۶۷۸۹'.indexOf(d))
.replace(/[٠-٩]/g, (d) => '٠١٢٣٤٥٦٧٨٩'.indexOf(d));
const jalaliToGregorian = (jy, jm, jd) => {
const 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);
let gyOut = gy + 400 * Math.floor(days / 146097);
days %= 146097;
if (days > 36524) {
gyOut += 100 * Math.floor(--days / 36524);
days %= 36524;
if (days >= 365) days += 1;
}
gyOut += 4 * Math.floor(days / 1461);
days %= 1461;
if (days > 365) {
gyOut += Math.floor((days - 1) / 365);
days = (days - 1) % 365;
}
let gd = days + 1;
const sal_a = [
0,
31,
(gyOut % 4 === 0 && gyOut % 100 !== 0) || gyOut % 400 === 0 ? 29 : 28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
];
let gm = 0;
for (gm = 1; gm <= 12 && gd > sal_a[gm]; gm += 1) gd -= sal_a[gm];
return `${gyOut}-${String(gm).padStart(2, '0')}-${String(gd).padStart(2, '0')}`;
};
const parseJalaliDate = (raw) => {
if (!raw) return null;
const text = toEnglishDigits(raw).replace(/[./\-]/g, '/').trim();
const match = text.match(/^(\d{3,4})\/(\d{1,2})\/(\d{1,2})$/);
if (!match) return null;
const jy = Number(match[1]);
const jm = Number(match[2]);
const jd = Number(match[3]);
if (!jy || !jm || !jd || jm > 12 || jd > 31 || jy < 1200 || jy > 1599) return null;
try {
return jalaliToGregorian(jy, jm, jd);
} catch {
return null;
}
};
const parseImportDate = (raw) => {
if (!raw) return null;
if (raw instanceof Date) {
return Number.isNaN(raw.getTime()) ? null : raw;
}
const text = toEnglishDigits(raw).trim();
if (!text) return null;
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(text)) {
const d = new Date(text);
return Number.isNaN(d.getTime()) ? null : d;
}
const dateMatch = text.match(/^(\d{3,4})[./\-](\d{1,2})[./\-](\d{1,2})/);
if (dateMatch) {
const year = Number(dateMatch[1]);
const month = Number(dateMatch[2]);
const day = Number(dateMatch[3]);
if (year >= 1200 && year <= 1599) {
const gDate = jalaliToGregorian(year, month, day);
if (gDate) return new Date(`${gDate}T00:00:00.000Z`);
} else if (year >= 1900 && year <= 2200) {
const mStr = String(month).padStart(2, '0');
const dStr = String(day).padStart(2, '0');
return new Date(`${year}-${mStr}-${dStr}T00:00:00.000Z`);
}
}
const jalali = parseJalaliDate(text);
if (jalali) return new Date(`${jalali}T00:00:00.000Z`);
const date = new Date(text);
return Number.isNaN(date.getTime()) ? null : date;
};
const gregorianToJalali = (gy, gm, gd) => {
const g_d_m = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
let jy;
if (gy > 1600) {
jy = 979;
gy -= 1600;
} else {
jy = 0;
gy -= 621;
}
const gy2 = gm > 2 ? gy + 1 : gy;
let days = 365 * gy + Math.floor((gy2 + 3) / 4) - Math.floor((gy2 + 99) / 100) + Math.floor((gy2 + 399) / 400) - 80 + gd + g_d_m[gm - 1];
jy += 33 * Math.floor(days / 12053);
days %= 12053;
jy += 4 * Math.floor(days / 1461);
days %= 1461;
if (days > 365) {
jy += Math.floor((days - 1) / 365);
days = (days - 1) % 365;
}
const jm = days < 186 ? 1 + Math.floor(days / 31) : 7 + Math.floor((days - 186) / 30);
const jd = 1 + (days < 186 ? days % 31 : (days - 186) % 30);
return `${jy}/${String(jm).padStart(2, '0')}/${String(jd).padStart(2, '0')}`;
};
const formatJalaliDate = (rawDate) => {
if (!rawDate) return '';
const date = rawDate instanceof Date ? rawDate : new Date(rawDate);
if (Number.isNaN(date.getTime())) return '';
return gregorianToJalali(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate());
};
const utcDayRange = (value) => {
const date = parseImportDate(value);
if (!date) return null;
const start = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000);
return { start, end };
};
module.exports = {
toEnglishDigits,
jalaliToGregorian,
gregorianToJalali,
formatJalaliDate,
parseJalaliDate,
parseImportDate,
utcDayRange
};