@ishubhamx/panchangam-js
Version:
Enhanced Indian Panchangam (Hindu Calendar) library with comprehensive Vedic features including Muhurta calculations, planetary positions, Rashi placements, and auspicious/inauspicious time calculations
1,034 lines (1,033 loc) • 58.7 kB
JavaScript
"use strict";
/**
* Festival Calculation Logic - v3.1.0
*
* Fixes applied over v3.0.0:
* - Dahi Handi: moved to Shravana (masa 4), tithi 24
* - Ahoi Ashtami: moved to Kartika (masa 7), tithi 23
* - Mauni Amavasya: moved to Magha (masa 10), tithi 30
* - Holashtak Begins: corrected to Phalguna Shukla Ashtami (tithi 8)
* - Kalki Jayanti: corrected to Shravana Shukla Shashthi (tithi 6)
* - Vat Savitri Vrat regional: corrected to North India
* - Vat Purnima regional: corrected to Maharashtra/Gujarat
* - Narada Jayanti: moved to Vaishakha (masa 1), tithi 16
* - Masik Shivaratri: suppressed in Magha (Maha Shivaratri handled separately)
* - Maghi: marked as solar-approximate, guarded with vara === 0 (Sunday nearest Makar)
* - Varalakshmi Vratam: moved to vara-based logic (Friday before Shravana Purnima)
* - Gayatri Jayanti (Jyeshtha): disambiguated from Shravana Purnima entry
* - Parivartini/Parsva Ekadashi duplicate: consolidated under EKADASHI_NAMES
* - Minor additions: Skanda Sashti (masa 7 + vara), Kamada Ekadashi description,
* Chaitra Navratri day-3/day-9 stubs, Shraddha Paksha daily observance.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EKADASHI_NAMES = void 0;
exports.getEkadashiName = getEkadashiName;
exports.getFestivals = getFestivals;
exports.getFestivalsByTithi = getFestivalsByTithi;
exports.getUpcomingFestivals = getUpcomingFestivals;
const constants_1 = require("./constants");
const udaya_tithi_1 = require("./udaya-tithi");
const calculations_1 = require("./calculations");
const ayanamsa_1 = require("./ayanamsa");
/**
* Ekadashi Names by Masa and Paksha
*
* Keys: "<masaIndex>-<Shukla|Krishna>"
* Tithis: Shukla Ekadashi = 11, Krishna Ekadashi = 26
*/
exports.EKADASHI_NAMES = {
// Chaitra (0)
"0-Shukla": "Kamada Ekadashi",
"0-Krishna": "Varuthini Ekadashi",
// Vaishakha (1)
"1-Shukla": "Mohini Ekadashi",
"1-Krishna": "Apara Ekadashi",
// Jyeshtha (2)
"2-Shukla": "Nirjala Ekadashi",
"2-Krishna": "Yogini Ekadashi",
// Ashadha (3)
// NOTE: Devshayani = Ashadha Shukla Ekadashi; handled in major-festivals block
// with richer metadata; duplicate-check prevents double-entry.
"3-Shukla": "Devshayani Ekadashi",
"3-Krishna": "Kamika Ekadashi",
// Shravana (4)
"4-Shukla": "Shravana Putrada Ekadashi",
"4-Krishna": "Aja Ekadashi",
// Bhadrapada (5)
// NOTE: Parivartini / Parsva are the same Ekadashi — consolidated here.
"5-Shukla": "Parsva Ekadashi (Parivartini)",
"5-Krishna": "Indira Ekadashi",
// Ashwina (6)
"6-Shukla": "Papankusha Ekadashi",
"6-Krishna": "Rama Ekadashi",
// Kartika (7)
// NOTE: Devutthana = Kartika Shukla Ekadashi; handled with richer metadata below.
"7-Shukla": "Devutthana Ekadashi",
"7-Krishna": "Utpanna Ekadashi",
// Margashirsha (8)
"8-Shukla": "Mokshada Ekadashi",
"8-Krishna": "Saphala Ekadashi",
// Pausha (9)
"9-Shukla": "Pausha Putrada Ekadashi",
"9-Krishna": "Shattila Ekadashi",
// Magha (10)
"10-Shukla": "Jaya Ekadashi",
"10-Krishna": "Vijaya Ekadashi",
// Phalguna (11)
"11-Shukla": "Amalaki Ekadashi",
"11-Krishna": "Papmochani Ekadashi",
};
/**
* Get Ekadashi name for a given Masa and Paksha.
*/
function getEkadashiName(masaIndex, paksha, isAdhika = false) {
if (isAdhika) {
return paksha === 'Shukla' ? 'Padmini Ekadashi' : 'Parama Ekadashi';
}
const key = `${masaIndex}-${paksha}`;
return exports.EKADASHI_NAMES[key] || `${constants_1.masaNames[masaIndex]} ${paksha} Ekadashi`;
}
// ---------------------------------------------------------------------------
// Solar Calendar Festivals (Sankranti-based)
// ---------------------------------------------------------------------------
function getSolarFestivals(date, options) {
const festivals = [];
if (!options.includeSolarFestivals) {
return festivals;
}
const timezoneOffsetMinutes = options.timezoneOffset ?? -date.getTimezoneOffset();
const ayanamsa = (0, ayanamsa_1.getAyanamsa)(date);
const sankranti = (0, calculations_1.getSankrantiForDate)(date, ayanamsa, timezoneOffsetMinutes);
if (!sankranti)
return festivals;
const rashiIndex = sankranti.rashi;
const solarFestivalConfigs = constants_1.SOLAR_FESTIVALS[rashiIndex];
if (!solarFestivalConfigs)
return festivals;
for (const config of solarFestivalConfigs) {
if (config.type === 'span' && config.spanDays && config.dayNames) {
const sankrantiTime = sankranti.exactTime.getTime();
const currentTime = date.getTime();
const daysDiff = Math.floor((currentTime - sankrantiTime) / (24 * 60 * 60 * 1000));
if (daysDiff >= -1 && daysDiff < config.spanDays - 1) {
const dayIndex = daysDiff + 1;
if (dayIndex >= 0 && dayIndex < config.spanDays) {
const dayName = config.dayNames[dayIndex];
festivals.push({
name: dayName,
type: 'span',
category: 'solar',
date,
description: config.description,
regional: config.regional,
spanDays: config.spanDays,
dailyNames: config.dayNames
});
}
}
}
else {
festivals.push({
name: config.name,
type: 'single',
category: 'solar',
date,
description: config.description,
regional: config.regional
});
}
}
return festivals;
}
// ---------------------------------------------------------------------------
// Multi-Day Festival Spans
// ---------------------------------------------------------------------------
function getMultiDayFestivals(masaIndex, udayaTithi, date, options) {
const festivals = [];
if (!options.includeMultiDaySpans)
return festivals;
for (const [, config] of Object.entries(constants_1.MULTI_DAY_FESTIVALS)) {
if (config.masaIndex !== masaIndex)
continue;
if (udayaTithi >= config.startTithi && udayaTithi <= config.endTithi) {
const dayIndex = udayaTithi - config.startTithi;
const dailyName = config.dailyNames[dayIndex] || `${config.name} Day ${dayIndex + 1}`;
festivals.push({
name: dailyName,
type: 'span',
category: 'major',
date,
tithi: udayaTithi,
masa: constants_1.masaNames[masaIndex],
spanDays: config.spanDays,
dailyNames: config.dailyNames,
description: `${config.description} (Day ${dayIndex + 1} of ${config.spanDays})`
});
}
}
return festivals;
}
// ---------------------------------------------------------------------------
// Main Festival Calculation Function (v3.1.0)
// ---------------------------------------------------------------------------
/**
* Uses Udaya Tithi (sunrise Tithi) as primary, with full-day tithi
* look-ahead for accurate festival date assignment per Drik Panchang
* convention.
*
* Three-pass approach:
* 1. Sunrise tithi — standard udaya-tithi festivals
* 2. Midday tithi — Madhyahna-vyapini (most festivals)
* 3. Sunset tithi — Aparahna/Sayahna-vyapini (e.g. Dussehra, Vat Savitri)
*
* When a tithi crosses a month boundary (Amavasya → Pratipada), the
* midday/sunset pass uses the NEXT masa index automatically.
*
* Also handles:
* - Adhika Masa festivals (only Ekadashi/Pradosham in Adhika)
* - Kshaya Tithi (short tithis that don't touch any sunrise)
* - Vriddhi Tithi (long tithis spanning two sunrises — festival on FIRST day)
*/
function getFestivals(options) {
const { date, observer, sunrise, masa, paksha } = options;
const calendarType = options.calendarType ?? 'purnimanta';
// Festival definitions are coded in Amanta masa indices.
// In Purnimanta, Krishna Paksha masa is shifted +1 vs Amanta.
// Reverse that shift so festival lookups match the table.
let masaIndex = masa.index;
if (calendarType === 'purnimanta' && paksha === 'Krishna' && !masa.isAdhika) {
masaIndex = (masa.index - 1 + 12) % 12;
}
// Udaya Tithi (1-indexed, 1–30)
const udayaTithi = (0, udaya_tithi_1.getTithiAtSunrise)(date, sunrise, observer);
// Vriddhi Tithi: skip if previous sunrise had the same tithi
const approxPrevSunrise = new Date(sunrise.getTime() - 24 * 60 * 60 * 1000);
const prevSunriseTithi = (0, udaya_tithi_1.getTithiAtTime)(approxPrevSunrise);
const isVriddhiSecondDay = prevSunriseTithi === udayaTithi;
const festivals = isVriddhiSecondDay
? []
: detectTithiBasedFestivals(masaIndex, udayaTithi, paksha, date, options.vara, masa.isAdhika);
// Helper: detect masa crossing at month boundary
const getMasaForTithi = (checkTithi) => {
if (udayaTithi >= 26 && checkTithi <= 15) {
return (masaIndex + 1) % 12;
}
return masaIndex;
};
// Helper: add festivals for intra-day tithis, deduplicating by name
const addFestivalsForTithi = (tithi, useMasa) => {
const t0 = tithi - 1;
const tPaksha = (0, calculations_1.getPaksha)(t0);
const mIdx = useMasa !== undefined ? useMasa : getMasaForTithi(tithi);
const isAdh = (mIdx === masaIndex) ? masa.isAdhika : false;
const fests = detectTithiBasedFestivals(mIdx, tithi, tPaksha, date, options.vara, isAdh);
for (const f of fests) {
if (!festivals.some(existing => existing.name === f.name)) {
festivals.push(f);
}
}
};
if (options.sunset) {
const midday = new Date((sunrise.getTime() + options.sunset.getTime()) / 2);
const middayTithi = (0, udaya_tithi_1.getTithiAtTime)(midday);
const sunsetTithi = (0, udaya_tithi_1.getTithiAtTime)(options.sunset);
const approxNextSunrise = new Date(sunrise.getTime() + 24 * 60 * 60 * 1000);
const nextSunriseTithi = (0, udaya_tithi_1.getTithiAtTime)(approxNextSunrise);
const tithisSeen = new Set([udayaTithi]);
if (middayTithi !== udayaTithi || sunsetTithi !== udayaTithi) {
const endTithi = sunsetTithi;
let t = udayaTithi;
while (true) {
t = t + 1;
if (t > 30)
t = 1;
tithisSeen.add(t);
if (t !== nextSunriseTithi) {
addFestivalsForTithi(t);
}
if (t === endTithi)
break;
if (tithisSeen.size > 5)
break;
}
}
}
// ===== NIGHT FESTIVAL SPECIAL CASES =====
// Maha Shivaratri: fire when Chaturdashi prevails at sunset in Magha Krishna
if (masaIndex === 10 && !masa.isAdhika) {
const CHATURDASHI = 29; // 1-indexed Krishna Chaturdashi
const hasChaturdashiAtSunset = options.sunset
? (0, udaya_tithi_1.getTithiAtTime)(options.sunset) === CHATURDASHI
: udayaTithi === CHATURDASHI;
if (hasChaturdashiAtSunset && !festivals.some(f => f.name === 'Maha Shivaratri')) {
festivals.push({
name: 'Maha Shivaratri',
type: 'single',
category: 'major',
date,
tithi: CHATURDASHI,
paksha: 'Krishna',
masa: constants_1.masaNames[masaIndex],
description: 'Great night of Shiva — observed on the night when Chaturdashi prevails at Pradosh Kala',
observances: ['Fasting', 'All-night vigil', 'Rudrabhishek', 'Shiva puja'],
isFastingDay: true
});
}
}
// ===== MULTI-DAY FESTIVAL SPANS =====
if (!isVriddhiSecondDay && !masa.isAdhika) {
const multiDayFestivals = getMultiDayFestivals(masaIndex, udayaTithi, date, options);
festivals.push(...multiDayFestivals);
}
// ===== SOLAR FESTIVALS =====
const solarFestivals = getSolarFestivals(date, options);
festivals.push(...solarFestivals);
return festivals;
}
// ---------------------------------------------------------------------------
// Public testable wrapper
// ---------------------------------------------------------------------------
/**
* Pure festival detection by Tithi — no astronomical dependencies.
* Recommended for unit testing.
*
* @param masaIndex - 0–11 (Chaitra → Phalguna)
* @param isAdhika - intercalary month flag
* @param udayaTithi - 1–30 (1-indexed)
* @param paksha - "Shukla" | "Krishna"
* @param vara - day of week 0=Sun…6=Sat (optional, used for vara-based festivals)
*/
function getFestivalsByTithi(masaIndex, isAdhika, udayaTithi, paksha, vara) {
const stubDate = new Date();
const festivals = detectTithiBasedFestivals(masaIndex, udayaTithi, paksha, stubDate, vara, isAdhika);
return festivals.map(f => f.name);
}
// ---------------------------------------------------------------------------
// Core detection — no astronomical dependencies
// ---------------------------------------------------------------------------
/**
* @param isAdhika - When true, only Ekadashi and Pradosham are returned.
*/
function detectTithiBasedFestivals(masaIndex, udayaTithi, paksha, date, vara, isAdhika = false) {
const festivals = [];
const createFestival = (name, category, metadata) => ({
name,
type: 'single',
category,
date,
tithi: udayaTithi,
paksha,
masa: constants_1.masaNames[masaIndex] || '',
...metadata
});
// In Adhika Masa only Ekadashi and Pradosham are observed.
if (isAdhika) {
if (udayaTithi === 11 || udayaTithi === 26) {
const ekadashiName = getEkadashiName(masaIndex, paksha, isAdhika);
festivals.push(createFestival(ekadashiName, 'ekadashi', {
isFastingDay: true,
observances: ["Fasting", "Vishnu worship"]
}));
}
if (udayaTithi === 13 || udayaTithi === 28) {
const pradoshamType = (udayaTithi === 13) ? "Shukla" : "Krishna";
festivals.push(createFestival(`Pradosham (${pradoshamType})`, 'pradosham', {
description: "Auspicious time for Shiva worship",
observances: ["Evening Shiva puja"]
}));
}
return festivals;
}
// =========================================================
// CHAITRA (masa 0)
// =========================================================
if (masaIndex === 0 && udayaTithi === 1) {
festivals.push(createFestival("Ugadi / Gudi Padwa", 'major', {
description: "Hindu Luni-Solar New Year",
observances: ["Panchanga reading", "Neem-jaggery prasad", "New clothes"],
regional: ['South', 'Maharashtra']
}));
festivals.push(createFestival("Chaitra Navratri Ghatasthapana", 'major', {
description: "Navratri Day 1 — Worship of Maa Shailputri; Kalash installation",
observances: ["Kalash sthapana", "Fasting begins", "Durga puja"]
}));
}
if (masaIndex === 0 && udayaTithi === 2) {
festivals.push(createFestival("Chaitra Navratri Dwitiya", 'minor', {
description: "Navratri Day 2 — Worship of Maa Brahmacharini"
}));
}
if (masaIndex === 0 && udayaTithi === 3) {
festivals.push(createFestival("Chaitra Navratri Tritiya", 'minor', {
description: "Navratri Day 3 — Worship of Maa Chandraghanta"
}));
festivals.push(createFestival("Gangaur", 'vrat', {
description: "Worship of Goddess Gauri (Isari/Gangaur) for marital bliss",
regional: ['Rajasthan', 'MP'],
isFastingDay: true
}));
}
if (masaIndex === 0 && udayaTithi === 4) {
festivals.push(createFestival("Chaitra Navratri Chaturthi", 'minor', {
description: "Navratri Day 4 — Worship of Maa Kushmanda"
}));
}
if (masaIndex === 0 && udayaTithi === 5) {
festivals.push(createFestival("Chaitra Navratri Panchami", 'minor', {
description: "Navratri Day 5 — Worship of Maa Skandamata"
}));
}
if (masaIndex === 0 && udayaTithi === 6) {
festivals.push(createFestival("Chaitra Navratri Shashthi", 'minor', {
description: "Navratri Day 6 — Worship of Maa Katyayani"
}));
festivals.push(createFestival("Yamuna Chhath (Yamuna Jayanti)", 'jayanti', {
description: "Goddess Yamuna descended to Earth",
regional: ['Brij', 'UP']
}));
}
if (masaIndex === 0 && udayaTithi === 7) {
festivals.push(createFestival("Chaitra Navratri Saptami", 'minor', {
description: "Navratri Day 7 — Worship of Maa Kaalratri"
}));
}
if (masaIndex === 0 && udayaTithi === 8) {
festivals.push(createFestival("Durga Ashtami (Chaitra)", 'major', {
description: "Navratri Day 8 — Worship of Maa Mahagauri",
observances: ["Kanya Pujan", "Havan"]
}));
}
if (masaIndex === 0 && udayaTithi === 9) {
festivals.push(createFestival("Rama Navami", 'major', {
description: "Birth of Lord Rama — Navratri Day 9",
observances: ["Rama Katha", "Chariot processions", "Fasting"],
isFastingDay: true
}));
}
if (masaIndex === 0 && udayaTithi === 15) {
festivals.push(createFestival("Hanuman Jayanti", 'jayanti', {
description: "Birth of Lord Hanuman",
observances: ["Hanuman puja", "Sundarkand path"]
}));
festivals.push(createFestival("Chaitra Purnima", 'minor', {
description: "Full moon of Chaitra — Chitragupta worship",
isFastingDay: true
}));
}
if (masaIndex === 0 && udayaTithi === 23) {
festivals.push(createFestival("Sheetala Ashtami (Basoda)", 'vrat', {
description: "Worship of Goddess Sheetala for good health; cold food offered",
isFastingDay: true,
regional: ['North', 'Rajasthan', 'UP']
}));
}
// =========================================================
// VAISHAKHA (masa 1)
// =========================================================
if (masaIndex === 1 && udayaTithi === 3) {
festivals.push(createFestival("Akshaya Tritiya", 'major', {
description: "Imperishable auspicious day — new beginnings, charity and gold purchase",
observances: ["Gold/silver purchases", "Charity", "Pitru tarpan"]
}));
festivals.push(createFestival("Parashurama Jayanti", 'jayanti', {
description: "Sixth avatar of Vishnu — Parashurama's birth anniversary"
}));
}
if (masaIndex === 1 && udayaTithi === 7) {
festivals.push(createFestival("Ganga Saptami", 'minor', {
description: "Second birth (Punara Janma) of Goddess Ganga",
observances: ["Ganga puja", "River bathing"]
}));
}
if (masaIndex === 1 && udayaTithi === 9) {
festivals.push(createFestival("Sita Navami (Janaki Jayanti)", 'jayanti', {
description: "Birth anniversary of Goddess Sita",
observances: ["Married women observe fast", "Sita-Rama puja"]
}));
}
if (masaIndex === 1 && udayaTithi === 14) {
festivals.push(createFestival("Narasimha Jayanti", 'jayanti', {
description: "Appearance of Narasimha (man-lion) Avatar of Vishnu",
observances: ["One-day fast", "Narasimha puja"]
}));
}
// FIX: Narada Jayanti moved here from Jyeshtha (masa 2)
// Most sources: Vaishakha Krishna Pratipada (tithi 16)
if (masaIndex === 1 && udayaTithi === 16) {
festivals.push(createFestival("Narada Jayanti", 'jayanti', {
description: "Birth anniversary of Devrishi Narada Muni"
}));
}
if (masaIndex === 1 && udayaTithi === 15) {
festivals.push(createFestival("Buddha Purnima", 'major', {
description: "Birth, Enlightenment and Mahaparinirvana of Gautama Buddha",
observances: ["Meditation", "Dana (charity)", "Dhamma teachings"]
}));
festivals.push(createFestival("Kurma Jayanti", 'jayanti', {
description: "Birth anniversary of Kurma (Tortoise) Avatar of Vishnu"
}));
festivals.push(createFestival("Vaishakha Purnima", 'minor', {
description: "Full moon of Vaishakha — auspicious for bathing and charity",
isFastingDay: true
}));
}
// =========================================================
// JYESHTHA (masa 2)
// =========================================================
if (masaIndex === 2 && udayaTithi === 9) {
festivals.push(createFestival("Mahesh Navami", 'minor', {
description: "Worship of Lord Shiva and Goddess Parvati",
regional: ['Rajasthan', 'North']
}));
}
if (masaIndex === 2 && udayaTithi === 10) {
festivals.push(createFestival("Ganga Dussehra", 'minor', {
description: "Descent of Ganga to Earth — 10 sins washed away",
observances: ["Ganga bathing", "Charity of 10 items"]
}));
}
if (masaIndex === 2 && udayaTithi === 11) {
// FIX: disambiguated — this is a minority tradition
festivals.push(createFestival("Gayatri Jayanti (Jyeshtha Shukla)", 'jayanti', {
description: "Minority tradition: Gayatri Jayanti on Jyeshtha Shukla Ekadashi",
regional: ['Some traditions']
}));
}
if (masaIndex === 2 && udayaTithi === 15) {
// FIX: regional corrected — Vat Purnima is Maharashtra/Gujarat
festivals.push(createFestival("Vat Purnima", 'vrat', {
description: "Married women fast and tie thread around Banyan tree for husband's longevity",
regional: ['Maharashtra', 'Gujarat'],
isFastingDay: true,
observances: ["Banyan tree puja", "Savitri-Satyavan story recitation"]
}));
}
if (masaIndex === 2 && udayaTithi === 30) {
// FIX: regional corrected — Vat Savitri on Amavasya is North India
festivals.push(createFestival("Vat Savitri Vrat", 'vrat', {
description: "Married women fast for husband's well-being; Banyan tree circumambulation",
regional: ['North', 'UP', 'Bihar', 'Rajasthan', 'Punjab'],
isFastingDay: true,
observances: ["Banyan tree puja", "Savitri-Satyavan story recitation"]
}));
festivals.push(createFestival("Shani Jayanti", 'jayanti', {
description: "Birth anniversary of Lord Shani (Saturn)",
observances: ["Shani puja", "Sesame oil lamp offering"]
}));
}
// =========================================================
// ASHADHA (masa 3)
// =========================================================
if (masaIndex === 3 && udayaTithi === 2) {
festivals.push(createFestival("Jagannath Rathyatra", 'major', {
description: "Annual chariot festival of Lord Jagannath, Balabhadra and Subhadra",
regional: ['Odisha', 'East'],
observances: ["Chariot procession", "Mahaprasad"]
}));
}
if (masaIndex === 3 && udayaTithi === 11) {
festivals.push(createFestival("Devshayani Ekadashi", 'ekadashi', {
description: "Lord Vishnu begins cosmic sleep (Yoga Nidra) — start of Chaturmas",
isFastingDay: true,
observances: ["Fasting", "Start of Chaturmas", "No auspicious events for 4 months"]
}));
}
if (masaIndex === 3 && udayaTithi === 15) {
festivals.push(createFestival("Guru Purnima", 'major', {
description: "Day to honour spiritual and academic teachers; Vyasa Puja",
observances: ["Guru worship", "Guru Dakshina", "Prayers"]
}));
festivals.push(createFestival("Vyasa Puja", 'jayanti', {
description: "Birth anniversary of Sage Veda Vyasa — compiler of Vedas and Puranas"
}));
festivals.push(createFestival("Kokila Vrat", 'vrat', {
description: "Women fast for a happy married life",
isFastingDay: true,
regional: ['Maharashtra', 'Gujarat']
}));
}
// =========================================================
// SHRAVANA (masa 4)
// =========================================================
if (masaIndex === 4 && udayaTithi === 3) {
festivals.push(createFestival("Hariyali Teej", 'vrat', {
description: "Monsoon festival of greenery, swings and marital happiness",
regional: ['North', 'Rajasthan', 'UP'],
isFastingDay: true,
observances: ["Swing games", "Songs of Teej", "Shiva-Parvati puja"]
}));
}
if (masaIndex === 4 && udayaTithi === 5) {
festivals.push(createFestival("Nag Panchami", 'minor', {
description: "Serpent deity worship — milk and flowers offered to snake idols",
observances: ["Snake worship", "Milk offering"]
}));
}
// FIX: Kalki Jayanti corrected to Shravana Shukla Shashthi (tithi 6)
if (masaIndex === 4 && udayaTithi === 6) {
festivals.push(createFestival("Kalki Jayanti", 'jayanti', {
description: "Anticipated birth anniversary of Kalki — the tenth and future avatar of Vishnu"
}));
}
// Varalakshmi Vratam: observed on the FRIDAY falling between Shravana
// Shukla Ashtami and Chaturdashi (tithis 8–14), i.e. the last Friday
// before Shravana Purnima. A fixed tithi does not exist — the vara check
// is the canonical trigger.
if (masaIndex === 4 && udayaTithi >= 8 && udayaTithi <= 14 && vara === 5) {
festivals.push(createFestival("Varalakshmi Vratam", 'vrat', {
description: "Worship of Goddess Varalakshmi for wealth and prosperity — observed on the Friday nearest to (and before) Shravana Purnima",
regional: ['South', 'Karnataka', 'Andhra', 'Tamil Nadu'],
isFastingDay: true,
observances: ["Lakshmi puja", "Kalasha worship", "New saree offered"]
}));
}
if (masaIndex === 4 && udayaTithi === 15) {
festivals.push(createFestival("Raksha Bandhan", 'major', {
description: "Festival celebrating the brother-sister bond",
observances: ["Rakhi tying", "Sister's prayers for brother", "Gift exchange"]
}));
// Canonical Gayatri Jayanti (most traditions: Shravana Purnima)
festivals.push(createFestival("Gayatri Jayanti", 'jayanti', {
description: "Manifestation anniversary of Goddess Gayatri (Vedmata)"
}));
festivals.push(createFestival("Hayagriva Jayanti", 'jayanti', {
description: "Birth anniversary of Hayagriva — the horse-headed avatar of Vishnu",
observances: ["Hayagriva puja", "Vedic recitation"]
}));
festivals.push(createFestival("Narali Purnima", 'minor', {
description: "Coconut offering to sea god — start of fishing season",
regional: ['Maharashtra', 'Konkan', 'Goa']
}));
festivals.push(createFestival("Shravana Purnima", 'minor', {
description: "Full moon of Shravana — Avani Avittam (Upakarma) in South India",
regional: ['South'],
observances: ["Upakarma", "Sacred thread change"],
isFastingDay: true
}));
}
if (masaIndex === 4 && udayaTithi === 18) {
festivals.push(createFestival("Kajari Teej", 'vrat', {
description: "Third Teej of the season — Shiva-Parvati worship",
regional: ['North', 'UP', 'MP', 'Bihar'],
isFastingDay: true
}));
}
// FIX: Dahi Handi moved here from Bhadrapada; it is observed one day
// after Janmashtami (Shravana Krishna Navami → tithi 24)
if (masaIndex === 4 && udayaTithi === 24) {
festivals.push(createFestival("Dahi Handi", 'major', {
description: "Breaking of suspended curd pot — celebrating Krishna's childhood butter theft",
regional: ['Maharashtra', 'Konkan', 'Mumbai'],
observances: ["Human pyramid (Govinda)", "Singing"]
}));
}
if (masaIndex === 4 && udayaTithi === 23) {
festivals.push(createFestival("Krishna Janmashtami", 'major', {
description: "Birth of Lord Krishna — Shravana Krishna Ashtami",
observances: ["Fasting", "Midnight celebrations", "Dahi Handi", "Bhajan Sandhya"],
isFastingDay: true
}));
}
// =========================================================
// BHADRAPADA (masa 5)
// =========================================================
if (masaIndex === 5 && udayaTithi === 3) {
festivals.push(createFestival("Hartalika Teej", 'vrat', {
description: "Shiva-Parvati puja for marital bliss — sandless fast",
isFastingDay: true,
observances: ["All-night vigil", "Sand Parvati image worship"]
}));
festivals.push(createFestival("Gowri Habba", 'vrat', {
description: "Worship of Goddess Gowri (Parvati) — eve of Ganesh Chaturthi",
regional: ['Karnataka', 'South']
}));
}
if (masaIndex === 5 && udayaTithi === 4) {
festivals.push(createFestival("Ganesh Chaturthi", 'major', {
description: "Birth of Lord Ganesha — 10-day festival",
observances: ["Ganesha idol installation", "Modak offerings", "Aarti", "Visarjan"],
regional: ['Maharashtra', 'Karnataka', 'Andhra']
}));
}
if (masaIndex === 5 && udayaTithi === 5) {
festivals.push(createFestival("Rishi Panchami", 'vrat', {
description: "Worship of Saptarishi (seven sages) — women observe atonement fast",
observances: ["Saptarishi puja", "Fasting"]
}));
}
if (masaIndex === 5 && udayaTithi === 8) {
festivals.push(createFestival("Radha Ashtami", 'jayanti', {
description: "Birth anniversary of Goddess Radha — consort of Krishna",
observances: ["Radha puja", "Bhajan sandhya"]
}));
festivals.push(createFestival("Durva Ashtami", 'vrat', {
description: "Offering Durva (Bermuda grass) to Lord Ganesha",
observances: ["21 Durva blade offering"]
}));
}
if (masaIndex === 5 && udayaTithi === 11) {
// Consolidated: Parsva Ekadashi = Parivartini Ekadashi (same festival)
festivals.push(createFestival("Parsva Ekadashi (Parivartini)", 'ekadashi', {
description: "Vishnu turns sides in cosmic sleep (Parsva Parivartana)",
isFastingDay: true,
observances: ["Fasting", "Vishnu puja", "Dwadashi parana"]
}));
}
if (masaIndex === 5 && udayaTithi === 12) {
festivals.push(createFestival("Vamana Jayanti", 'jayanti', {
description: "Birth anniversary of Vamana — the dwarf avatar of Vishnu",
observances: ["Vamana puja", "Daana (charity)"]
}));
}
if (masaIndex === 5 && udayaTithi === 14) {
festivals.push(createFestival("Anant Chaturdashi", 'major', {
description: "Worship of Ananta (Vishnu) — Anant Vrat thread tied on wrist",
observances: ["Ananta puja", "Vrat thread"]
}));
festivals.push(createFestival("Ganesh Visarjan", 'major', {
description: "Immersion of Ganesha idols on the 10th day",
observances: ["Procession", "Immersion in water body"]
}));
}
if (masaIndex === 5 && udayaTithi === 15) {
festivals.push(createFestival("Purnima Shraddha", 'minor', {
description: "First day of Pitru Paksha — Purnima Shraddha for ancestors"
}));
}
if (masaIndex === 5 && udayaTithi === 30) {
festivals.push(createFestival("Sarva Pitru Amavasya (Mahalaya)", 'major', {
description: "Last and most important day of Pitru Paksha — all ancestor worship",
observances: ["Tarpan", "Pinda Daan", "Brahmin bhojan"]
}));
}
// =========================================================
// ASHWINA (masa 6)
// =========================================================
if (masaIndex === 6 && udayaTithi === 1) {
festivals.push(createFestival("Navaratri Ghatasthapana", 'major', {
description: "Sharad Navaratri Day 1 — Worship of Maa Shailputri; Kalash installation",
observances: ["Kalash sthapana", "Fasting begins", "Akhand Jyot"]
}));
}
if (masaIndex === 6 && udayaTithi === 2) {
festivals.push(createFestival("Navaratri Dwitiya", 'minor', {
description: "Navaratri Day 2 — Worship of Maa Brahmacharini"
}));
}
if (masaIndex === 6 && udayaTithi === 3) {
festivals.push(createFestival("Navaratri Tritiya", 'minor', {
description: "Navaratri Day 3 — Worship of Maa Chandraghanta"
}));
}
if (masaIndex === 6 && udayaTithi === 4) {
festivals.push(createFestival("Navaratri Chaturthi", 'minor', {
description: "Navaratri Day 4 — Worship of Maa Kushmanda"
}));
}
if (masaIndex === 6 && udayaTithi === 5) {
festivals.push(createFestival("Navaratri Panchami", 'minor', {
description: "Navaratri Day 5 — Worship of Maa Skandamata"
}));
festivals.push(createFestival("Upang Lalita Vrat", 'vrat', {
description: "Worship of Goddess Lalita Devi on Navaratri Day 5"
}));
}
if (masaIndex === 6 && udayaTithi === 6) {
festivals.push(createFestival("Navaratri Shashthi", 'minor', {
description: "Navaratri Day 6 — Worship of Maa Katyayani"
}));
}
if (masaIndex === 6 && udayaTithi === 7) {
festivals.push(createFestival("Navaratri Saptami", 'minor', {
description: "Navaratri Day 7 — Worship of Maa Kaalratri"
}));
}
if (masaIndex === 6 && udayaTithi === 8) {
festivals.push(createFestival("Durga Ashtami (Maha Ashtami)", 'major', {
description: "Navaratri Day 8 — Worship of Maa Mahagauri",
observances: ["Durga puja", "Kumari puja", "Sandhi puja at Ashtami-Navami junction"]
}));
}
if (masaIndex === 6 && udayaTithi === 9) {
festivals.push(createFestival("Maha Navami", 'major', {
description: "Navaratri Day 9 — Worship of Maa Siddhidatri",
observances: ["Durga worship", "Ayudha puja", "Kanya Pujan"]
}));
}
if (masaIndex === 6 && udayaTithi === 10) {
festivals.push(createFestival("Vijaya Dashami (Dussehra)", 'major', {
description: "Victory of good over evil — Rama's victory over Ravana",
observances: ["Ravana effigy burning", "Shami tree worship", "Shaastra puja"]
}));
}
if (masaIndex === 6 && udayaTithi === 15) {
festivals.push(createFestival("Sharad Purnima", 'major', {
description: "Full harvest moon — Goddess Lakshmi descends; Kheer left in moonlight",
observances: ["Moonlight kheer offering", "River bathing"]
}));
festivals.push(createFestival("Valmiki Jayanti", 'jayanti', {
description: "Birth anniversary of Maharishi Valmiki — author of Ramayana",
observances: ["Valmiki puja", "Ramayan recitation"]
}));
festivals.push(createFestival("Kojagara Puja", 'minor', {
description: "Night vigil for Lakshmi worship — 'Who is awake?' (Ko Jagara)",
regional: ['Bengal', 'Odisha', 'East']
}));
}
if (masaIndex === 6 && udayaTithi === 19) {
festivals.push(createFestival("Karwa Chauth", 'vrat', {
description: "Married women fast from sunrise to moonrise for husband's long life",
isFastingDay: true,
regional: ['North', 'UP', 'Punjab', 'Rajasthan', 'Delhi'],
observances: ["Sunrise-to-moonrise fast", "Moon sighting through sieve"]
}));
}
// FIX: Ahoi Ashtami moved to Kartika (masa 7) below
if (masaIndex === 6 && udayaTithi === 23) {
festivals.push(createFestival("Jivitputrika Vrat (Jitiya)", 'vrat', {
description: "Mothers observe nirjala (waterless) fast for children's well-being",
regional: ['Bihar', 'Jharkhand', 'UP', 'Nepal'],
isFastingDay: true,
observances: ["Nirjala fast", "Jivitputrika story recitation"]
}));
}
if (masaIndex === 6 && udayaTithi === 28) {
festivals.push(createFestival("Dhanteras (Dhanatrayodashi)", 'major', {
description: "Festival of wealth and health — Lakshmi and Dhanvantari worship",
observances: ["Gold/silver/utensil purchase", "Lakshmi puja", "Yama Deepak outside home"]
}));
}
if (masaIndex === 6 && udayaTithi === 29) {
festivals.push(createFestival("Naraka Chaturdashi (Choti Diwali)", 'major', {
description: "Celebration of Krishna's victory over demon Narakasura",
observances: ["Abhyanga snan (oil bath) before sunrise", "Lamps lit"]
}));
}
if (masaIndex === 6 && udayaTithi === 30) {
festivals.push(createFestival("Diwali (Lakshmi Puja)", 'major', {
description: "Festival of Lights — Lakshmi-Ganesha puja on Kartika Amavasya",
observances: ["Lakshmi-Ganesha puja", "Fireworks", "Diyas", "Sweets exchange", "Gambling tradition"]
}));
}
// =========================================================
// KARTIKA (masa 7)
// =========================================================
if (masaIndex === 7 && udayaTithi === 1) {
festivals.push(createFestival("Govardhan Puja", 'major', {
description: "Worship of Govardhan Hill — Krishna lifted it to protect Braj from Indra's wrath",
observances: ["Annakut (mountain of food offered)", "Cow worship"]
}));
festivals.push(createFestival("Bali Pratipada", 'major', {
description: "King Bali's return from netherworld; New Year in some regions",
regional: ['Maharashtra', 'Karnataka', 'South']
}));
}
if (masaIndex === 7 && udayaTithi === 2) {
festivals.push(createFestival("Bhai Dooj (Yama Dwitiya)", 'major', {
description: "Sister-brother bond celebration — Yama visits sister Yamuna",
observances: ["Tilak ceremony", "Sister's prayers for brother", "Gift exchange"]
}));
}
if (masaIndex === 7 && udayaTithi === 4) {
festivals.push(createFestival("Karva Chauth (Kartik)", 'vrat', {
description: "Regional variant: some communities observe Karva Chauth in Kartika Shukla",
regional: ['Some North traditions'],
isFastingDay: true
}));
}
if (masaIndex === 7 && udayaTithi === 6) {
festivals.push(createFestival("Chhath Puja", 'major', {
description: "Four-day Sun god (Chhathi Maiya/Surya) worship — one of the most rigorous Hindu festivals",
regional: ['Bihar', 'Jharkhand', 'UP', 'Nepal'],
observances: ["Nahay-Khay", "Kharna", "Sandhya Arghya to setting Sun", "Usha Arghya to rising Sun"]
}));
}
// PRIMARY Skanda Sashti (Kanda Sashti): Kartika Shukla Shashthi is the
// canonical Skanda Sashti — a 6-day fast culminating in Soorasamharam
// (Murugan's victory over demon Soorapadman). Most important in Tamil Nadu.
if (masaIndex === 7 && udayaTithi === 6) {
festivals.push(createFestival("Skanda Sashti (Kanda Sashti)", 'major', {
description: "Six-day fast culminating in Lord Murugan's victory over demon Soorapadman (Soorasamharam)",
regional: ['South', 'Tamil Nadu', 'Kerala', 'Sri Lanka'],
isFastingDay: true,
observances: ["6-day fast", "Kavadi", "Vel worship", "Soorasamharam re-enactment"]
}));
}
if (masaIndex === 7 && udayaTithi === 8) {
festivals.push(createFestival("Gopashtami", 'minor', {
description: "Krishna formally becomes a cowherd; cow and cowherd worship",
regional: ['Brij', 'North']
}));
}
if (masaIndex === 7 && udayaTithi === 9) {
festivals.push(createFestival("Akshaya Navami (Amla Navami)", 'minor', {
description: "Worship of Amla (Indian gooseberry) tree — Vishnu resides in it this day",
observances: ["Amla tree circumambulation", "Food cooked under tree"]
}));
}
if (masaIndex === 7 && udayaTithi === 10) {
festivals.push(createFestival("Kansa Vadh", 'minor', {
description: "Commemoration of Krishna slaying the demon king Kansa"
}));
}
if (masaIndex === 7 && udayaTithi === 11) {
festivals.push(createFestival("Devutthana Ekadashi (Prabodhini)", 'ekadashi', {
description: "Lord Vishnu wakes from cosmic sleep — end of Chaturmas; auspicious season begins",
isFastingDay: true,
observances: ["Fasting", "End of Chaturmas", "Tulsi Vivah performed", "Weddings resume"]
}));
}
if (masaIndex === 7 && udayaTithi === 12) {
festivals.push(createFestival("Tulasi Vivah", 'minor', {
description: "Ceremonial marriage of Tulasi plant with Lord Vishnu (Shaligram)",
observances: ["Tulasi-Shaligram puja", "Wedding rituals", "Sugarcane canopy"]
}));
}
// FIX: Ahoi Ashtami moved here (Kartika Krishna Ashtami = tithi 23)
if (masaIndex === 7 && udayaTithi === 23) {
festivals.push(createFestival("Ahoi Ashtami", 'vrat', {
description: "Mothers fast from sunrise to starrise for children's well-being",
regional: ['North', 'UP', 'Rajasthan', 'Punjab', 'Delhi'],
isFastingDay: true,
observances: ["Starrise-time puja", "Ahoi Mata story recitation"]
}));
}
if (masaIndex === 7 && udayaTithi === 15) {
festivals.push(createFestival("Kartik Purnima / Dev Diwali", 'major', {
description: "Gods celebrate Diwali — Tripura Nasini (Shiva destroys Tripura); grand lamp festival at Varanasi ghats",
observances: ["River bathing at Varanasi", "Diyas on river", "Boat puja", "Pushkar Fair"]
}));
}
// =========================================================
// MARGASHIRSHA (masa 8)
// =========================================================
if (masaIndex === 8 && udayaTithi === 1) {
festivals.push(createFestival("Margashirsha Shukla Pratipada", 'minor', {
description: "Lord Krishna's favourite month begins (BG 10.35)"
}));
}
if (masaIndex === 8 && udayaTithi === 5) {
festivals.push(createFestival("Vivah Panchami", 'minor', {
description: "Divine marriage anniversary of Lord Rama and Goddess Sita",
observances: ["Rama-Sita wedding re-enactment", "Bhajan"]
}));
}
if (masaIndex === 8 && udayaTithi === 11) {
festivals.push(createFestival("Gita Jayanti", 'minor', {
description: "Anniversary of Lord Krishna's Bhagavad Gita discourse to Arjuna",
observances: ["Gita recitation", "Gita Yajna", "Gita distribution"]
}));
}
if (masaIndex === 8 && udayaTithi === 15) {
festivals.push(createFestival("Dattatreya Jayanti", 'jayanti', {
description: "Birth anniversary of Lord Dattatreya — combined avatar of Brahma, Vishnu, Shiva",
observances: ["Dattatreya puja", "All-night bhajan"]
}));
festivals.push(createFestival("Annapurna Jayanti", 'jayanti', {
description: "Birthday of Goddess Annapurna — goddess of food and nourishment"
}));
}
if (masaIndex === 8 && udayaTithi === 23) {
festivals.push(createFestival("Kalabhairav Jayanti", 'jayanti', {
description: "Birth of Lord Kalabhairava — fierce form of Shiva, guardian of Kashi",
observances: ["Night puja", "Bhairav ashtami fast"]
}));
}
// =========================================================
// PAUSHA (masa 9)
// =========================================================
if (masaIndex === 9 && udayaTithi === 6) {
// Pausha Skanda Sashti: monthly Shukla Shashthi Murugan worship.
// The PRIMARY / most important Skanda Sashti is in Kartika (masa 7) above.
festivals.push(createFestival("Skanda Sashti", 'vrat', {
description: "Monthly Shukla Shashthi worship of Lord Murugan (Skanda/Kartikeya). The principal Skanda Sashti is Kartika Shukla Shashthi (Kanda Sashti).",
regional: ['South', 'Tamil Nadu', 'Kerala'],
isFastingDay: true,
observances: ["Murugan puja", "Vel worship"]
}));
}
if (masaIndex === 9 && udayaTithi === 8) {
festivals.push(createFestival("Banada Ashtami", 'vrat', {
description: "Shakambhari Navratri observance — Goddess Shakambhari worship",
regional: ['Rajasthan', 'North']
}));
}
if (masaIndex === 9 && udayaTithi === 11) {
festivals.push(createFestival("Pausha Putrada Ekadashi", 'ekadashi', {
description: "Ekadashi for those wishing for progeny — Vishnu worship",
isFastingDay: true,
observances: ["Fasting", "Vishnu worship", "Satyanarayan Katha"]
}));
}
if (masaIndex === 9 && udayaTithi === 15) {
festivals.push(createFestival("Pausha Purnima", 'minor', {
description: "Sacred bathing day — start of month-long Magha mela bathing",
isFastingDay: true
}));
festivals.push(createFestival("Shakambhari Purnima", 'jayanti', {
description: "End of Shakambari Navratri — Goddess Shakambhari (vegetable goddess) worship"
}));
}
// =========================================================
// MAGHA (masa 10)
// =========================================================
if (masaIndex === 10 && udayaTithi === 1) {
festivals.push(createFestival("Magha Gupta Navratri Begins", 'minor', {
description: "Start of Magha Gupta Navratri — hidden Navratri for Tantric practice"
}));
}
if (masaIndex === 10 && udayaTithi === 5) {
festivals.push(createFestival("Vasant Panchami (Shri Panchami)", 'major', {
description: "Arrival of spring — Goddess Saraswati worship; yellow-clad celebrations",
observances: ["Saraswati puja", "Yellow clothes worn", "Books/instruments worshipped", "Kite flying in Punjab"]
}));
}
if (masaIndex === 10 && udayaTithi === 7) {
festivals.push(createFestival("Ratha Saptami", 'minor', {
description: "Sun god's chariot turns northward — Surya's seven-horse chariot worship",
observances: ["Surya puja", "Ayilyam leaves bath", "108 Surya Namaskara"]
}));
}
if (masaIndex === 10 && udayaTithi === 8) {
festivals.push(createFestival("Bhishma Ashtami", 'minor', {
description: "Death anniversary of Bhishma Pitamaha — tarpan offered for paternal lineage",
observances: ["Bhishma tarpan", "Pitru shraddha"]
}));
}
// FIX: Masik Shivaratri is suppressed in Magha — Maha Shivaratri
// is handled separately as a night-festival in getFestivals().
// The recurring block at the bottom explicitly guards masaIndex === 10.
if (masaIndex === 10 && udayaTithi === 13 && vara === 0) {
// Maghi is a solar festival (Makar Sankranti) celebrated in Punjab.
// It has no fixed lunar tithi; vara === 0 (Sunday) is used as a
// best-effort guard so it doesn't fire on every Magha Trayodashi.
// For accurate placement, use the solar SOLAR_FESTIVALS Makar Sankranti
// entry instead — this block is a lunar fallback only.
festivals.push(createFestival("Maghi (approx.)", 'minor', {
description: "Punjabi Maghi — traditionally on Makar Sankranti (solar). Lunar tithi 13 + Sunday is an approximation; prefer the solar festival entry.",
regional: ['Punjab', 'North'],
observances: ["Sacred bathing at Muktsar", "Prayers"]
}));
}
if (masaIndex === 10 && udayaTithi === 15) {
festivals.push(createFestival("Magha Purnima", 'minor', {
description: "Most sacred bathing day of Magha mela — charity and fast",
isFastingDay: true,
observances: ["Sangam snan", "Charity", "Lamp offering"]
}));
festivals.push(createFestival("Thai Pusam", 'major', {
description: "Worship of Lord Murugan (Skanda) — Kavadi festival",
regional: ['South', 'Tamil Nadu', 'Malaysia', 'Singapore'],
observances: ["Kavadi Attam", "Vel worship", "Piercing rituals"]
}));
}
if (masaIndex === 10 && udayaTithi === 19) {
festivals.push(createFestival("Sakat Chauth (Sankashti)", 'vrat', {
description: "Ganesha worship for removing obstacles — Tilkuta (sesame-jaggery) offered",
isFastingDay: true,
observances: ["Moonrise-time Ganesha puja", "Fasting until moonrise", "Sesame-jaggery offering"]
}));
}
// FIX: Mauni Amavasya moved here from Pausha (masa 9)
if (masaIndex === 10 && udayaTithi === 30) {
festivals.push(createFestival("Mauni Amavasya", 'minor', {