UEA-Prodem
This commit is contained in:
+28
@@ -0,0 +1,28 @@
|
||||
import type { Locale } from "date-fns";
|
||||
import React from "react";
|
||||
import { DateLib, type DateLibOptions } from "../index.js";
|
||||
import type { DayPickerProps } from "../types/props.js";
|
||||
/**
|
||||
* Render the Hijri (Umm al-Qura) calendar.
|
||||
*
|
||||
* Defaults:
|
||||
*
|
||||
* - `locale`: `ar-SA`
|
||||
* - `dir`: `rtl`
|
||||
* - `numerals`: `arab`
|
||||
* - `startMonth`: `1924-08-01`
|
||||
* - `endMonth`: `2077-11-16`
|
||||
*
|
||||
* Out-of-range date props are clamped to the supported Umm al-Qura conversion
|
||||
* range, preventing runtime conversion errors.
|
||||
*/
|
||||
export declare function DayPicker(props: DayPickerProps & {
|
||||
locale?: Locale;
|
||||
dir?: DayPickerProps["dir"];
|
||||
numerals?: DayPickerProps["numerals"];
|
||||
dateLib?: DayPickerProps["dateLib"];
|
||||
}): React.JSX.Element;
|
||||
/** Returns the date library used in the Hijri calendar. */
|
||||
export declare const getDateLib: (options?: DateLibOptions) => DateLib;
|
||||
export { arSA } from "../locale/ar-SA.js";
|
||||
export { enUS } from "../locale/en-US.js";
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.enUS = exports.arSA = exports.getDateLib = void 0;
|
||||
exports.DayPicker = DayPicker;
|
||||
const react_1 = __importDefault(require("react"));
|
||||
const index_js_1 = require("../index.js");
|
||||
const ar_SA_js_1 = require("../locale/ar-SA.js");
|
||||
const hijriDateLib = __importStar(require("./lib/index.js"));
|
||||
const range_js_1 = require("./utils/range.js");
|
||||
function clampDateProp(date) {
|
||||
if (!date) {
|
||||
return undefined;
|
||||
}
|
||||
return (0, range_js_1.clampGregorianDate)(date);
|
||||
}
|
||||
/**
|
||||
* Render the Hijri (Umm al-Qura) calendar.
|
||||
*
|
||||
* Defaults:
|
||||
*
|
||||
* - `locale`: `ar-SA`
|
||||
* - `dir`: `rtl`
|
||||
* - `numerals`: `arab`
|
||||
* - `startMonth`: `1924-08-01`
|
||||
* - `endMonth`: `2077-11-16`
|
||||
*
|
||||
* Out-of-range date props are clamped to the supported Umm al-Qura conversion
|
||||
* range, preventing runtime conversion errors.
|
||||
*/
|
||||
function DayPicker(props) {
|
||||
const { dateLib: dateLibProp, ...dayPickerProps } = props;
|
||||
const hasStartBound = props.startMonth !== undefined ||
|
||||
props.fromMonth !== undefined ||
|
||||
props.fromYear !== undefined;
|
||||
const hasEndBound = props.endMonth !== undefined ||
|
||||
props.toMonth !== undefined ||
|
||||
props.toYear !== undefined;
|
||||
const clampedProps = {
|
||||
...dayPickerProps,
|
||||
month: clampDateProp(props.month),
|
||||
defaultMonth: clampDateProp(props.defaultMonth),
|
||||
today: clampDateProp(props.today),
|
||||
startMonth: hasStartBound
|
||||
? clampDateProp(props.startMonth)
|
||||
: new Date(range_js_1.GREGORIAN_MIN_DATE),
|
||||
endMonth: hasEndBound
|
||||
? clampDateProp(props.endMonth)
|
||||
: new Date(range_js_1.GREGORIAN_MAX_DATE),
|
||||
fromMonth: clampDateProp(props.fromMonth),
|
||||
toMonth: clampDateProp(props.toMonth),
|
||||
};
|
||||
return (react_1.default.createElement(index_js_1.DayPicker, { ...clampedProps, locale: props.locale ?? ar_SA_js_1.arSA, numerals: props.numerals ?? "arab", dir: props.dir ?? "rtl", dateLib: { ...hijriDateLib, ...dateLibProp } }));
|
||||
}
|
||||
/** Returns the date library used in the Hijri calendar. */
|
||||
const getDateLib = (options) => {
|
||||
return new index_js_1.DateLib(options, hijriDateLib);
|
||||
};
|
||||
exports.getDateLib = getDateLib;
|
||||
var ar_SA_js_2 = require("../locale/ar-SA.js");
|
||||
Object.defineProperty(exports, "arSA", { enumerable: true, get: function () { return ar_SA_js_2.arSA; } });
|
||||
var en_US_js_1 = require("../locale/en-US.js");
|
||||
Object.defineProperty(exports, "enUS", { enumerable: true, get: function () { return en_US_js_1.enUS; } });
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function addMonths(date: Date, amount: number): Date;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.addMonths = addMonths;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const setMonth_js_1 = require("./setMonth.js");
|
||||
function addMonths(date, amount) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
return (0, setMonth_js_1.setMonth)(date, hijri.monthIndex + amount);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function addYears(date: Date, amount: number): Date;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.addYears = addYears;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const setYear_js_1 = require("./setYear.js");
|
||||
function addYears(date, amount) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
return (0, setYear_js_1.setYear)(date, hijri.year + amount);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function differenceInCalendarMonths(dateLeft: Date, dateRight: Date): number;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.differenceInCalendarMonths = differenceInCalendarMonths;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function differenceInCalendarMonths(dateLeft, dateRight) {
|
||||
const hijriLeft = (0, conversion_js_1.toHijriDate)(dateLeft);
|
||||
const hijriRight = (0, conversion_js_1.toHijriDate)(dateRight);
|
||||
return ((hijriLeft.year - hijriRight.year) * 12 +
|
||||
(hijriLeft.monthIndex - hijriRight.monthIndex));
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
import { type Interval } from "date-fns";
|
||||
export declare function eachMonthOfInterval(interval: Interval): Date[];
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.eachMonthOfInterval = eachMonthOfInterval;
|
||||
const date_fns_1 = require("date-fns");
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function eachMonthOfInterval(interval) {
|
||||
const start = (0, date_fns_1.toDate)(interval.start);
|
||||
const end = (0, date_fns_1.toDate)(interval.end);
|
||||
if (end.getTime() < start.getTime()) {
|
||||
throw new RangeError("Invalid interval");
|
||||
}
|
||||
const startDate = (0, conversion_js_1.toHijriDate)(start);
|
||||
const endDate = (0, conversion_js_1.toHijriDate)(end);
|
||||
const months = [];
|
||||
let currentYear = startDate.year;
|
||||
let currentMonth = startDate.monthIndex;
|
||||
const endYear = endDate.year;
|
||||
const endMonth = endDate.monthIndex;
|
||||
while (currentYear < endYear ||
|
||||
(currentYear === endYear && currentMonth <= endMonth)) {
|
||||
months.push((0, conversion_js_1.toGregorianDate)({ year: currentYear, monthIndex: currentMonth, day: 1 }));
|
||||
currentMonth += 1;
|
||||
if (currentMonth > 11) {
|
||||
currentMonth = 0;
|
||||
currentYear += 1;
|
||||
}
|
||||
}
|
||||
return months;
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
import { type Interval } from "date-fns";
|
||||
export declare function eachYearOfInterval(interval: Interval): Date[];
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.eachYearOfInterval = eachYearOfInterval;
|
||||
const date_fns_1 = require("date-fns");
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function eachYearOfInterval(interval) {
|
||||
const start = (0, date_fns_1.toDate)(interval.start);
|
||||
const end = (0, date_fns_1.toDate)(interval.end);
|
||||
if (end.getTime() < start.getTime()) {
|
||||
return [];
|
||||
}
|
||||
const startYear = (0, conversion_js_1.toHijriDate)(start).year;
|
||||
const endYear = (0, conversion_js_1.toHijriDate)(end).year;
|
||||
const years = [];
|
||||
for (let year = startYear; year <= endYear; year += 1) {
|
||||
years.push((0, conversion_js_1.toGregorianDate)({ year, monthIndex: 0, day: 1 }));
|
||||
}
|
||||
return years;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function endOfMonth(date: Date): Date;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.endOfMonth = endOfMonth;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const daysInMonth_js_1 = require("../utils/daysInMonth.js");
|
||||
function endOfMonth(date) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
const day = (0, daysInMonth_js_1.getDaysInMonth)(hijri.year, hijri.monthIndex);
|
||||
return (0, conversion_js_1.toGregorianDate)({
|
||||
year: hijri.year,
|
||||
monthIndex: hijri.monthIndex,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function endOfYear(date: Date): Date;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.endOfYear = endOfYear;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const daysInMonth_js_1 = require("../utils/daysInMonth.js");
|
||||
function endOfYear(date) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
const day = (0, daysInMonth_js_1.getDaysInMonth)(hijri.year, 11);
|
||||
return (0, conversion_js_1.toGregorianDate)({
|
||||
year: hijri.year,
|
||||
monthIndex: 11,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type FallbackLocaleCode = "ar" | "en";
|
||||
export type IntlNameWidth = "long" | "short" | "narrow";
|
||||
export declare const getFallbackLocaleCode: (localeCode: string) => FallbackLocaleCode;
|
||||
export declare const getFallbackMonthName: (date: Date, localeCode: string, width: IntlNameWidth) => string;
|
||||
export declare const getFallbackWeekdayName: (date: Date, localeCode: string, width: IntlNameWidth) => string;
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getFallbackWeekdayName = exports.getFallbackMonthName = exports.getFallbackLocaleCode = void 0;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const fallbackMonthNames = {
|
||||
en: {
|
||||
long: [
|
||||
"Muharram",
|
||||
"Safar",
|
||||
"Rabi I",
|
||||
"Rabi II",
|
||||
"Jumada I",
|
||||
"Jumada II",
|
||||
"Rajab",
|
||||
"Shaban",
|
||||
"Ramadan",
|
||||
"Shawwal",
|
||||
"Dhu al-Qadah",
|
||||
"Dhu al-Hijjah",
|
||||
],
|
||||
short: [
|
||||
"Muh",
|
||||
"Saf",
|
||||
"Rab-I",
|
||||
"Rab-II",
|
||||
"Jum-I",
|
||||
"Jum-II",
|
||||
"Raj",
|
||||
"Sha",
|
||||
"Ram",
|
||||
"Shw",
|
||||
"Dhu-Q",
|
||||
"Dhu-H",
|
||||
],
|
||||
narrow: ["M", "S", "R", "R", "J", "J", "R", "S", "R", "S", "D", "D"],
|
||||
},
|
||||
ar: {
|
||||
long: [
|
||||
"محرم",
|
||||
"صفر",
|
||||
"ربيع الأول",
|
||||
"ربيع الآخر",
|
||||
"جمادى الأولى",
|
||||
"جمادى الآخرة",
|
||||
"رجب",
|
||||
"شعبان",
|
||||
"رمضان",
|
||||
"شوال",
|
||||
"ذو القعدة",
|
||||
"ذو الحجة",
|
||||
],
|
||||
short: [
|
||||
"محرم",
|
||||
"صفر",
|
||||
"ربيع ١",
|
||||
"ربيع ٢",
|
||||
"جمادى ١",
|
||||
"جمادى ٢",
|
||||
"رجب",
|
||||
"شعبان",
|
||||
"رمضان",
|
||||
"شوال",
|
||||
"ذو القعدة",
|
||||
"ذو الحجة",
|
||||
],
|
||||
narrow: ["م", "ص", "ر", "ر", "ج", "ج", "ر", "ش", "ر", "ش", "ذ", "ذ"],
|
||||
},
|
||||
};
|
||||
const fallbackWeekdayNames = {
|
||||
en: {
|
||||
long: [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
],
|
||||
short: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||
narrow: ["S", "M", "T", "W", "T", "F", "S"],
|
||||
},
|
||||
ar: {
|
||||
long: [
|
||||
"الأحد",
|
||||
"الاثنين",
|
||||
"الثلاثاء",
|
||||
"الأربعاء",
|
||||
"الخميس",
|
||||
"الجمعة",
|
||||
"السبت",
|
||||
],
|
||||
short: ["أحد", "اثن", "ثلا", "أرب", "خمي", "جمع", "سبت"],
|
||||
narrow: ["ح", "ن", "ث", "ر", "خ", "ج", "س"],
|
||||
},
|
||||
};
|
||||
const getFallbackLocaleCode = (localeCode) => {
|
||||
return localeCode.toLowerCase().startsWith("ar") ? "ar" : "en";
|
||||
};
|
||||
exports.getFallbackLocaleCode = getFallbackLocaleCode;
|
||||
const getFallbackMonthName = (date, localeCode, width) => {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
const locale = (0, exports.getFallbackLocaleCode)(localeCode);
|
||||
return fallbackMonthNames[locale][width][hijri.monthIndex];
|
||||
};
|
||||
exports.getFallbackMonthName = getFallbackMonthName;
|
||||
const getFallbackWeekdayName = (date, localeCode, width) => {
|
||||
const locale = (0, exports.getFallbackLocaleCode)(localeCode);
|
||||
return fallbackWeekdayNames[locale][width][date.getDay()];
|
||||
};
|
||||
exports.getFallbackWeekdayName = getFallbackWeekdayName;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import type { FormatOptions as DateFnsFormatOptions } from "date-fns";
|
||||
/** Hijri calendar formatting override. */
|
||||
export declare function format(date: Date, formatStr: string, options?: DateFnsFormatOptions): string;
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.format = format;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const range_js_1 = require("../utils/range.js");
|
||||
const fallbackLocaleData_js_1 = require("./fallbackLocaleData.js");
|
||||
const DEFAULT_LOCALE_CODE = "ar-SA";
|
||||
const BASE_NUMBERING_SYSTEM = "latn";
|
||||
const UMM_AL_QURA_CALENDAR = "islamic-umalqura";
|
||||
const getLocaleCode = (options) => {
|
||||
return options?.locale?.code ?? DEFAULT_LOCALE_CODE;
|
||||
};
|
||||
const formatWithUmmAlQura = (date, localeCode, options) => {
|
||||
try {
|
||||
return new Intl.DateTimeFormat(localeCode, {
|
||||
...options,
|
||||
calendar: UMM_AL_QURA_CALENDAR,
|
||||
numberingSystem: BASE_NUMBERING_SYSTEM,
|
||||
}).format(date);
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
const formatNumber = (value) => {
|
||||
return value.toString();
|
||||
};
|
||||
const formatPaddedNumber = (value) => {
|
||||
return formatNumber(value).padStart(2, "0");
|
||||
};
|
||||
const formatMonthName = (date, localeCode, width) => {
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
month: width,
|
||||
});
|
||||
return formatted ?? (0, fallbackLocaleData_js_1.getFallbackMonthName)(date, localeCode, width);
|
||||
};
|
||||
const formatWeekdayName = (date, localeCode, width) => {
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
weekday: width,
|
||||
});
|
||||
return formatted ?? (0, fallbackLocaleData_js_1.getFallbackWeekdayName)(date, localeCode, width);
|
||||
};
|
||||
const formatDateStyle = (date, localeCode, style) => {
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
dateStyle: style,
|
||||
});
|
||||
if (formatted) {
|
||||
return formatted;
|
||||
}
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
const monthName = (0, fallbackLocaleData_js_1.getFallbackMonthName)(date, localeCode, "long");
|
||||
switch (style) {
|
||||
case "full":
|
||||
return `${(0, fallbackLocaleData_js_1.getFallbackWeekdayName)(date, localeCode, "long")}, ${monthName} ${hijri.day}, ${hijri.year}`;
|
||||
case "long":
|
||||
return `${monthName} ${hijri.day}, ${hijri.year}`;
|
||||
case "medium":
|
||||
return `${formatPaddedNumber(hijri.day)} ${monthName} ${hijri.year}`;
|
||||
case "short":
|
||||
return `${hijri.monthIndex + 1}/${hijri.day}/${hijri.year}`;
|
||||
}
|
||||
};
|
||||
const buildTimeFormat = (date, localeCode, formatStr) => {
|
||||
const hour12 = formatStr.includes("a");
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12,
|
||||
});
|
||||
if (formatted) {
|
||||
return formatted;
|
||||
}
|
||||
try {
|
||||
return new Intl.DateTimeFormat(localeCode, {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12,
|
||||
numberingSystem: BASE_NUMBERING_SYSTEM,
|
||||
}).format(date);
|
||||
}
|
||||
catch {
|
||||
const minutes = formatPaddedNumber(date.getMinutes());
|
||||
if (hour12) {
|
||||
const hour = date.getHours() % 12 || 12;
|
||||
const period = date.getHours() >= 12 ? "PM" : "AM";
|
||||
return `${hour}:${minutes} ${period}`;
|
||||
}
|
||||
return `${formatNumber(date.getHours())}:${minutes}`;
|
||||
}
|
||||
};
|
||||
/** Hijri calendar formatting override. */
|
||||
function format(date, formatStr, options) {
|
||||
const extendedOptions = options;
|
||||
const localeCode = getLocaleCode(extendedOptions);
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
const gregorian = (0, range_js_1.getGregorianDateParts)(date);
|
||||
const isOutOfRange = (0, range_js_1.clampGregorianDate)(date) !== date;
|
||||
const numericDate = isOutOfRange
|
||||
? {
|
||||
year: gregorian.year,
|
||||
monthIndex: gregorian.month - 1,
|
||||
day: gregorian.day,
|
||||
}
|
||||
: hijri;
|
||||
switch (formatStr) {
|
||||
case "LLLL y":
|
||||
case "LLLL yyyy":
|
||||
return `${formatMonthName(date, localeCode, "long")} ${formatNumber(numericDate.year)}`;
|
||||
case "LLLL":
|
||||
return formatMonthName(date, localeCode, "long");
|
||||
case "LLL":
|
||||
return formatMonthName(date, localeCode, "short");
|
||||
case "PPP":
|
||||
return formatDateStyle(date, localeCode, "long");
|
||||
case "PPPP":
|
||||
return formatDateStyle(date, localeCode, "full");
|
||||
case "PP":
|
||||
return formatDateStyle(date, localeCode, "medium");
|
||||
case "P":
|
||||
return formatDateStyle(date, localeCode, "short");
|
||||
case "cccc":
|
||||
return formatWeekdayName(date, localeCode, "long");
|
||||
case "ccc":
|
||||
return formatWeekdayName(date, localeCode, "short");
|
||||
case "ccccc":
|
||||
case "cccccc":
|
||||
return formatWeekdayName(date, localeCode, "narrow");
|
||||
case "yyyy":
|
||||
case "y":
|
||||
return formatNumber(numericDate.year);
|
||||
case "yyyy-MM":
|
||||
return `${formatNumber(numericDate.year)}-${formatPaddedNumber(numericDate.monthIndex + 1)}`;
|
||||
case "yyyy-MM-dd":
|
||||
return `${formatNumber(numericDate.year)}-${formatPaddedNumber(numericDate.monthIndex + 1)}-${formatPaddedNumber(numericDate.day)}`;
|
||||
case "MM":
|
||||
return formatPaddedNumber(numericDate.monthIndex + 1);
|
||||
case "M":
|
||||
return formatNumber(numericDate.monthIndex + 1);
|
||||
case "dd":
|
||||
return formatPaddedNumber(numericDate.day);
|
||||
case "d":
|
||||
return formatNumber(numericDate.day);
|
||||
default:
|
||||
if (/[Hh]/.test(formatStr) && /m/.test(formatStr)) {
|
||||
return buildTimeFormat(date, localeCode, formatStr);
|
||||
}
|
||||
return formatDateStyle(date, localeCode, "medium");
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function getMonth(date: Date): number;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getMonth = getMonth;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function getMonth(date) {
|
||||
return (0, conversion_js_1.toHijriDate)(date).monthIndex;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function getYear(date: Date): number;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getYear = getYear;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function getYear(date) {
|
||||
return (0, conversion_js_1.toHijriDate)(date).year;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
export * from "./addMonths.js";
|
||||
export * from "./addYears.js";
|
||||
export * from "./differenceInCalendarMonths.js";
|
||||
export * from "./eachMonthOfInterval.js";
|
||||
export * from "./eachYearOfInterval.js";
|
||||
export * from "./endOfMonth.js";
|
||||
export * from "./endOfYear.js";
|
||||
export * from "./format.js";
|
||||
export * from "./getMonth.js";
|
||||
export * from "./getYear.js";
|
||||
export * from "./isSameMonth.js";
|
||||
export * from "./isSameYear.js";
|
||||
export * from "./newDate.js";
|
||||
export * from "./setMonth.js";
|
||||
export * from "./setYear.js";
|
||||
export * from "./startOfMonth.js";
|
||||
export * from "./startOfYear.js";
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./addMonths.js"), exports);
|
||||
__exportStar(require("./addYears.js"), exports);
|
||||
__exportStar(require("./differenceInCalendarMonths.js"), exports);
|
||||
__exportStar(require("./eachMonthOfInterval.js"), exports);
|
||||
__exportStar(require("./eachYearOfInterval.js"), exports);
|
||||
__exportStar(require("./endOfMonth.js"), exports);
|
||||
__exportStar(require("./endOfYear.js"), exports);
|
||||
__exportStar(require("./format.js"), exports);
|
||||
__exportStar(require("./getMonth.js"), exports);
|
||||
__exportStar(require("./getYear.js"), exports);
|
||||
__exportStar(require("./isSameMonth.js"), exports);
|
||||
__exportStar(require("./isSameYear.js"), exports);
|
||||
__exportStar(require("./newDate.js"), exports);
|
||||
__exportStar(require("./setMonth.js"), exports);
|
||||
__exportStar(require("./setYear.js"), exports);
|
||||
__exportStar(require("./startOfMonth.js"), exports);
|
||||
__exportStar(require("./startOfYear.js"), exports);
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function isSameMonth(dateLeft: Date, dateRight: Date): boolean;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isSameMonth = isSameMonth;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function isSameMonth(dateLeft, dateRight) {
|
||||
const hijriLeft = (0, conversion_js_1.toHijriDate)(dateLeft);
|
||||
const hijriRight = (0, conversion_js_1.toHijriDate)(dateRight);
|
||||
return (hijriLeft.year === hijriRight.year &&
|
||||
hijriLeft.monthIndex === hijriRight.monthIndex);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function isSameYear(dateLeft: Date, dateRight: Date): boolean;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isSameYear = isSameYear;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function isSameYear(dateLeft, dateRight) {
|
||||
const hijriLeft = (0, conversion_js_1.toHijriDate)(dateLeft);
|
||||
const hijriRight = (0, conversion_js_1.toHijriDate)(dateRight);
|
||||
return hijriLeft.year === hijriRight.year;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function newDate(year: number, monthIndex: number, day: number): Date;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.newDate = newDate;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function newDate(year, monthIndex, day) {
|
||||
return (0, conversion_js_1.toGregorianDate)({ year, monthIndex, day });
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function setMonth(date: Date, monthIndex: number): Date;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.setMonth = setMonth;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const daysInMonth_js_1 = require("../utils/daysInMonth.js");
|
||||
function setMonth(date, monthIndex) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
// Handle overflow/underflow of monthIndex
|
||||
// Note: monthIndex argument is absolute month index for the year.
|
||||
// E.g. setMonth(..., 13) sets to Safar next year.
|
||||
let targetYear = hijri.year;
|
||||
let targetMonth = monthIndex;
|
||||
if (targetMonth > 11 || targetMonth < 0) {
|
||||
targetYear += Math.floor(targetMonth / 12);
|
||||
targetMonth = targetMonth % 12;
|
||||
if (targetMonth < 0) {
|
||||
targetMonth += 12;
|
||||
}
|
||||
}
|
||||
const daysInTargetMonth = (0, daysInMonth_js_1.getDaysInMonth)(targetYear, targetMonth);
|
||||
const day = Math.min(hijri.day, daysInTargetMonth);
|
||||
return (0, conversion_js_1.toGregorianDate)({
|
||||
year: targetYear,
|
||||
monthIndex: targetMonth,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function setYear(date: Date, year: number): Date;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.setYear = setYear;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
const daysInMonth_js_1 = require("../utils/daysInMonth.js");
|
||||
function setYear(date, year) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
const daysInTargetMonth = (0, daysInMonth_js_1.getDaysInMonth)(year, hijri.monthIndex);
|
||||
const day = Math.min(hijri.day, daysInTargetMonth);
|
||||
return (0, conversion_js_1.toGregorianDate)({
|
||||
year,
|
||||
monthIndex: hijri.monthIndex,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function startOfMonth(date: Date): Date;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.startOfMonth = startOfMonth;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function startOfMonth(date) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
return (0, conversion_js_1.toGregorianDate)({
|
||||
year: hijri.year,
|
||||
monthIndex: hijri.monthIndex,
|
||||
day: 1,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function startOfYear(date: Date): Date;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.startOfYear = startOfYear;
|
||||
const conversion_js_1 = require("../utils/conversion.js");
|
||||
function startOfYear(date) {
|
||||
const hijri = (0, conversion_js_1.toHijriDate)(date);
|
||||
return (0, conversion_js_1.toGregorianDate)({
|
||||
year: hijri.year,
|
||||
monthIndex: 0,
|
||||
day: 1,
|
||||
});
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type { HijriDate } from "./types.js";
|
||||
/** Convert a Gregorian date to a Hijri date. */
|
||||
export declare function toHijriDate(date: Date): HijriDate;
|
||||
/** Convert a Hijri date back to the Gregorian calendar. */
|
||||
export declare function toGregorianDate(hijri: HijriDate): Date;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.toHijriDate = toHijriDate;
|
||||
exports.toGregorianDate = toGregorianDate;
|
||||
const hijri_converter_1 = require("@tabby_ai/hijri-converter");
|
||||
const range_js_1 = require("./range.js");
|
||||
/** Convert a Gregorian date to a Hijri date. */
|
||||
function toHijriDate(date) {
|
||||
const clamped = (0, range_js_1.clampGregorianDate)(date);
|
||||
const { year, month, day } = (0, range_js_1.getGregorianDateParts)(clamped);
|
||||
// gregorianToHijri uses 1-indexed months
|
||||
const hijri = (0, hijri_converter_1.gregorianToHijri)({ year, month, day });
|
||||
return {
|
||||
year: hijri.year,
|
||||
monthIndex: hijri.month - 1, // Convert to 0-indexed
|
||||
day: hijri.day,
|
||||
};
|
||||
}
|
||||
/** Convert a Hijri date back to the Gregorian calendar. */
|
||||
function toGregorianDate(hijri) {
|
||||
const clamped = (0, range_js_1.clampHijriDate)(hijri);
|
||||
// hijriToGregorian expects 1-indexed months. Probe down from the candidate
|
||||
// day to handle invalid month/day combinations without throwing.
|
||||
for (let day = clamped.day; day >= 1; day -= 1) {
|
||||
try {
|
||||
const gregorian = (0, hijri_converter_1.hijriToGregorian)({
|
||||
year: clamped.year,
|
||||
month: clamped.monthIndex + 1,
|
||||
day,
|
||||
});
|
||||
return (0, range_js_1.clampGregorianDate)(new Date(gregorian.year, gregorian.month - 1, gregorian.day));
|
||||
}
|
||||
catch {
|
||||
// Try a lower day for months that only have 29 days.
|
||||
}
|
||||
}
|
||||
// Fallback to the minimum supported Gregorian date if conversion probing
|
||||
// somehow fails for all days.
|
||||
return new Date(range_js_1.GREGORIAN_MIN_DATE);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function getDaysInMonth(year: number, monthIndex: number): number;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getDaysInMonth = getDaysInMonth;
|
||||
const conversion_js_1 = require("./conversion.js");
|
||||
const range_js_1 = require("./range.js");
|
||||
const MAX_DAY_IN_HIJRI_MONTH = 30;
|
||||
const MIN_DAY_IN_HIJRI_MONTH = 29;
|
||||
function getDaysInMonth(year, monthIndex) {
|
||||
const clamped = (0, range_js_1.clampHijriDate)({ year, monthIndex, day: 1 });
|
||||
for (let day = MAX_DAY_IN_HIJRI_MONTH; day >= MIN_DAY_IN_HIJRI_MONTH; day -= 1) {
|
||||
const candidateDate = (0, conversion_js_1.toGregorianDate)({
|
||||
year: clamped.year,
|
||||
monthIndex: clamped.monthIndex,
|
||||
day,
|
||||
});
|
||||
const roundTrip = (0, conversion_js_1.toHijriDate)(candidateDate);
|
||||
if (roundTrip.year === clamped.year &&
|
||||
roundTrip.monthIndex === clamped.monthIndex &&
|
||||
roundTrip.day === day) {
|
||||
return day;
|
||||
}
|
||||
}
|
||||
return MIN_DAY_IN_HIJRI_MONTH;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import type { HijriDate } from "./types.js";
|
||||
type GregorianDateParts = {
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
};
|
||||
/** Returns Gregorian date parts while preserving years < 100. */
|
||||
export declare function getGregorianDateParts(date: Date): GregorianDateParts;
|
||||
/** Internal Gregorian lower bound supported by the Hijri converter. */
|
||||
export declare const GREGORIAN_MIN_DATE: Date;
|
||||
/** Internal Gregorian upper bound supported by the Hijri converter. */
|
||||
export declare const GREGORIAN_MAX_DATE: Date;
|
||||
/** Clamp a Gregorian date to the supported Hijri conversion range. */
|
||||
export declare function clampGregorianDate(date: Date): Date;
|
||||
/** Returns whether the provided Gregorian date was clamped. */
|
||||
export declare function wasGregorianDateClamped(date: Date): boolean;
|
||||
/** Clamp a Hijri date to the supported range and normalize month overflow. */
|
||||
export declare function clampHijriDate(date: HijriDate): HijriDate;
|
||||
/** Returns whether the provided Hijri date was clamped. */
|
||||
export declare function wasHijriDateClamped(date: HijriDate): boolean;
|
||||
export {};
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GREGORIAN_MAX_DATE = exports.GREGORIAN_MIN_DATE = void 0;
|
||||
exports.getGregorianDateParts = getGregorianDateParts;
|
||||
exports.clampGregorianDate = clampGregorianDate;
|
||||
exports.wasGregorianDateClamped = wasGregorianDateClamped;
|
||||
exports.clampHijriDate = clampHijriDate;
|
||||
exports.wasHijriDateClamped = wasHijriDateClamped;
|
||||
const MAX_HIJRI_DAY = 30;
|
||||
const MONTHS_PER_YEAR = 12;
|
||||
const HIJRI_MIN = { year: 1343, monthIndex: 0, day: 1 };
|
||||
const HIJRI_MAX = { year: 1500, monthIndex: 11, day: 30 };
|
||||
const GREGORIAN_MIN = { year: 1924, month: 8, day: 1 };
|
||||
const GREGORIAN_MAX = { year: 2077, month: 11, day: 16 };
|
||||
function compareGregorianDates(left, right) {
|
||||
if (left.year !== right.year) {
|
||||
return left.year - right.year;
|
||||
}
|
||||
if (left.month !== right.month) {
|
||||
return left.month - right.month;
|
||||
}
|
||||
return left.day - right.day;
|
||||
}
|
||||
function createDate(parts) {
|
||||
return new Date(parts.year, parts.month - 1, parts.day);
|
||||
}
|
||||
function normalizeHijriMonth(year, monthIndex) {
|
||||
let normalizedYear = year + Math.trunc(monthIndex / MONTHS_PER_YEAR);
|
||||
let normalizedMonth = monthIndex % MONTHS_PER_YEAR;
|
||||
if (normalizedMonth < 0) {
|
||||
normalizedMonth += MONTHS_PER_YEAR;
|
||||
normalizedYear -= 1;
|
||||
}
|
||||
return { year: normalizedYear, monthIndex: normalizedMonth };
|
||||
}
|
||||
/** Returns Gregorian date parts while preserving years < 100. */
|
||||
function getGregorianDateParts(date) {
|
||||
const useUTC = date.getFullYear() < 100;
|
||||
return {
|
||||
year: useUTC ? date.getUTCFullYear() : date.getFullYear(),
|
||||
month: (useUTC ? date.getUTCMonth() : date.getMonth()) + 1,
|
||||
day: useUTC ? date.getUTCDate() : date.getDate(),
|
||||
};
|
||||
}
|
||||
/** Internal Gregorian lower bound supported by the Hijri converter. */
|
||||
exports.GREGORIAN_MIN_DATE = createDate(GREGORIAN_MIN);
|
||||
/** Internal Gregorian upper bound supported by the Hijri converter. */
|
||||
exports.GREGORIAN_MAX_DATE = createDate(GREGORIAN_MAX);
|
||||
/** Clamp a Gregorian date to the supported Hijri conversion range. */
|
||||
function clampGregorianDate(date) {
|
||||
const parts = getGregorianDateParts(date);
|
||||
if (compareGregorianDates(parts, GREGORIAN_MIN) < 0) {
|
||||
return createDate(GREGORIAN_MIN);
|
||||
}
|
||||
if (compareGregorianDates(parts, GREGORIAN_MAX) > 0) {
|
||||
return createDate(GREGORIAN_MAX);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
/** Returns whether the provided Gregorian date was clamped. */
|
||||
function wasGregorianDateClamped(date) {
|
||||
return clampGregorianDate(date) !== date;
|
||||
}
|
||||
/** Clamp a Hijri date to the supported range and normalize month overflow. */
|
||||
function clampHijriDate(date) {
|
||||
const normalized = normalizeHijriMonth(date.year, date.monthIndex);
|
||||
const candidate = {
|
||||
year: normalized.year,
|
||||
monthIndex: normalized.monthIndex,
|
||||
day: Math.min(Math.max(date.day, 1), MAX_HIJRI_DAY),
|
||||
};
|
||||
if (candidate.year < HIJRI_MIN.year) {
|
||||
return { ...HIJRI_MIN };
|
||||
}
|
||||
if (candidate.year > HIJRI_MAX.year) {
|
||||
return { ...HIJRI_MAX };
|
||||
}
|
||||
if (candidate.year === HIJRI_MIN.year &&
|
||||
candidate.monthIndex < HIJRI_MIN.monthIndex) {
|
||||
return { ...HIJRI_MIN };
|
||||
}
|
||||
if (candidate.year === HIJRI_MAX.year &&
|
||||
candidate.monthIndex > HIJRI_MAX.monthIndex) {
|
||||
return { ...HIJRI_MAX };
|
||||
}
|
||||
if (candidate.year === HIJRI_MIN.year &&
|
||||
candidate.monthIndex === HIJRI_MIN.monthIndex &&
|
||||
candidate.day < HIJRI_MIN.day) {
|
||||
return { ...HIJRI_MIN };
|
||||
}
|
||||
if (candidate.year === HIJRI_MAX.year &&
|
||||
candidate.monthIndex === HIJRI_MAX.monthIndex &&
|
||||
candidate.day > HIJRI_MAX.day) {
|
||||
return { ...HIJRI_MAX };
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
/** Returns whether the provided Hijri date was clamped. */
|
||||
function wasHijriDateClamped(date) {
|
||||
const clamped = clampHijriDate(date);
|
||||
return (clamped.year !== date.year ||
|
||||
clamped.monthIndex !== date.monthIndex ||
|
||||
clamped.day !== date.day);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type HijriDate = {
|
||||
year: number;
|
||||
monthIndex: number;
|
||||
day: number;
|
||||
};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import type { Locale } from "date-fns";
|
||||
import React from "react";
|
||||
import { DateLib, type DateLibOptions } from "../index.js";
|
||||
import type { DayPickerProps } from "../types/props.js";
|
||||
/**
|
||||
* Render the Hijri (Umm al-Qura) calendar.
|
||||
*
|
||||
* Defaults:
|
||||
*
|
||||
* - `locale`: `ar-SA`
|
||||
* - `dir`: `rtl`
|
||||
* - `numerals`: `arab`
|
||||
* - `startMonth`: `1924-08-01`
|
||||
* - `endMonth`: `2077-11-16`
|
||||
*
|
||||
* Out-of-range date props are clamped to the supported Umm al-Qura conversion
|
||||
* range, preventing runtime conversion errors.
|
||||
*/
|
||||
export declare function DayPicker(props: DayPickerProps & {
|
||||
locale?: Locale;
|
||||
dir?: DayPickerProps["dir"];
|
||||
numerals?: DayPickerProps["numerals"];
|
||||
dateLib?: DayPickerProps["dateLib"];
|
||||
}): React.JSX.Element;
|
||||
/** Returns the date library used in the Hijri calendar. */
|
||||
export declare const getDateLib: (options?: DateLibOptions) => DateLib;
|
||||
export { arSA } from "../locale/ar-SA.js";
|
||||
export { enUS } from "../locale/en-US.js";
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
import React from "react";
|
||||
import { DateLib, DayPicker as DayPickerComponent, } from "../index.js";
|
||||
import { arSA } from "../locale/ar-SA.js";
|
||||
import * as hijriDateLib from "./lib/index.js";
|
||||
import { clampGregorianDate, GREGORIAN_MAX_DATE, GREGORIAN_MIN_DATE, } from "./utils/range.js";
|
||||
function clampDateProp(date) {
|
||||
if (!date) {
|
||||
return undefined;
|
||||
}
|
||||
return clampGregorianDate(date);
|
||||
}
|
||||
/**
|
||||
* Render the Hijri (Umm al-Qura) calendar.
|
||||
*
|
||||
* Defaults:
|
||||
*
|
||||
* - `locale`: `ar-SA`
|
||||
* - `dir`: `rtl`
|
||||
* - `numerals`: `arab`
|
||||
* - `startMonth`: `1924-08-01`
|
||||
* - `endMonth`: `2077-11-16`
|
||||
*
|
||||
* Out-of-range date props are clamped to the supported Umm al-Qura conversion
|
||||
* range, preventing runtime conversion errors.
|
||||
*/
|
||||
export function DayPicker(props) {
|
||||
const { dateLib: dateLibProp, ...dayPickerProps } = props;
|
||||
const hasStartBound = props.startMonth !== undefined ||
|
||||
props.fromMonth !== undefined ||
|
||||
props.fromYear !== undefined;
|
||||
const hasEndBound = props.endMonth !== undefined ||
|
||||
props.toMonth !== undefined ||
|
||||
props.toYear !== undefined;
|
||||
const clampedProps = {
|
||||
...dayPickerProps,
|
||||
month: clampDateProp(props.month),
|
||||
defaultMonth: clampDateProp(props.defaultMonth),
|
||||
today: clampDateProp(props.today),
|
||||
startMonth: hasStartBound
|
||||
? clampDateProp(props.startMonth)
|
||||
: new Date(GREGORIAN_MIN_DATE),
|
||||
endMonth: hasEndBound
|
||||
? clampDateProp(props.endMonth)
|
||||
: new Date(GREGORIAN_MAX_DATE),
|
||||
fromMonth: clampDateProp(props.fromMonth),
|
||||
toMonth: clampDateProp(props.toMonth),
|
||||
};
|
||||
return (React.createElement(DayPickerComponent, { ...clampedProps, locale: props.locale ?? arSA, numerals: props.numerals ?? "arab", dir: props.dir ?? "rtl", dateLib: { ...hijriDateLib, ...dateLibProp } }));
|
||||
}
|
||||
/** Returns the date library used in the Hijri calendar. */
|
||||
export const getDateLib = (options) => {
|
||||
return new DateLib(options, hijriDateLib);
|
||||
};
|
||||
export { arSA } from "../locale/ar-SA.js";
|
||||
export { enUS } from "../locale/en-US.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function addMonths(date: Date, amount: number): Date;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
import { setMonth } from "./setMonth.js";
|
||||
export function addMonths(date, amount) {
|
||||
const hijri = toHijriDate(date);
|
||||
return setMonth(date, hijri.monthIndex + amount);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function addYears(date: Date, amount: number): Date;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
import { setYear } from "./setYear.js";
|
||||
export function addYears(date, amount) {
|
||||
const hijri = toHijriDate(date);
|
||||
return setYear(date, hijri.year + amount);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function differenceInCalendarMonths(dateLeft: Date, dateRight: Date): number;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
export function differenceInCalendarMonths(dateLeft, dateRight) {
|
||||
const hijriLeft = toHijriDate(dateLeft);
|
||||
const hijriRight = toHijriDate(dateRight);
|
||||
return ((hijriLeft.year - hijriRight.year) * 12 +
|
||||
(hijriLeft.monthIndex - hijriRight.monthIndex));
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
import { type Interval } from "date-fns";
|
||||
export declare function eachMonthOfInterval(interval: Interval): Date[];
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { toDate } from "date-fns";
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
export function eachMonthOfInterval(interval) {
|
||||
const start = toDate(interval.start);
|
||||
const end = toDate(interval.end);
|
||||
if (end.getTime() < start.getTime()) {
|
||||
throw new RangeError("Invalid interval");
|
||||
}
|
||||
const startDate = toHijriDate(start);
|
||||
const endDate = toHijriDate(end);
|
||||
const months = [];
|
||||
let currentYear = startDate.year;
|
||||
let currentMonth = startDate.monthIndex;
|
||||
const endYear = endDate.year;
|
||||
const endMonth = endDate.monthIndex;
|
||||
while (currentYear < endYear ||
|
||||
(currentYear === endYear && currentMonth <= endMonth)) {
|
||||
months.push(toGregorianDate({ year: currentYear, monthIndex: currentMonth, day: 1 }));
|
||||
currentMonth += 1;
|
||||
if (currentMonth > 11) {
|
||||
currentMonth = 0;
|
||||
currentYear += 1;
|
||||
}
|
||||
}
|
||||
return months;
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
import { type Interval } from "date-fns";
|
||||
export declare function eachYearOfInterval(interval: Interval): Date[];
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { toDate } from "date-fns";
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
export function eachYearOfInterval(interval) {
|
||||
const start = toDate(interval.start);
|
||||
const end = toDate(interval.end);
|
||||
if (end.getTime() < start.getTime()) {
|
||||
return [];
|
||||
}
|
||||
const startYear = toHijriDate(start).year;
|
||||
const endYear = toHijriDate(end).year;
|
||||
const years = [];
|
||||
for (let year = startYear; year <= endYear; year += 1) {
|
||||
years.push(toGregorianDate({ year, monthIndex: 0, day: 1 }));
|
||||
}
|
||||
return years;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function endOfMonth(date: Date): Date;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
import { getDaysInMonth } from "../utils/daysInMonth.js";
|
||||
export function endOfMonth(date) {
|
||||
const hijri = toHijriDate(date);
|
||||
const day = getDaysInMonth(hijri.year, hijri.monthIndex);
|
||||
return toGregorianDate({
|
||||
year: hijri.year,
|
||||
monthIndex: hijri.monthIndex,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function endOfYear(date: Date): Date;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
import { getDaysInMonth } from "../utils/daysInMonth.js";
|
||||
export function endOfYear(date) {
|
||||
const hijri = toHijriDate(date);
|
||||
const day = getDaysInMonth(hijri.year, 11);
|
||||
return toGregorianDate({
|
||||
year: hijri.year,
|
||||
monthIndex: 11,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type FallbackLocaleCode = "ar" | "en";
|
||||
export type IntlNameWidth = "long" | "short" | "narrow";
|
||||
export declare const getFallbackLocaleCode: (localeCode: string) => FallbackLocaleCode;
|
||||
export declare const getFallbackMonthName: (date: Date, localeCode: string, width: IntlNameWidth) => string;
|
||||
export declare const getFallbackWeekdayName: (date: Date, localeCode: string, width: IntlNameWidth) => string;
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
const fallbackMonthNames = {
|
||||
en: {
|
||||
long: [
|
||||
"Muharram",
|
||||
"Safar",
|
||||
"Rabi I",
|
||||
"Rabi II",
|
||||
"Jumada I",
|
||||
"Jumada II",
|
||||
"Rajab",
|
||||
"Shaban",
|
||||
"Ramadan",
|
||||
"Shawwal",
|
||||
"Dhu al-Qadah",
|
||||
"Dhu al-Hijjah",
|
||||
],
|
||||
short: [
|
||||
"Muh",
|
||||
"Saf",
|
||||
"Rab-I",
|
||||
"Rab-II",
|
||||
"Jum-I",
|
||||
"Jum-II",
|
||||
"Raj",
|
||||
"Sha",
|
||||
"Ram",
|
||||
"Shw",
|
||||
"Dhu-Q",
|
||||
"Dhu-H",
|
||||
],
|
||||
narrow: ["M", "S", "R", "R", "J", "J", "R", "S", "R", "S", "D", "D"],
|
||||
},
|
||||
ar: {
|
||||
long: [
|
||||
"محرم",
|
||||
"صفر",
|
||||
"ربيع الأول",
|
||||
"ربيع الآخر",
|
||||
"جمادى الأولى",
|
||||
"جمادى الآخرة",
|
||||
"رجب",
|
||||
"شعبان",
|
||||
"رمضان",
|
||||
"شوال",
|
||||
"ذو القعدة",
|
||||
"ذو الحجة",
|
||||
],
|
||||
short: [
|
||||
"محرم",
|
||||
"صفر",
|
||||
"ربيع ١",
|
||||
"ربيع ٢",
|
||||
"جمادى ١",
|
||||
"جمادى ٢",
|
||||
"رجب",
|
||||
"شعبان",
|
||||
"رمضان",
|
||||
"شوال",
|
||||
"ذو القعدة",
|
||||
"ذو الحجة",
|
||||
],
|
||||
narrow: ["م", "ص", "ر", "ر", "ج", "ج", "ر", "ش", "ر", "ش", "ذ", "ذ"],
|
||||
},
|
||||
};
|
||||
const fallbackWeekdayNames = {
|
||||
en: {
|
||||
long: [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
],
|
||||
short: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||
narrow: ["S", "M", "T", "W", "T", "F", "S"],
|
||||
},
|
||||
ar: {
|
||||
long: [
|
||||
"الأحد",
|
||||
"الاثنين",
|
||||
"الثلاثاء",
|
||||
"الأربعاء",
|
||||
"الخميس",
|
||||
"الجمعة",
|
||||
"السبت",
|
||||
],
|
||||
short: ["أحد", "اثن", "ثلا", "أرب", "خمي", "جمع", "سبت"],
|
||||
narrow: ["ح", "ن", "ث", "ر", "خ", "ج", "س"],
|
||||
},
|
||||
};
|
||||
export const getFallbackLocaleCode = (localeCode) => {
|
||||
return localeCode.toLowerCase().startsWith("ar") ? "ar" : "en";
|
||||
};
|
||||
export const getFallbackMonthName = (date, localeCode, width) => {
|
||||
const hijri = toHijriDate(date);
|
||||
const locale = getFallbackLocaleCode(localeCode);
|
||||
return fallbackMonthNames[locale][width][hijri.monthIndex];
|
||||
};
|
||||
export const getFallbackWeekdayName = (date, localeCode, width) => {
|
||||
const locale = getFallbackLocaleCode(localeCode);
|
||||
return fallbackWeekdayNames[locale][width][date.getDay()];
|
||||
};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import type { FormatOptions as DateFnsFormatOptions } from "date-fns";
|
||||
/** Hijri calendar formatting override. */
|
||||
export declare function format(date: Date, formatStr: string, options?: DateFnsFormatOptions): string;
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
import { clampGregorianDate, getGregorianDateParts } from "../utils/range.js";
|
||||
import { getFallbackMonthName, getFallbackWeekdayName, } from "./fallbackLocaleData.js";
|
||||
const DEFAULT_LOCALE_CODE = "ar-SA";
|
||||
const BASE_NUMBERING_SYSTEM = "latn";
|
||||
const UMM_AL_QURA_CALENDAR = "islamic-umalqura";
|
||||
const getLocaleCode = (options) => {
|
||||
return options?.locale?.code ?? DEFAULT_LOCALE_CODE;
|
||||
};
|
||||
const formatWithUmmAlQura = (date, localeCode, options) => {
|
||||
try {
|
||||
return new Intl.DateTimeFormat(localeCode, {
|
||||
...options,
|
||||
calendar: UMM_AL_QURA_CALENDAR,
|
||||
numberingSystem: BASE_NUMBERING_SYSTEM,
|
||||
}).format(date);
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
const formatNumber = (value) => {
|
||||
return value.toString();
|
||||
};
|
||||
const formatPaddedNumber = (value) => {
|
||||
return formatNumber(value).padStart(2, "0");
|
||||
};
|
||||
const formatMonthName = (date, localeCode, width) => {
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
month: width,
|
||||
});
|
||||
return formatted ?? getFallbackMonthName(date, localeCode, width);
|
||||
};
|
||||
const formatWeekdayName = (date, localeCode, width) => {
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
weekday: width,
|
||||
});
|
||||
return formatted ?? getFallbackWeekdayName(date, localeCode, width);
|
||||
};
|
||||
const formatDateStyle = (date, localeCode, style) => {
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
dateStyle: style,
|
||||
});
|
||||
if (formatted) {
|
||||
return formatted;
|
||||
}
|
||||
const hijri = toHijriDate(date);
|
||||
const monthName = getFallbackMonthName(date, localeCode, "long");
|
||||
switch (style) {
|
||||
case "full":
|
||||
return `${getFallbackWeekdayName(date, localeCode, "long")}, ${monthName} ${hijri.day}, ${hijri.year}`;
|
||||
case "long":
|
||||
return `${monthName} ${hijri.day}, ${hijri.year}`;
|
||||
case "medium":
|
||||
return `${formatPaddedNumber(hijri.day)} ${monthName} ${hijri.year}`;
|
||||
case "short":
|
||||
return `${hijri.monthIndex + 1}/${hijri.day}/${hijri.year}`;
|
||||
}
|
||||
};
|
||||
const buildTimeFormat = (date, localeCode, formatStr) => {
|
||||
const hour12 = formatStr.includes("a");
|
||||
const formatted = formatWithUmmAlQura(date, localeCode, {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12,
|
||||
});
|
||||
if (formatted) {
|
||||
return formatted;
|
||||
}
|
||||
try {
|
||||
return new Intl.DateTimeFormat(localeCode, {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12,
|
||||
numberingSystem: BASE_NUMBERING_SYSTEM,
|
||||
}).format(date);
|
||||
}
|
||||
catch {
|
||||
const minutes = formatPaddedNumber(date.getMinutes());
|
||||
if (hour12) {
|
||||
const hour = date.getHours() % 12 || 12;
|
||||
const period = date.getHours() >= 12 ? "PM" : "AM";
|
||||
return `${hour}:${minutes} ${period}`;
|
||||
}
|
||||
return `${formatNumber(date.getHours())}:${minutes}`;
|
||||
}
|
||||
};
|
||||
/** Hijri calendar formatting override. */
|
||||
export function format(date, formatStr, options) {
|
||||
const extendedOptions = options;
|
||||
const localeCode = getLocaleCode(extendedOptions);
|
||||
const hijri = toHijriDate(date);
|
||||
const gregorian = getGregorianDateParts(date);
|
||||
const isOutOfRange = clampGregorianDate(date) !== date;
|
||||
const numericDate = isOutOfRange
|
||||
? {
|
||||
year: gregorian.year,
|
||||
monthIndex: gregorian.month - 1,
|
||||
day: gregorian.day,
|
||||
}
|
||||
: hijri;
|
||||
switch (formatStr) {
|
||||
case "LLLL y":
|
||||
case "LLLL yyyy":
|
||||
return `${formatMonthName(date, localeCode, "long")} ${formatNumber(numericDate.year)}`;
|
||||
case "LLLL":
|
||||
return formatMonthName(date, localeCode, "long");
|
||||
case "LLL":
|
||||
return formatMonthName(date, localeCode, "short");
|
||||
case "PPP":
|
||||
return formatDateStyle(date, localeCode, "long");
|
||||
case "PPPP":
|
||||
return formatDateStyle(date, localeCode, "full");
|
||||
case "PP":
|
||||
return formatDateStyle(date, localeCode, "medium");
|
||||
case "P":
|
||||
return formatDateStyle(date, localeCode, "short");
|
||||
case "cccc":
|
||||
return formatWeekdayName(date, localeCode, "long");
|
||||
case "ccc":
|
||||
return formatWeekdayName(date, localeCode, "short");
|
||||
case "ccccc":
|
||||
case "cccccc":
|
||||
return formatWeekdayName(date, localeCode, "narrow");
|
||||
case "yyyy":
|
||||
case "y":
|
||||
return formatNumber(numericDate.year);
|
||||
case "yyyy-MM":
|
||||
return `${formatNumber(numericDate.year)}-${formatPaddedNumber(numericDate.monthIndex + 1)}`;
|
||||
case "yyyy-MM-dd":
|
||||
return `${formatNumber(numericDate.year)}-${formatPaddedNumber(numericDate.monthIndex + 1)}-${formatPaddedNumber(numericDate.day)}`;
|
||||
case "MM":
|
||||
return formatPaddedNumber(numericDate.monthIndex + 1);
|
||||
case "M":
|
||||
return formatNumber(numericDate.monthIndex + 1);
|
||||
case "dd":
|
||||
return formatPaddedNumber(numericDate.day);
|
||||
case "d":
|
||||
return formatNumber(numericDate.day);
|
||||
default:
|
||||
if (/[Hh]/.test(formatStr) && /m/.test(formatStr)) {
|
||||
return buildTimeFormat(date, localeCode, formatStr);
|
||||
}
|
||||
return formatDateStyle(date, localeCode, "medium");
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function getMonth(date: Date): number;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
export function getMonth(date) {
|
||||
return toHijriDate(date).monthIndex;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function getYear(date: Date): number;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
export function getYear(date) {
|
||||
return toHijriDate(date).year;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
export * from "./addMonths.js";
|
||||
export * from "./addYears.js";
|
||||
export * from "./differenceInCalendarMonths.js";
|
||||
export * from "./eachMonthOfInterval.js";
|
||||
export * from "./eachYearOfInterval.js";
|
||||
export * from "./endOfMonth.js";
|
||||
export * from "./endOfYear.js";
|
||||
export * from "./format.js";
|
||||
export * from "./getMonth.js";
|
||||
export * from "./getYear.js";
|
||||
export * from "./isSameMonth.js";
|
||||
export * from "./isSameYear.js";
|
||||
export * from "./newDate.js";
|
||||
export * from "./setMonth.js";
|
||||
export * from "./setYear.js";
|
||||
export * from "./startOfMonth.js";
|
||||
export * from "./startOfYear.js";
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
export * from "./addMonths.js";
|
||||
export * from "./addYears.js";
|
||||
export * from "./differenceInCalendarMonths.js";
|
||||
export * from "./eachMonthOfInterval.js";
|
||||
export * from "./eachYearOfInterval.js";
|
||||
export * from "./endOfMonth.js";
|
||||
export * from "./endOfYear.js";
|
||||
export * from "./format.js";
|
||||
export * from "./getMonth.js";
|
||||
export * from "./getYear.js";
|
||||
export * from "./isSameMonth.js";
|
||||
export * from "./isSameYear.js";
|
||||
export * from "./newDate.js";
|
||||
export * from "./setMonth.js";
|
||||
export * from "./setYear.js";
|
||||
export * from "./startOfMonth.js";
|
||||
export * from "./startOfYear.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function isSameMonth(dateLeft: Date, dateRight: Date): boolean;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
export function isSameMonth(dateLeft, dateRight) {
|
||||
const hijriLeft = toHijriDate(dateLeft);
|
||||
const hijriRight = toHijriDate(dateRight);
|
||||
return (hijriLeft.year === hijriRight.year &&
|
||||
hijriLeft.monthIndex === hijriRight.monthIndex);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function isSameYear(dateLeft: Date, dateRight: Date): boolean;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { toHijriDate } from "../utils/conversion.js";
|
||||
export function isSameYear(dateLeft, dateRight) {
|
||||
const hijriLeft = toHijriDate(dateLeft);
|
||||
const hijriRight = toHijriDate(dateRight);
|
||||
return hijriLeft.year === hijriRight.year;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function newDate(year: number, monthIndex: number, day: number): Date;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { toGregorianDate } from "../utils/conversion.js";
|
||||
export function newDate(year, monthIndex, day) {
|
||||
return toGregorianDate({ year, monthIndex, day });
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function setMonth(date: Date, monthIndex: number): Date;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
import { getDaysInMonth } from "../utils/daysInMonth.js";
|
||||
export function setMonth(date, monthIndex) {
|
||||
const hijri = toHijriDate(date);
|
||||
// Handle overflow/underflow of monthIndex
|
||||
// Note: monthIndex argument is absolute month index for the year.
|
||||
// E.g. setMonth(..., 13) sets to Safar next year.
|
||||
let targetYear = hijri.year;
|
||||
let targetMonth = monthIndex;
|
||||
if (targetMonth > 11 || targetMonth < 0) {
|
||||
targetYear += Math.floor(targetMonth / 12);
|
||||
targetMonth = targetMonth % 12;
|
||||
if (targetMonth < 0) {
|
||||
targetMonth += 12;
|
||||
}
|
||||
}
|
||||
const daysInTargetMonth = getDaysInMonth(targetYear, targetMonth);
|
||||
const day = Math.min(hijri.day, daysInTargetMonth);
|
||||
return toGregorianDate({
|
||||
year: targetYear,
|
||||
monthIndex: targetMonth,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function setYear(date: Date, year: number): Date;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
import { getDaysInMonth } from "../utils/daysInMonth.js";
|
||||
export function setYear(date, year) {
|
||||
const hijri = toHijriDate(date);
|
||||
const daysInTargetMonth = getDaysInMonth(year, hijri.monthIndex);
|
||||
const day = Math.min(hijri.day, daysInTargetMonth);
|
||||
return toGregorianDate({
|
||||
year,
|
||||
monthIndex: hijri.monthIndex,
|
||||
day,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function startOfMonth(date: Date): Date;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
export function startOfMonth(date) {
|
||||
const hijri = toHijriDate(date);
|
||||
return toGregorianDate({
|
||||
year: hijri.year,
|
||||
monthIndex: hijri.monthIndex,
|
||||
day: 1,
|
||||
});
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function startOfYear(date: Date): Date;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { toGregorianDate, toHijriDate } from "../utils/conversion.js";
|
||||
export function startOfYear(date) {
|
||||
const hijri = toHijriDate(date);
|
||||
return toGregorianDate({
|
||||
year: hijri.year,
|
||||
monthIndex: 0,
|
||||
day: 1,
|
||||
});
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type { HijriDate } from "./types.js";
|
||||
/** Convert a Gregorian date to a Hijri date. */
|
||||
export declare function toHijriDate(date: Date): HijriDate;
|
||||
/** Convert a Hijri date back to the Gregorian calendar. */
|
||||
export declare function toGregorianDate(hijri: HijriDate): Date;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { gregorianToHijri, hijriToGregorian } from "@tabby_ai/hijri-converter";
|
||||
import { clampGregorianDate, clampHijriDate, GREGORIAN_MIN_DATE, getGregorianDateParts, } from "./range.js";
|
||||
/** Convert a Gregorian date to a Hijri date. */
|
||||
export function toHijriDate(date) {
|
||||
const clamped = clampGregorianDate(date);
|
||||
const { year, month, day } = getGregorianDateParts(clamped);
|
||||
// gregorianToHijri uses 1-indexed months
|
||||
const hijri = gregorianToHijri({ year, month, day });
|
||||
return {
|
||||
year: hijri.year,
|
||||
monthIndex: hijri.month - 1, // Convert to 0-indexed
|
||||
day: hijri.day,
|
||||
};
|
||||
}
|
||||
/** Convert a Hijri date back to the Gregorian calendar. */
|
||||
export function toGregorianDate(hijri) {
|
||||
const clamped = clampHijriDate(hijri);
|
||||
// hijriToGregorian expects 1-indexed months. Probe down from the candidate
|
||||
// day to handle invalid month/day combinations without throwing.
|
||||
for (let day = clamped.day; day >= 1; day -= 1) {
|
||||
try {
|
||||
const gregorian = hijriToGregorian({
|
||||
year: clamped.year,
|
||||
month: clamped.monthIndex + 1,
|
||||
day,
|
||||
});
|
||||
return clampGregorianDate(new Date(gregorian.year, gregorian.month - 1, gregorian.day));
|
||||
}
|
||||
catch {
|
||||
// Try a lower day for months that only have 29 days.
|
||||
}
|
||||
}
|
||||
// Fallback to the minimum supported Gregorian date if conversion probing
|
||||
// somehow fails for all days.
|
||||
return new Date(GREGORIAN_MIN_DATE);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare function getDaysInMonth(year: number, monthIndex: number): number;
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { toGregorianDate, toHijriDate } from "./conversion.js";
|
||||
import { clampHijriDate } from "./range.js";
|
||||
const MAX_DAY_IN_HIJRI_MONTH = 30;
|
||||
const MIN_DAY_IN_HIJRI_MONTH = 29;
|
||||
export function getDaysInMonth(year, monthIndex) {
|
||||
const clamped = clampHijriDate({ year, monthIndex, day: 1 });
|
||||
for (let day = MAX_DAY_IN_HIJRI_MONTH; day >= MIN_DAY_IN_HIJRI_MONTH; day -= 1) {
|
||||
const candidateDate = toGregorianDate({
|
||||
year: clamped.year,
|
||||
monthIndex: clamped.monthIndex,
|
||||
day,
|
||||
});
|
||||
const roundTrip = toHijriDate(candidateDate);
|
||||
if (roundTrip.year === clamped.year &&
|
||||
roundTrip.monthIndex === clamped.monthIndex &&
|
||||
roundTrip.day === day) {
|
||||
return day;
|
||||
}
|
||||
}
|
||||
return MIN_DAY_IN_HIJRI_MONTH;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import type { HijriDate } from "./types.js";
|
||||
type GregorianDateParts = {
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
};
|
||||
/** Returns Gregorian date parts while preserving years < 100. */
|
||||
export declare function getGregorianDateParts(date: Date): GregorianDateParts;
|
||||
/** Internal Gregorian lower bound supported by the Hijri converter. */
|
||||
export declare const GREGORIAN_MIN_DATE: Date;
|
||||
/** Internal Gregorian upper bound supported by the Hijri converter. */
|
||||
export declare const GREGORIAN_MAX_DATE: Date;
|
||||
/** Clamp a Gregorian date to the supported Hijri conversion range. */
|
||||
export declare function clampGregorianDate(date: Date): Date;
|
||||
/** Returns whether the provided Gregorian date was clamped. */
|
||||
export declare function wasGregorianDateClamped(date: Date): boolean;
|
||||
/** Clamp a Hijri date to the supported range and normalize month overflow. */
|
||||
export declare function clampHijriDate(date: HijriDate): HijriDate;
|
||||
/** Returns whether the provided Hijri date was clamped. */
|
||||
export declare function wasHijriDateClamped(date: HijriDate): boolean;
|
||||
export {};
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
const MAX_HIJRI_DAY = 30;
|
||||
const MONTHS_PER_YEAR = 12;
|
||||
const HIJRI_MIN = { year: 1343, monthIndex: 0, day: 1 };
|
||||
const HIJRI_MAX = { year: 1500, monthIndex: 11, day: 30 };
|
||||
const GREGORIAN_MIN = { year: 1924, month: 8, day: 1 };
|
||||
const GREGORIAN_MAX = { year: 2077, month: 11, day: 16 };
|
||||
function compareGregorianDates(left, right) {
|
||||
if (left.year !== right.year) {
|
||||
return left.year - right.year;
|
||||
}
|
||||
if (left.month !== right.month) {
|
||||
return left.month - right.month;
|
||||
}
|
||||
return left.day - right.day;
|
||||
}
|
||||
function createDate(parts) {
|
||||
return new Date(parts.year, parts.month - 1, parts.day);
|
||||
}
|
||||
function normalizeHijriMonth(year, monthIndex) {
|
||||
let normalizedYear = year + Math.trunc(monthIndex / MONTHS_PER_YEAR);
|
||||
let normalizedMonth = monthIndex % MONTHS_PER_YEAR;
|
||||
if (normalizedMonth < 0) {
|
||||
normalizedMonth += MONTHS_PER_YEAR;
|
||||
normalizedYear -= 1;
|
||||
}
|
||||
return { year: normalizedYear, monthIndex: normalizedMonth };
|
||||
}
|
||||
/** Returns Gregorian date parts while preserving years < 100. */
|
||||
export function getGregorianDateParts(date) {
|
||||
const useUTC = date.getFullYear() < 100;
|
||||
return {
|
||||
year: useUTC ? date.getUTCFullYear() : date.getFullYear(),
|
||||
month: (useUTC ? date.getUTCMonth() : date.getMonth()) + 1,
|
||||
day: useUTC ? date.getUTCDate() : date.getDate(),
|
||||
};
|
||||
}
|
||||
/** Internal Gregorian lower bound supported by the Hijri converter. */
|
||||
export const GREGORIAN_MIN_DATE = createDate(GREGORIAN_MIN);
|
||||
/** Internal Gregorian upper bound supported by the Hijri converter. */
|
||||
export const GREGORIAN_MAX_DATE = createDate(GREGORIAN_MAX);
|
||||
/** Clamp a Gregorian date to the supported Hijri conversion range. */
|
||||
export function clampGregorianDate(date) {
|
||||
const parts = getGregorianDateParts(date);
|
||||
if (compareGregorianDates(parts, GREGORIAN_MIN) < 0) {
|
||||
return createDate(GREGORIAN_MIN);
|
||||
}
|
||||
if (compareGregorianDates(parts, GREGORIAN_MAX) > 0) {
|
||||
return createDate(GREGORIAN_MAX);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
/** Returns whether the provided Gregorian date was clamped. */
|
||||
export function wasGregorianDateClamped(date) {
|
||||
return clampGregorianDate(date) !== date;
|
||||
}
|
||||
/** Clamp a Hijri date to the supported range and normalize month overflow. */
|
||||
export function clampHijriDate(date) {
|
||||
const normalized = normalizeHijriMonth(date.year, date.monthIndex);
|
||||
const candidate = {
|
||||
year: normalized.year,
|
||||
monthIndex: normalized.monthIndex,
|
||||
day: Math.min(Math.max(date.day, 1), MAX_HIJRI_DAY),
|
||||
};
|
||||
if (candidate.year < HIJRI_MIN.year) {
|
||||
return { ...HIJRI_MIN };
|
||||
}
|
||||
if (candidate.year > HIJRI_MAX.year) {
|
||||
return { ...HIJRI_MAX };
|
||||
}
|
||||
if (candidate.year === HIJRI_MIN.year &&
|
||||
candidate.monthIndex < HIJRI_MIN.monthIndex) {
|
||||
return { ...HIJRI_MIN };
|
||||
}
|
||||
if (candidate.year === HIJRI_MAX.year &&
|
||||
candidate.monthIndex > HIJRI_MAX.monthIndex) {
|
||||
return { ...HIJRI_MAX };
|
||||
}
|
||||
if (candidate.year === HIJRI_MIN.year &&
|
||||
candidate.monthIndex === HIJRI_MIN.monthIndex &&
|
||||
candidate.day < HIJRI_MIN.day) {
|
||||
return { ...HIJRI_MIN };
|
||||
}
|
||||
if (candidate.year === HIJRI_MAX.year &&
|
||||
candidate.monthIndex === HIJRI_MAX.monthIndex &&
|
||||
candidate.day > HIJRI_MAX.day) {
|
||||
return { ...HIJRI_MAX };
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
/** Returns whether the provided Hijri date was clamped. */
|
||||
export function wasHijriDateClamped(date) {
|
||||
const clamped = clampHijriDate(date);
|
||||
return (clamped.year !== date.year ||
|
||||
clamped.monthIndex !== date.monthIndex ||
|
||||
clamped.day !== date.day);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export type HijriDate = {
|
||||
year: number;
|
||||
monthIndex: number;
|
||||
day: number;
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user