651 lines
19 KiB
JavaScript
651 lines
19 KiB
JavaScript
(function () {
|
||
"use strict";
|
||
|
||
const HEBREW_MONTH_ALIAS_BY_ID = {
|
||
nisan: ["nisan"],
|
||
iyar: ["iyar"],
|
||
sivan: ["sivan"],
|
||
tammuz: ["tamuz", "tammuz"],
|
||
av: ["av"],
|
||
elul: ["elul"],
|
||
tishrei: ["tishri", "tishrei"],
|
||
cheshvan: ["heshvan", "cheshvan", "marcheshvan"],
|
||
kislev: ["kislev"],
|
||
tevet: ["tevet"],
|
||
shvat: ["shevat", "shvat"],
|
||
adar: ["adar", "adar i", "adar 1"],
|
||
"adar-ii": ["adar ii", "adar 2"]
|
||
};
|
||
|
||
const MONTH_NAME_TO_INDEX = {
|
||
january: 0,
|
||
february: 1,
|
||
march: 2,
|
||
april: 3,
|
||
may: 4,
|
||
june: 5,
|
||
july: 6,
|
||
august: 7,
|
||
september: 8,
|
||
october: 9,
|
||
november: 10,
|
||
december: 11
|
||
};
|
||
|
||
const GREGORIAN_MONTH_ID_TO_ORDER = {
|
||
january: 1,
|
||
february: 2,
|
||
march: 3,
|
||
april: 4,
|
||
may: 5,
|
||
june: 6,
|
||
july: 7,
|
||
august: 8,
|
||
september: 9,
|
||
october: 10,
|
||
november: 11,
|
||
december: 12
|
||
};
|
||
|
||
let config = {};
|
||
|
||
function getSelectedYear() {
|
||
return Number(config.getSelectedYear?.()) || new Date().getFullYear();
|
||
}
|
||
|
||
function getSelectedCalendar() {
|
||
return String(config.getSelectedCalendar?.() || "gregorian").trim().toLowerCase();
|
||
}
|
||
|
||
function getIslamicMonths() {
|
||
return config.getIslamicMonths?.() || [];
|
||
}
|
||
|
||
function parseMonthDayToken(token) {
|
||
const [month, day] = String(token || "").split("-").map((part) => Number(part));
|
||
if (!Number.isFinite(month) || !Number.isFinite(day)) {
|
||
return null;
|
||
}
|
||
return { month, day };
|
||
}
|
||
|
||
function monthDayDate(monthDay, year) {
|
||
const parsed = parseMonthDayToken(monthDay);
|
||
if (!parsed) {
|
||
return null;
|
||
}
|
||
return new Date(year, parsed.month - 1, parsed.day);
|
||
}
|
||
|
||
function buildSignDateBounds(sign) {
|
||
const start = monthDayDate(sign?.start, 2025);
|
||
const endBase = monthDayDate(sign?.end, 2025);
|
||
if (!start || !endBase) {
|
||
return null;
|
||
}
|
||
|
||
const wrapsYear = endBase.getTime() < start.getTime();
|
||
const end = wrapsYear ? monthDayDate(sign?.end, 2026) : endBase;
|
||
if (!end) {
|
||
return null;
|
||
}
|
||
|
||
return { start, end };
|
||
}
|
||
|
||
function addDays(date, days) {
|
||
const next = new Date(date);
|
||
next.setDate(next.getDate() + days);
|
||
return next;
|
||
}
|
||
|
||
function formatDateLabel(date) {
|
||
return date.toLocaleDateString(undefined, { month: "short", day: "numeric" });
|
||
}
|
||
|
||
function monthDayOrdinal(month, day) {
|
||
if (!Number.isFinite(month) || !Number.isFinite(day)) {
|
||
return null;
|
||
}
|
||
const base = new Date(2025, Math.trunc(month) - 1, Math.trunc(day), 12, 0, 0, 0);
|
||
if (Number.isNaN(base.getTime())) {
|
||
return null;
|
||
}
|
||
const start = new Date(2025, 0, 1, 12, 0, 0, 0);
|
||
const diff = base.getTime() - start.getTime();
|
||
return Math.floor(diff / (24 * 60 * 60 * 1000)) + 1;
|
||
}
|
||
|
||
function isMonthDayInRange(targetMonth, targetDay, startMonth, startDay, endMonth, endDay) {
|
||
const target = monthDayOrdinal(targetMonth, targetDay);
|
||
const start = monthDayOrdinal(startMonth, startDay);
|
||
const end = monthDayOrdinal(endMonth, endDay);
|
||
if (!Number.isFinite(target) || !Number.isFinite(start) || !Number.isFinite(end)) {
|
||
return false;
|
||
}
|
||
|
||
if (end >= start) {
|
||
return target >= start && target <= end;
|
||
}
|
||
return target >= start || target <= end;
|
||
}
|
||
|
||
function parseMonthDayTokensFromText(value) {
|
||
const text = String(value || "");
|
||
const matches = [...text.matchAll(/(\d{2})-(\d{2})/g)];
|
||
return matches
|
||
.map((match) => ({ month: Number(match[1]), day: Number(match[2]) }))
|
||
.filter((token) => Number.isFinite(token.month) && Number.isFinite(token.day));
|
||
}
|
||
|
||
function parseDayRangeFromText(value) {
|
||
const text = String(value || "");
|
||
const range = text.match(/\b(\d{1,2})\s*[–-]\s*(\d{1,2})\b/);
|
||
if (!range) {
|
||
return null;
|
||
}
|
||
|
||
const startDay = Number(range[1]);
|
||
const endDay = Number(range[2]);
|
||
if (!Number.isFinite(startDay) || !Number.isFinite(endDay)) {
|
||
return null;
|
||
}
|
||
|
||
return { startDay, endDay };
|
||
}
|
||
|
||
function isoToDateAtNoon(iso) {
|
||
const text = String(iso || "").trim();
|
||
if (!text) {
|
||
return null;
|
||
}
|
||
const parsed = new Date(`${text}T12:00:00`);
|
||
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
||
}
|
||
|
||
function getDaysInMonth(year, monthOrder) {
|
||
if (!Number.isFinite(year) || !Number.isFinite(monthOrder)) {
|
||
return null;
|
||
}
|
||
return new Date(year, monthOrder, 0).getDate();
|
||
}
|
||
|
||
function getMonthStartWeekday(year, monthOrder) {
|
||
const date = new Date(year, monthOrder - 1, 1);
|
||
return date.toLocaleDateString(undefined, { weekday: "long" });
|
||
}
|
||
|
||
function parseMonthRange(month) {
|
||
const startText = String(month?.start || "").trim();
|
||
const endText = String(month?.end || "").trim();
|
||
if (!startText || !endText) {
|
||
return "--";
|
||
}
|
||
return `${startText} to ${endText}`;
|
||
}
|
||
|
||
function getGregorianMonthOrderFromId(monthId) {
|
||
if (!monthId) {
|
||
return null;
|
||
}
|
||
const key = String(monthId).trim().toLowerCase();
|
||
const value = GREGORIAN_MONTH_ID_TO_ORDER[key];
|
||
return Number.isFinite(value) ? value : null;
|
||
}
|
||
|
||
function normalizeCalendarText(value) {
|
||
return String(value || "")
|
||
.normalize("NFKD")
|
||
.replace(/[\u0300-\u036f]/g, "")
|
||
.replace(/['`´ʻ’]/g, "")
|
||
.toLowerCase()
|
||
.replace(/[^a-z0-9]+/g, " ")
|
||
.trim();
|
||
}
|
||
|
||
function readNumericPart(parts, partType) {
|
||
const raw = parts.find((part) => part.type === partType)?.value;
|
||
if (!raw) {
|
||
return null;
|
||
}
|
||
|
||
const digits = String(raw).replace(/[^0-9]/g, "");
|
||
if (!digits) {
|
||
return null;
|
||
}
|
||
|
||
const parsed = Number(digits);
|
||
return Number.isFinite(parsed) ? parsed : null;
|
||
}
|
||
|
||
function formatGregorianReferenceDate(date) {
|
||
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
||
return "--";
|
||
}
|
||
|
||
return date.toLocaleDateString(undefined, {
|
||
weekday: "long",
|
||
year: "numeric",
|
||
month: "long",
|
||
day: "numeric"
|
||
});
|
||
}
|
||
|
||
function formatCalendarDateFromGregorian(date, calendarId) {
|
||
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
||
return "--";
|
||
}
|
||
|
||
const locale = calendarId === "hebrew"
|
||
? "en-u-ca-hebrew"
|
||
: (calendarId === "islamic" ? "en-u-ca-islamic" : "en");
|
||
|
||
return new Intl.DateTimeFormat(locale, {
|
||
weekday: "long",
|
||
year: "numeric",
|
||
month: "long",
|
||
day: "numeric"
|
||
}).format(date);
|
||
}
|
||
|
||
function getGregorianMonthStartDate(monthOrder, year = getSelectedYear()) {
|
||
if (!Number.isFinite(monthOrder) || !Number.isFinite(year)) {
|
||
return null;
|
||
}
|
||
|
||
return new Date(Math.trunc(year), Math.trunc(monthOrder) - 1, 1, 12, 0, 0, 0);
|
||
}
|
||
|
||
function getHebrewMonthAliases(month) {
|
||
const aliases = [];
|
||
const idAliases = HEBREW_MONTH_ALIAS_BY_ID[String(month?.id || "").toLowerCase()] || [];
|
||
aliases.push(...idAliases);
|
||
|
||
const nameAlias = normalizeCalendarText(month?.name);
|
||
if (nameAlias) {
|
||
aliases.push(nameAlias);
|
||
}
|
||
|
||
return Array.from(new Set(aliases.map((alias) => normalizeCalendarText(alias)).filter(Boolean)));
|
||
}
|
||
|
||
function findHebrewMonthStartInGregorianYear(month, year) {
|
||
const aliases = getHebrewMonthAliases(month);
|
||
if (!aliases.length || !Number.isFinite(year)) {
|
||
return null;
|
||
}
|
||
|
||
const formatter = new Intl.DateTimeFormat("en-u-ca-hebrew", {
|
||
day: "numeric",
|
||
month: "long",
|
||
year: "numeric"
|
||
});
|
||
|
||
const cursor = new Date(Math.trunc(year), 0, 1, 12, 0, 0, 0);
|
||
const end = new Date(Math.trunc(year), 11, 31, 12, 0, 0, 0);
|
||
|
||
while (cursor.getTime() <= end.getTime()) {
|
||
const parts = formatter.formatToParts(cursor);
|
||
const day = readNumericPart(parts, "day");
|
||
const monthName = normalizeCalendarText(parts.find((part) => part.type === "month")?.value);
|
||
if (day === 1 && aliases.includes(monthName)) {
|
||
return new Date(cursor);
|
||
}
|
||
cursor.setDate(cursor.getDate() + 1);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function findIslamicMonthStartInGregorianYear(month, year) {
|
||
const targetOrder = Number(month?.order);
|
||
if (!Number.isFinite(targetOrder) || !Number.isFinite(year)) {
|
||
return null;
|
||
}
|
||
|
||
const formatter = new Intl.DateTimeFormat("en-u-ca-islamic", {
|
||
day: "numeric",
|
||
month: "numeric",
|
||
year: "numeric"
|
||
});
|
||
|
||
const cursor = new Date(Math.trunc(year), 0, 1, 12, 0, 0, 0);
|
||
const end = new Date(Math.trunc(year), 11, 31, 12, 0, 0, 0);
|
||
|
||
while (cursor.getTime() <= end.getTime()) {
|
||
const parts = formatter.formatToParts(cursor);
|
||
const day = readNumericPart(parts, "day");
|
||
const monthNo = readNumericPart(parts, "month");
|
||
if (day === 1 && monthNo === Math.trunc(targetOrder)) {
|
||
return new Date(cursor);
|
||
}
|
||
cursor.setDate(cursor.getDate() + 1);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function parseFirstMonthDayFromText(dateText) {
|
||
const text = String(dateText || "").replace(/~/g, " ");
|
||
const firstSegment = text.split("/")[0] || text;
|
||
const match = firstSegment.match(/(January|February|March|April|May|June|July|August|September|October|November|December)\s+(\d{1,2})/i);
|
||
if (!match) {
|
||
return null;
|
||
}
|
||
|
||
const monthIndex = MONTH_NAME_TO_INDEX[String(match[1]).toLowerCase()];
|
||
const day = Number(match[2]);
|
||
if (!Number.isFinite(monthIndex) || !Number.isFinite(day)) {
|
||
return null;
|
||
}
|
||
|
||
return { monthIndex, day };
|
||
}
|
||
|
||
function parseMonthDayStartToken(token) {
|
||
const match = String(token || "").match(/(\d{2})-(\d{2})/);
|
||
if (!match) {
|
||
return null;
|
||
}
|
||
|
||
const month = Number(match[1]);
|
||
const day = Number(match[2]);
|
||
if (!Number.isFinite(month) || !Number.isFinite(day)) {
|
||
return null;
|
||
}
|
||
|
||
return { month, day };
|
||
}
|
||
|
||
function createDateAtNoon(year, monthIndex, dayOfMonth) {
|
||
return new Date(Math.trunc(year), monthIndex, Math.trunc(dayOfMonth), 12, 0, 0, 0);
|
||
}
|
||
|
||
function computeWesternEasterDate(year) {
|
||
const y = Math.trunc(Number(year));
|
||
if (!Number.isFinite(y)) {
|
||
return null;
|
||
}
|
||
|
||
const a = y % 19;
|
||
const b = Math.floor(y / 100);
|
||
const c = y % 100;
|
||
const d = Math.floor(b / 4);
|
||
const e = b % 4;
|
||
const f = Math.floor((b + 8) / 25);
|
||
const g = Math.floor((b - f + 1) / 3);
|
||
const h = (19 * a + b - d - g + 15) % 30;
|
||
const i = Math.floor(c / 4);
|
||
const k = c % 4;
|
||
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
||
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
||
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
||
const day = ((h + l - 7 * m + 114) % 31) + 1;
|
||
return createDateAtNoon(y, month - 1, day);
|
||
}
|
||
|
||
function computeNthWeekdayOfMonth(year, monthIndex, weekday, ordinal) {
|
||
const y = Math.trunc(Number(year));
|
||
if (!Number.isFinite(y)) {
|
||
return null;
|
||
}
|
||
|
||
const first = createDateAtNoon(y, monthIndex, 1);
|
||
const firstWeekday = first.getDay();
|
||
const offset = (weekday - firstWeekday + 7) % 7;
|
||
const dayOfMonth = 1 + offset + (Math.trunc(ordinal) - 1) * 7;
|
||
const daysInMonth = new Date(y, monthIndex + 1, 0).getDate();
|
||
if (dayOfMonth > daysInMonth) {
|
||
return null;
|
||
}
|
||
return createDateAtNoon(y, monthIndex, dayOfMonth);
|
||
}
|
||
|
||
function resolveGregorianDateRule(rule, year = getSelectedYear()) {
|
||
const key = String(rule || "").trim().toLowerCase();
|
||
if (!key) {
|
||
return null;
|
||
}
|
||
|
||
if (key === "gregorian-easter-sunday") {
|
||
return computeWesternEasterDate(year);
|
||
}
|
||
|
||
if (key === "gregorian-good-friday") {
|
||
const easter = computeWesternEasterDate(year);
|
||
if (!(easter instanceof Date) || Number.isNaN(easter.getTime())) {
|
||
return null;
|
||
}
|
||
return createDateAtNoon(easter.getFullYear(), easter.getMonth(), easter.getDate() - 2);
|
||
}
|
||
|
||
if (key === "gregorian-thanksgiving-us") {
|
||
return computeNthWeekdayOfMonth(year, 10, 4, 4);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function findHebrewMonthDayInGregorianYear(monthId, day, year) {
|
||
const aliases = HEBREW_MONTH_ALIAS_BY_ID[String(monthId || "").toLowerCase()] || [];
|
||
const targetDay = Number(day);
|
||
if (!aliases.length || !Number.isFinite(targetDay) || !Number.isFinite(year)) {
|
||
return null;
|
||
}
|
||
|
||
const normalizedAliases = aliases.map((alias) => normalizeCalendarText(alias)).filter(Boolean);
|
||
const formatter = new Intl.DateTimeFormat("en-u-ca-hebrew", {
|
||
day: "numeric",
|
||
month: "long",
|
||
year: "numeric"
|
||
});
|
||
|
||
const cursor = new Date(Math.trunc(year), 0, 1, 12, 0, 0, 0);
|
||
const end = new Date(Math.trunc(year), 11, 31, 12, 0, 0, 0);
|
||
|
||
while (cursor.getTime() <= end.getTime()) {
|
||
const parts = formatter.formatToParts(cursor);
|
||
const currentDay = readNumericPart(parts, "day");
|
||
const monthName = normalizeCalendarText(parts.find((part) => part.type === "month")?.value);
|
||
if (currentDay === Math.trunc(targetDay) && normalizedAliases.includes(monthName)) {
|
||
return new Date(cursor);
|
||
}
|
||
cursor.setDate(cursor.getDate() + 1);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function getIslamicMonthOrderById(monthId) {
|
||
const month = getIslamicMonths().find((item) => item?.id === monthId);
|
||
const order = Number(month?.order);
|
||
return Number.isFinite(order) ? Math.trunc(order) : null;
|
||
}
|
||
|
||
function findIslamicMonthDayInGregorianYear(monthId, day, year) {
|
||
const monthOrder = getIslamicMonthOrderById(monthId);
|
||
const targetDay = Number(day);
|
||
if (!Number.isFinite(monthOrder) || !Number.isFinite(targetDay) || !Number.isFinite(year)) {
|
||
return null;
|
||
}
|
||
|
||
const formatter = new Intl.DateTimeFormat("en-u-ca-islamic", {
|
||
day: "numeric",
|
||
month: "numeric",
|
||
year: "numeric"
|
||
});
|
||
|
||
const cursor = new Date(Math.trunc(year), 0, 1, 12, 0, 0, 0);
|
||
const end = new Date(Math.trunc(year), 11, 31, 12, 0, 0, 0);
|
||
|
||
while (cursor.getTime() <= end.getTime()) {
|
||
const parts = formatter.formatToParts(cursor);
|
||
const currentDay = readNumericPart(parts, "day");
|
||
const currentMonth = readNumericPart(parts, "month");
|
||
if (currentDay === Math.trunc(targetDay) && currentMonth === monthOrder) {
|
||
return new Date(cursor);
|
||
}
|
||
cursor.setDate(cursor.getDate() + 1);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function resolveHolidayGregorianDate(holiday) {
|
||
if (!holiday || typeof holiday !== "object") {
|
||
return null;
|
||
}
|
||
|
||
const calendarId = String(holiday.calendarId || "").trim().toLowerCase();
|
||
const monthId = String(holiday.monthId || "").trim().toLowerCase();
|
||
const day = Number(holiday.day);
|
||
const selectedYear = getSelectedYear();
|
||
|
||
if (calendarId === "gregorian") {
|
||
if (holiday?.dateRule) {
|
||
const ruledDate = resolveGregorianDateRule(holiday.dateRule, selectedYear);
|
||
if (ruledDate) {
|
||
return ruledDate;
|
||
}
|
||
}
|
||
|
||
const monthDay = parseMonthDayStartToken(holiday.monthDayStart) || parseMonthDayStartToken(holiday.dateText);
|
||
if (monthDay) {
|
||
return new Date(selectedYear, monthDay.month - 1, monthDay.day, 12, 0, 0, 0);
|
||
}
|
||
const order = getGregorianMonthOrderFromId(monthId);
|
||
if (Number.isFinite(order) && Number.isFinite(day)) {
|
||
return new Date(selectedYear, order - 1, Math.trunc(day), 12, 0, 0, 0);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
if (calendarId === "hebrew") {
|
||
return findHebrewMonthDayInGregorianYear(monthId, day, selectedYear);
|
||
}
|
||
|
||
if (calendarId === "islamic") {
|
||
return findIslamicMonthDayInGregorianYear(monthId, day, selectedYear);
|
||
}
|
||
|
||
if (calendarId === "wheel-of-year") {
|
||
const monthDay = parseMonthDayStartToken(holiday.monthDayStart) || parseFirstMonthDayFromText(holiday.dateText);
|
||
if (monthDay?.month && monthDay?.day) {
|
||
return new Date(selectedYear, monthDay.month - 1, monthDay.day, 12, 0, 0, 0);
|
||
}
|
||
if (monthDay?.monthIndex != null && monthDay?.day) {
|
||
return new Date(selectedYear, monthDay.monthIndex, monthDay.day, 12, 0, 0, 0);
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function findWheelMonthStartInGregorianYear(month, year) {
|
||
const parsed = parseFirstMonthDayFromText(month?.date);
|
||
if (!parsed || !Number.isFinite(year)) {
|
||
return null;
|
||
}
|
||
|
||
return new Date(Math.trunc(year), parsed.monthIndex, parsed.day, 12, 0, 0, 0);
|
||
}
|
||
|
||
function getGregorianReferenceDateForCalendarMonth(month) {
|
||
const calId = getSelectedCalendar();
|
||
const selectedYear = getSelectedYear();
|
||
if (calId === "gregorian") {
|
||
return getGregorianMonthStartDate(Number(month?.order), selectedYear);
|
||
}
|
||
if (calId === "hebrew") {
|
||
return findHebrewMonthStartInGregorianYear(month, selectedYear);
|
||
}
|
||
if (calId === "islamic") {
|
||
return findIslamicMonthStartInGregorianYear(month, selectedYear);
|
||
}
|
||
if (calId === "wheel-of-year") {
|
||
return findWheelMonthStartInGregorianYear(month, selectedYear);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function formatIsoDate(date) {
|
||
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
||
return "";
|
||
}
|
||
|
||
const year = date.getFullYear();
|
||
const month = `${date.getMonth() + 1}`.padStart(2, "0");
|
||
const day = `${date.getDate()}`.padStart(2, "0");
|
||
return `${year}-${month}-${day}`;
|
||
}
|
||
|
||
function resolveCalendarDayToGregorian(month, dayNumber) {
|
||
const calId = getSelectedCalendar();
|
||
const selectedYear = getSelectedYear();
|
||
const day = Math.trunc(Number(dayNumber));
|
||
if (!Number.isFinite(day) || day <= 0) {
|
||
return null;
|
||
}
|
||
|
||
if (calId === "gregorian") {
|
||
const monthOrder = Number(month?.order);
|
||
if (!Number.isFinite(monthOrder)) {
|
||
return null;
|
||
}
|
||
return new Date(selectedYear, monthOrder - 1, day, 12, 0, 0, 0);
|
||
}
|
||
|
||
if (calId === "hebrew") {
|
||
return findHebrewMonthDayInGregorianYear(month?.id, day, selectedYear);
|
||
}
|
||
|
||
if (calId === "islamic") {
|
||
return findIslamicMonthDayInGregorianYear(month?.id, day, selectedYear);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function intersectDateRanges(startA, endA, startB, endB) {
|
||
const start = startA.getTime() > startB.getTime() ? startA : startB;
|
||
const end = endA.getTime() < endB.getTime() ? endA : endB;
|
||
return start.getTime() <= end.getTime() ? { start, end } : null;
|
||
}
|
||
|
||
function init(nextConfig = {}) {
|
||
config = {
|
||
...config,
|
||
...nextConfig
|
||
};
|
||
}
|
||
|
||
window.TarotCalendarDates = {
|
||
...(window.TarotCalendarDates || {}),
|
||
init,
|
||
parseMonthDayToken,
|
||
buildSignDateBounds,
|
||
addDays,
|
||
formatDateLabel,
|
||
isMonthDayInRange,
|
||
parseMonthDayTokensFromText,
|
||
parseDayRangeFromText,
|
||
isoToDateAtNoon,
|
||
getDaysInMonth,
|
||
getMonthStartWeekday,
|
||
parseMonthRange,
|
||
normalizeCalendarText,
|
||
formatGregorianReferenceDate,
|
||
formatCalendarDateFromGregorian,
|
||
getGregorianMonthStartDate,
|
||
findHebrewMonthStartInGregorianYear,
|
||
findIslamicMonthStartInGregorianYear,
|
||
parseFirstMonthDayFromText,
|
||
parseMonthDayStartToken,
|
||
resolveHolidayGregorianDate,
|
||
findWheelMonthStartInGregorianYear,
|
||
getGregorianReferenceDateForCalendarMonth,
|
||
formatIsoDate,
|
||
resolveCalendarDayToGregorian,
|
||
intersectDateRanges
|
||
};
|
||
})(); |