UNPKG

@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

302 lines 15.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getPanchangam = getPanchangam; exports.getPanchangamDetails = getPanchangamDetails; const astronomy_engine_1 = require("astronomy-engine"); const ayanamsa_1 = require("./ayanamsa"); const calculations_1 = require("./calculations"); const festivals_1 = require("./festivals"); const choghadiya_1 = require("./muhurta/choghadiya"); const gowri_1 = require("./muhurta/gowri"); const shoola_1 = require("./shoola"); const chandrashtama_1 = require("./chandrashtama"); const tarabalam_1 = require("./tarabalam"); /** * Validates inputs for getPanchangam / getPanchangamDetails. * @throws {Error} If any input is invalid. */ function validateInputs(date, observer, options) { // Date validation if (!(date instanceof Date) || isNaN(date.getTime())) { throw new Error('Invalid date: expected a valid Date object.'); } // Observer validation if (observer == null || typeof observer !== 'object') { throw new Error('Invalid observer: expected an Observer object with latitude, longitude, and height.'); } if (typeof observer.latitude !== 'number' || !isFinite(observer.latitude) || observer.latitude < -90 || observer.latitude > 90) { throw new Error(`Invalid observer latitude: ${observer.latitude}. Must be between -90 and 90.`); } if (typeof observer.longitude !== 'number' || !isFinite(observer.longitude) || observer.longitude < -180 || observer.longitude > 180) { throw new Error(`Invalid observer longitude: ${observer.longitude}. Must be between -180 and 180.`); } if (typeof observer.height !== 'number' || !isFinite(observer.height) || observer.height < -500 || observer.height > 100000) { throw new Error(`Invalid observer height: ${observer.height}. Must be between -500 and 100000 meters.`); } // Options validation if (options != null) { if (typeof options !== 'object') { throw new Error('Invalid options: expected a PanchangamOptions object.'); } if (options.timezoneOffset != null) { if (typeof options.timezoneOffset !== 'number' || !isFinite(options.timezoneOffset) || options.timezoneOffset < -720 || options.timezoneOffset > 840) { throw new Error(`Invalid timezoneOffset: ${options.timezoneOffset}. Must be between -720 and 840 minutes.`); } } } } function getPanchangam(date, observer, options) { validateInputs(date, observer, options); const sunrise = (0, calculations_1.getSunrise)(date, observer, options); const sunset = (0, calculations_1.getSunset)(date, observer, options); const moonrise = (0, calculations_1.getMoonrise)(date, observer, options); const moonset = (0, calculations_1.getMoonset)(date, observer, options); // Anchor: Use Sunrise for the Panchang Day attributes. Fallback to input date if no sunrise (Polar/Space). // This ensures Tithi, Nakshatra, Vara, etc. are consistent for the civil day. const anchorDate = sunrise || date; const ayanamsa = (0, ayanamsa_1.getAyanamsa)(anchorDate); // Calculate attributes at Anchor (Sunrise) const sunVector = (0, astronomy_engine_1.GeoVector)(astronomy_engine_1.Body.Sun, anchorDate, true); const moonVector = (0, astronomy_engine_1.GeoVector)(astronomy_engine_1.Body.Moon, anchorDate, true); const sunTrop = (0, astronomy_engine_1.Ecliptic)(sunVector).elon; const moonTrop = (0, astronomy_engine_1.Ecliptic)(moonVector).elon; const sunLon = (sunTrop - ayanamsa + 360) % 360; const moonLon = (moonTrop - ayanamsa + 360) % 360; const nakshatraStartTime = (0, calculations_1.findNakshatraStart)(anchorDate, ayanamsa); const nakshatraEndTime = (0, calculations_1.findNakshatraEnd)(anchorDate, ayanamsa); const tithiStartTime = (0, calculations_1.findTithiStart)(anchorDate); const tithiEndTime = (0, calculations_1.findTithiEnd)(anchorDate); const yogaEndTime = (0, calculations_1.findYogaEnd)(anchorDate, ayanamsa); const rahuKalam = (sunrise && sunset) ? (0, calculations_1.calculateRahuKalam)(sunrise, sunset, (0, calculations_1.getVara)(anchorDate, observer, options?.timezoneOffset)) : null; // For transitions, search from Sunrise to Next Sunrise let nextSunrise = null; if (sunrise) { const nextDay = new Date(sunrise.getTime()); nextDay.setDate(nextDay.getDate() + 1); nextSunrise = (0, calculations_1.getSunrise)(nextDay, observer, options); } const karanaTransitions = (sunrise && nextSunrise) ? (0, calculations_1.findKaranaTransitions)(sunrise, nextSunrise) : []; const tithiTransitions = (sunrise && nextSunrise) ? (0, calculations_1.findTithiTransitions)(sunrise, nextSunrise) : []; const nakshatraTransitions = (sunrise && nextSunrise) ? (0, calculations_1.findNakshatraTransitions)(sunrise, nextSunrise, ayanamsa) : []; const yogaTransitions = (sunrise && nextSunrise) ? (0, calculations_1.findYogaTransitions)(sunrise, nextSunrise, ayanamsa) : []; const abhijitMuhurta = (sunrise && sunset) ? (0, calculations_1.calculateAbhijitMuhurta)(sunrise, sunset) : null; let prevSunset; if (sunrise) { const prevDate = new Date(date); prevDate.setDate(prevDate.getDate() - 1); prevSunset = (0, calculations_1.getSunset)(prevDate, observer, options) || undefined; } const brahmaMuhurta = sunrise ? (0, calculations_1.calculateBrahmaMuhurta)(sunrise, prevSunset) : null; const govardhanMuhurta = (sunrise && sunset) ? (0, calculations_1.calculateGovardhanMuhurta)(sunrise, sunset) : null; // Vara should be based on Anchor Date (Sunrise) const vara = (0, calculations_1.getVara)(anchorDate, observer, options?.timezoneOffset); const yamagandaKalam = (sunrise && sunset) ? (0, calculations_1.calculateYamagandaKalam)(sunrise, sunset, vara) : null; const gulikaKalam = (sunrise && sunset) ? (0, calculations_1.calculateGulikaKalam)(sunrise, sunset, vara) : null; const durMuhurta = (sunrise && sunset) ? (0, calculations_1.calculateDurMuhurta)(sunrise, sunset, vara) : null; // Planetary positions at INSTANT (date), not Sunrise // Ayanamsa change in 1 day is small, so using anchor ayanamsa is acceptable for positions too, // or calculate instant ayanamsa. Let's reuse anchor for efficiency as difference is negligible. const rahuPos = (0, calculations_1.getRahuPosition)(date, ayanamsa); const planetaryPositions = { sun: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Sun, date, ayanamsa), moon: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Moon, date, ayanamsa), mars: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Mars, date, ayanamsa), mercury: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Mercury, date, ayanamsa), jupiter: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Jupiter, date, ayanamsa), venus: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Venus, date, ayanamsa), saturn: (0, calculations_1.getPlanetaryPosition)(astronomy_engine_1.Body.Saturn, date, ayanamsa), rahu: rahuPos, ketu: (0, calculations_1.getKetuPosition)(rahuPos) }; const chandrabalam = (0, calculations_1.calculateChandraBalam)(moonLon, sunLon); const currentHora = (0, calculations_1.getCurrentHora)(date, sunrise || date, observer, options?.timezoneOffset); const tithi = (0, calculations_1.getTithi)(sunLon, moonLon); const calendarType = options?.calendarType ?? 'purnimanta'; // Masa/Samvat should be based on Anchor (Day's Month/Year) const masa = (0, calculations_1.getMasa)(sunLon, moonLon, anchorDate, calendarType); const paksha = (0, calculations_1.getPaksha)(tithi); const ritu = (0, calculations_1.getRitu)(sunTrop); const ayana = (0, calculations_1.getAyana)(sunTrop); const samvat = (0, calculations_1.getSamvat)(anchorDate, masa.index); // Phase 3: Planetary Details const nakshatraPada = (0, calculations_1.getNakshatraPada)(moonLon); const moonRashi = (0, calculations_1.getRashi)(moonLon); const sunRashi = (0, calculations_1.getRashi)(sunLon); const sunNakshatra = (0, calculations_1.getSunNakshatra)(sunLon); const udayaLagna = (0, calculations_1.getUdayaLagna)(sunrise || date, observer, ayanamsa); const moonRashiTransitions = (sunrise && nextSunrise) ? (0, calculations_1.findRashiTransitions)(sunrise, nextSunrise, ayanamsa) : []; // Phase 4: Advanced Muhurta const nakshatraEnd = nakshatraTransitions.length > 0 ? nakshatraTransitions[0].endTime : nextSunrise; // Approximate if not found today const currentNakshatraStart = (0, calculations_1.findNakshatraStart)(date, ayanamsa) || date; // Fallback to now if start not found (e.g. earlier than search window) // Note: findNakshatraStart scans back 25h. If null, it means start is way back. // We calculate from current time if start not found. // Varjyam & Amrit Kalam: Check Current, Previous, and Next Nakshatras const amritKalam = []; const varjyam = []; const checkAndAdd = (nakIndex, start, end) => { if (!start || !end) return; const v = (0, calculations_1.calculateVarjyam)(nakIndex, start, end); varjyam.push(...v); const a = (0, calculations_1.calculateAmritKalam)(nakIndex, start, end); if (a) amritKalam.push(a); }; // 1. Current Nakshatra const currentNakIndex = (0, calculations_1.getNakshatra)(moonLon); const nStart = nakshatraStartTime || date; // Fallback const nEnd = nakshatraEndTime || nextSunrise || date; // Fallback checkAndAdd(currentNakIndex, nStart, nEnd); // 2. Previous Nakshatra (if current started after sunrise/start of day) // We need the Previous Nakshatra End = Current Nakshatra Start. if (nakshatraStartTime) { // If start is known and valid const prevNakIndex = (currentNakIndex - 1 + 27) % 27; // We need Previous Start. // We can find it by searching backwards from nakshatraStartTime. // We search from 1 minute before current start. const prevSearchDate = new Date(nakshatraStartTime.getTime() - 60000); const prevStart = (0, calculations_1.findNakshatraStart)(prevSearchDate, ayanamsa); if (prevStart) { checkAndAdd(prevNakIndex, prevStart, nakshatraStartTime); } } // 3. Next Nakshatra (if current ends today) // nakshatraEndTime is the End of Current. if (nakshatraEndTime) { const nextNakIndex = (currentNakIndex + 1) % 27; // Next Start = Current End. // We search from 1 minute after next start to find its end. const nextSearchDate = new Date(nakshatraEndTime.getTime() + 60000); const nextEnd = (0, calculations_1.findNakshatraEnd)(nextSearchDate, ayanamsa); if (nextEnd) { checkAndAdd(nextNakIndex, nakshatraEndTime, nextEnd); } } // Filter out periods completely outside "Today"? // Usually Drik shows periods even if they spill over to next day early morning. // We return all found relevant to the Nakshatras spanning "Today". // Sort const sortByStart = (a, b) => a.start.getTime() - b.start.getTime(); amritKalam.sort(sortByStart); varjyam.sort(sortByStart); return { tithi, nakshatra: (0, calculations_1.getNakshatra)(moonLon), yoga: (0, calculations_1.getYoga)(sunLon, moonLon), karana: (0, calculations_1.getKarana)(sunLon, moonLon), vara, ayanamsa, sunrise, sunset, moonrise, moonset, nakshatraStartTime, nakshatraEndTime, tithiStartTime, tithiEndTime, yogaEndTime, rahuKalamStart: rahuKalam?.start || null, rahuKalamEnd: rahuKalam?.end || null, karanaTransitions, tithiTransitions, nakshatraTransitions, yogaTransitions, moonRashiTransitions, // Unified List tithis: tithiTransitions, nakshatras: nakshatraTransitions, yogas: yogaTransitions, karanas: karanaTransitions, rashis: moonRashiTransitions, // Enhanced Vedic Features amritKalam, varjyam, // Special Yogas specialYogas: (0, calculations_1.getSpecialYoga)(vara, currentNakIndex), // Phase 6: Dasha System // We calculate Dasha based on the Moon position at the given 'date'. // This signifies: "If a child were born at this time, what is the Dasha?" // Or "What is the ruling Dasha for the day?" vimshottariDasha: (0, calculations_1.calculateVimshottariDasha)(moonLon, anchorDate), // Phase 7: Festivals (v3.0.0 API with Udaya Tithi) festivals: (0, festivals_1.getFestivals)({ date, observer, sunrise: sunrise || date, sunset: sunset || undefined, masa, paksha, // tithi from getTithi() is 0-indexed (0-29). Festivals expect 1-indexed (1-30). tithi: tithi + 1, nakshatra: currentNakIndex, vara, includeSolarFestivals: true, includeMultiDaySpans: true, calendarType: calendarType, timezoneOffset: options?.timezoneOffset }), // Phase 8: Advanced Muhurta (v2.1) choghadiya: (sunrise && sunset && nextSunrise) ? (0, choghadiya_1.calculateChoghadiya)(sunrise, sunset, nextSunrise, vara) : { day: [], night: [] }, gowri: (sunrise && sunset && nextSunrise) ? (0, gowri_1.calculateGowriPanchangam)(sunrise, sunset, nextSunrise, vara) : { day: [], night: [] }, abhijitMuhurta, brahmaMuhurta, govardhanMuhurta, yamagandaKalam, gulikaKalam, durMuhurta, planetaryPositions, chandrabalam, currentHora, dishaShoola: (0, shoola_1.getDishaShoola)(vara), chandrashtama: (options?.birthMoonRashi !== undefined) ? (0, chandrashtama_1.getChandrashtama)(options.birthMoonRashi, moonRashi.index) : null, tarabalam: (options?.birthNakshatra !== undefined) ? (0, tarabalam_1.getTarabalam)(options.birthNakshatra, (0, calculations_1.getNakshatra)(moonLon)) : null, // Phase 3: Planetary Details nakshatraPada, moonRashi, sunRashi, sunNakshatra, udayaLagna, // Phase 2: Calendar Units masa, paksha, ritu, ayana, samvat }; } function getPanchangamDetails(date, observer, options) { validateInputs(date, observer, options); const panchangam = getPanchangam(date, observer, options); const sunrise = (0, calculations_1.getSunrise)(date, observer, options); const sunset = (0, calculations_1.getSunset)(date, observer, options); const nakshatraEndTime = (0, calculations_1.findNakshatraEnd)(date, panchangam.ayanamsa); return { ...panchangam, sunrise, sunset, nakshatraEndTime, }; } //# sourceMappingURL=panchangam.js.map