jalaliday
Version:
Persian (Jalali, Khorshidi) Plugin for Day.js
313 lines (309 loc) • 10.3 kB
JavaScript
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 };