UNPKG

jalaliday

Version:

Persian (Jalali, Khorshidi) Plugin for Day.js

313 lines (309 loc) 10.3 kB
import fa from "dayjs/locale/fa"; //#region src/calendar.ts const $floor = Math.floor; function mod(a, b) { return a - b * $floor(a / b); } function lg(year) { return year % 4 === 0 && !(year % 100 === 0 && year % 400 !== 0); } const GE = 1721425.5; function g2j(year, month, day) { return GE - 1 + 365 * (year - 1) + $floor((year - 1) / 4) + -$floor((year - 1) / 100) + $floor((year - 1) / 400) + $floor((367 * month - 362) / 12 + (month <= 2 ? 0 : lg(year) ? -1 : -2) + day); } function j2g(jd) { const wjd = $floor(jd - .5) + .5; const depoch = wjd - GE; const quadricent = $floor(depoch / 146097); const dqc = mod(depoch, 146097); const cent = $floor(dqc / 36524); const dcent = mod(dqc, 36524); const quad = $floor(dcent / 1461); const dquad = mod(dcent, 1461); const yindex = $floor(dquad / 365); let year = quadricent * 400 + cent * 100 + quad * 4 + yindex; if (!(cent === 4 || yindex === 4)) year++; const yearday = wjd - g2j(year, 1, 1); const leapadj = wjd < g2j(year, 3, 1) ? 0 : lg(year) ? 1 : 2; const month = $floor(((yearday + leapadj) * 12 + 373) / 367); const day = wjd - g2j(year, month, 1) + 1; return [ year, month, day ]; } const PE = 1948320.5; function p2j(year, month, day) { const epbase = year - (year >= 0 ? 474 : 473); const epyear = 474 + mod(epbase, 2820); return day + (month <= 7 ? (month - 1) * 31 : (month - 1) * 30 + 6) + $floor((epyear * 682 - 110) / 2816) + (epyear - 1) * 365 + $floor(epbase / 2820) * 1029983 + (PE - 1); } function j2p(jd) { let year, ycycle, aux1, aux2; jd = $floor(jd) + .5; const depoch = jd - p2j(475, 1, 1); const cycle = $floor(depoch / 1029983); const cyear = mod(depoch, 1029983); if (cyear === 1029982) ycycle = 2820; else { aux1 = $floor(cyear / 366); aux2 = mod(cyear, 366); ycycle = $floor((2134 * aux1 + 2816 * aux2 + 2815) / 1028522) + aux1 + 1; } year = ycycle + 2820 * cycle + 474; if (year <= 0) year--; const yday = jd - p2j(year, 1, 1) + 1; const month = yday <= 186 ? Math.ceil(yday / 31) : Math.ceil((yday - 6) / 30); const day = jd - p2j(year, month, 1) + 1; return [ year, month, day ]; } var calendar_default = { J: (y, m, d) => j2p(g2j(y, m, d)), G: (y, m, d) => j2g(p2j(y, m, d)) }; //#endregion //#region src/constant.ts const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})[-/]?(\d{0,2})(.*)$/; const REGEX_FORMAT = /\[.*?\]|jY{2,4}|jM{1,4}|jD{1,2}|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g; const DATE = "date"; const D = "day"; const M = "month"; const Y = "year"; const W = "week"; const FORMAT_DEFAULT = "YYYY-MM-DDTHH:mm:ssZ"; const fa$1 = { jmonths: "فروردین_اردیبهشت_خرداد_تیر_مرداد_شهریور_مهر_آبان_آذر_دی_بهمن_اسفند".split("_") }; //#endregion //#region src/dayjs/plugin.ts const plugin = (o, Dayjs, dayjs) => { const proto = Dayjs.prototype; const U = proto.$utils(); const $isJalali = (v) => v.$C === "jalali"; const $prettyUnit = U.prettyUnit || U.p; const $isUndefined = U.isUndefined || U.u; const $padStart = U.padStart || U.s; const $monthDiff = U.monthDiff || U.m; const $absFloor = U.absFloor || U.a; const wrapperOfTruth = (action) => function(...args) { const unsure = action.bind(this)(...args); unsure.$C = this.$C; if (unsure.isJalali()) unsure.InitJalali(); return unsure; }; proto.startOf = wrapperOfTruth(proto.startOf); proto.endOf = wrapperOfTruth(proto.endOf); proto.add = wrapperOfTruth(proto.add); proto.subtract = wrapperOfTruth(proto.subtract); proto.set = wrapperOfTruth(proto.set); const oldParse = proto.parse; const oldInit = proto.init; const oldStartOf = proto.startOf; const old$Set = proto.$set; const oldAdd = proto.add; const oldFormat = proto.format; const oldDiff = proto.diff; const oldYear = proto.year; const oldMonth = proto.month; const oldDate = proto.date; const oldDaysInMonth = proto.daysInMonth; const oldToArray = proto.toArray; dayjs.$C = "gregory"; dayjs.$fdow = 6; dayjs.calendar = function(calendar) { dayjs.$C = calendar; return dayjs; }; proto.calendar = function(calendar) { const that = this.clone(); that.$C = calendar; if (that.isJalali()) that.InitJalali(); return that; }; proto.isJalali = function() { return $isJalali(this); }; dayjs.en.jmonths = "Farvardin_Ordibehesht_Khordaad_Tir_Mordaad_Shahrivar_Mehr_Aabaan_Aazar_Dey_Bahman_Esfand".split("_"); dayjs.locale("fa", { ...fa, ...fa$1 }, true); const wrapper = function(date, instance) { return dayjs(date, { locale: instance.$L, utc: instance.$u, calendar: instance.$C }); }; proto.init = function(cfg = {}) { oldInit.bind(this)(cfg); if (this.isJalali()) this.InitJalali(); }; proto.parse = function(cfg) { this.$C = cfg.calendar || this.$C || dayjs.$C; if (cfg.jalali && typeof cfg.date === "string" && /.*[^Z]$/i.test(cfg.date)) { const reg = cfg.date.match(REGEX_PARSE); if (reg) { const [y, m, d] = calendar_default.G(Number.parseInt(reg[1], 10), Number.parseInt(reg[2], 10), Number.parseInt(reg[3] || 1, 10)); cfg.date = `${y}-${m}-${d}${reg[4] || ""}`; } } return oldParse.bind(this)(cfg); }; proto.InitJalali = function() { const [jy, jm, jd] = calendar_default.J(this.$y, this.$M + 1, this.$D); this.$jy = jy; this.$jM = jm - 1; this.$jD = jd; }; proto.startOf = function(units, startOf) { if (!$isJalali(this)) return oldStartOf.bind(this)(units, startOf); const isStartOf = !$isUndefined(startOf) ? startOf : true; const unit = $prettyUnit(units); const instanceFactory = (d, m, y = this.$jy) => { const [gy, gm, gd] = calendar_default.G(y, m + 1, d); const ins = wrapper(new Date(gy, gm - 1, gd), this); return (isStartOf ? ins : ins.endOf(D)).$set("hour", 1); }; const WModifier = (this.$W + (7 - dayjs.$fdow)) % 7; switch (unit) { case Y: return isStartOf ? instanceFactory(1, 0) : instanceFactory(0, 0, this.$jy + 1); case M: return isStartOf ? instanceFactory(1, this.$jM) : instanceFactory(0, (this.$jM + 1) % 12, this.$jy + Math.floor((this.$jM + 1) / 12)); case W: return isStartOf ? instanceFactory(this.$jD - WModifier, this.$jM) : instanceFactory(this.$jD + (6 - WModifier), this.$jM); default: return oldStartOf.bind(this)(units, startOf); } }; proto.$set = function(units, int) { if (!$isJalali(this)) return old$Set.bind(this)(units, int); const unit = $prettyUnit(units); const instanceFactory = (d, m, y = this.$jy) => { const [gy, gm, gd] = calendar_default.G(y, m + 1, d); this.$d.setFullYear(gy); this.$d.setMonth(gm - 1); this.$d.setDate(gd); return this; }; switch (unit) { case DATE: case D: instanceFactory(int, this.$jM); break; case M: instanceFactory(this.$jD, int); break; case Y: instanceFactory(this.$jD, this.$jM, int); break; default: return old$Set.bind(this)(units, int); } this.init(); return this; }; proto.add = function(number, units) { if (!$isJalali(this)) return oldAdd.bind(this)(number, units); number = Number(number); const unit = units && (units.length === 1 || units === "ms") ? units : $prettyUnit(units); const instanceFactory = (u, n) => { const date = this.set(DATE, 1).set(u, n + number); return date.set(DATE, Math.min(this.$jD, date.daysInMonth())); }; if (["M", M].includes(unit)) { const n = this.$jM + number; const y = n < 0 ? -Math.ceil(-n / 12) : Math.floor(n / 12); const d = this.$jD; const x = this.set(D, 1).add(y, Y).set(M, n - y * 12); return x.set(D, Math.min(x.daysInMonth(), d)); } if (["y", Y].includes(unit)) return instanceFactory(Y, this.$jy); if (["d", D].includes(unit)) { const date = new Date(this.$d); date.setDate(date.getDate() + number); return wrapper(date, this); } if (["w", W].includes(unit)) { const date = new Date(this.$d); date.setDate(date.getDate() + number * 7); return wrapper(date, this); } return oldAdd.bind(this)(number, units); }; proto.format = function(formatStr, localeObject) { if (!$isJalali(this)) return oldFormat.bind(this)(formatStr, localeObject); const str = formatStr || FORMAT_DEFAULT; const locale = localeObject || this.$locale(); const { jmonths } = locale; return str.replace(REGEX_FORMAT, (match) => { if (match.includes("[")) return match.replace(/\[|\]/g, ""); switch (match) { case "YY": return String(this.$jy).slice(-2); case "YYYY": return String(this.$jy); case "M": return String(this.$jM + 1); case "MM": return $padStart(this.$jM + 1, 2, "0"); case "MMM": return jmonths[this.$jM].slice(0, 3); case "MMMM": return jmonths[this.$jM]; case "D": return String(this.$jD); case "DD": return $padStart(this.$jD, 2, "0"); default: return oldFormat.bind(this)(match, localeObject); } }); }; proto.diff = function(input, units, float) { if (!$isJalali(this)) return oldDiff.bind(this)(input, units, float); const unit = $prettyUnit(units); const that = dayjs(input); let result = $monthDiff(this, that); switch (unit) { case Y: result /= 12; break; case M: break; default: return oldDiff.bind(this)(input, units, float); } return float ? result : $absFloor(result); }; proto.$g = function(input, get, set) { if ($isUndefined(input)) return this[get]; return this.set(set, input); }; proto.year = function(input) { if (!$isJalali(this)) return oldYear.bind(this)(input); return this.$g(input, "$jy", Y); }; proto.month = function(input) { if (!$isJalali(this)) return oldMonth.bind(this)(input); return this.$g(input, "$jM", M); }; proto.date = function(input) { if (!$isJalali(this)) return oldDate.bind(this)(input); return this.$g(input, "$jD", D); }; proto.daysInMonth = function() { if (!$isJalali(this)) return oldDaysInMonth.bind(this)(); return this.endOf(M).$jD; }; /** * toArray function moved to official plugin * Check function existence before override */ if (oldToArray) proto.toArray = function() { if (!$isJalali(this)) return oldToArray.bind(this)(); return [ this.$jy, this.$jM, this.$jD, this.$H, this.$m, this.$s, this.$ms ]; }; proto.clone = function() { return wrapper(this.toDate(), this); }; }; var plugin_default = plugin; //#endregion export { plugin_default };