From 7780dc7ca28b7c4f1e9e8e1141f3ab98c1ad4851 Mon Sep 17 00:00:00 2001 From: khumnath Date: Wed, 13 Aug 2025 10:25:16 +0545 Subject: [PATCH 1/8] added events display in day detail and monthly events below calendar. now event data is dummy for testing only --- qml/CalendarGrid.qml | 185 ++++++++++++++++-------------- qml/CalendarLogic.qml | 52 ++++++--- qml/DayCell.qml | 15 +++ qml/EventDisplay.qml | 63 +++++++++++ qml/PanchangaDetailDialog.qml | 187 +++++++++++++++++-------------- qml/main.qml | 2 + resources.qrc | 2 + resources/EventData.js | 80 +++++++++++++ resources/PanchangaCalculator.js | 89 +++++++++++++-- 9 files changed, 480 insertions(+), 195 deletions(-) create mode 100644 qml/EventDisplay.qml create mode 100644 resources/EventData.js diff --git a/qml/CalendarGrid.qml b/qml/CalendarGrid.qml index 6d9cbc1..4706b6c 100644 --- a/qml/CalendarGrid.qml +++ b/qml/CalendarGrid.qml @@ -4,64 +4,118 @@ import QtQuick.Controls 2.15 import "qrc:/qml/" // CalendarGrid.qml -GridLayout { - id: calendarGrid - columns: 7 - rowSpacing: 0 - columnSpacing: 0 +ColumnLayout { + id: calendarGridRoot Layout.fillWidth: true - Layout.fillHeight: true - Layout.margins: 20 - Layout.topMargin: 10 + // Properties property alias calendarModel: repeater.model + property alias eventListModel: eventLabel.eventModel property var theme + // Signals signal dayClicked(var panchanga) - Repeater { - id: repeater - delegate: Item { - Layout.fillWidth: true - Layout.fillHeight: modelData.type === "day" || modelData.type === "empty" - Layout.preferredHeight: modelData.type === "header" ? 35 : -1 + // Components - Loader { - id: delegateLoader - anchors.fill: parent + // Calendar grid layout + GridLayout { + id: calendarGrid + columns: 7 + rowSpacing: 0 + columnSpacing: 0 + Layout.fillWidth: true + Layout.preferredHeight: parent.width + Layout.margins: 10 + Layout.topMargin: 10 + //Layout.bottomMargin: 10 + + Repeater { + id: repeater + delegate: Item { + Layout.fillWidth: true + Layout.fillHeight: modelData.type === "day" || modelData.type === "empty" + Layout.preferredHeight: modelData.type === "header" ? 35 : -1 + + Loader { + id: delegateLoader + anchors.fill: parent - sourceComponent: { - if (modelData.type === "header") { - return headerComponent; - } else if (modelData.type === "day") { - return dayComponent; - } else { // for "empty" type - return emptyComponent; + sourceComponent: { + if (modelData.type === "header") { + return headerComponent; + } else if (modelData.type === "day") { + return dayComponent; + } else { + return emptyComponent; + } + } + + onLoaded: { + if (modelData.type === "day") { + item.bsDay = modelData.bsDay; + item.adDay = modelData.adDay; + item.tithi = modelData.tithi; + item.isToday = modelData.isToday; + item.isSaturday = modelData.isSaturday; + item.hasEvent = modelData.hasEvent; + item.theme = calendarGridRoot.theme; + item.clicked.connect(function() { + calendarGridRoot.dayClicked(modelData.panchanga) + }); + } else if (modelData.type === "header") { + item.text = modelData.text; + item.theme = calendarGridRoot.theme; + item.cellIndex = index; + } } } + } + } + } + + // Event List Footer + Rectangle { + id: eventFooter + Layout.fillWidth: true + //Layout.topMargin: 10 + implicitHeight: eventLabel.paintedHeight + 20 + color: theme.secondaryBg + radius: 6 + visible: eventLabel.eventModel && eventLabel.eventModel.length > 0 - onLoaded: { - if (modelData.type === "day") { - item.bsDay = modelData.bsDay; - item.adDay = modelData.adDay; - item.tithi = modelData.tithi; - item.isToday = modelData.isToday; - item.isSaturday = modelData.isSaturday; - item.theme = calendarGrid.theme; - item.clicked.connect(function() { - calendarGrid.dayClicked(modelData.panchanga) - }); - } else if (modelData.type === "header") { - item.text = modelData.text; - item.theme = calendarGrid.theme; - item.cellIndex = index; + Label { + id: eventLabel + anchors.fill: parent + anchors.margins: 10 + + property var eventModel: [] // Model reference + + // Bind the text property to a function that builds the string + text: { + var str = ""; + if (eventModel) { + for (var i = 0; i < eventModel.length; i++) { + var item = eventModel[i]; + str += item.bsDay + " :\u00A0" + item.eventName; + if (i < eventModel.length - 1) { + str += " • "; + } } } + return str; } + + font.pixelSize: 14 + color: theme ? theme.secondaryText : "black" + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter } } + // Component Definitions Component { id: headerComponent Item { @@ -78,56 +132,15 @@ GridLayout { border.color: theme.borderColor } - Rectangle { - visible: cellIndex === 0 - width: headerBackground.radius - height: headerBackground.radius - color: headerBackground.color - anchors.top: parent.top - anchors.right: parent.right - } - Rectangle { - visible: cellIndex === 0 - width: headerBackground.radius - height: headerBackground.radius - color: headerBackground.color - anchors.bottom: parent.bottom - anchors.left: parent.left - } - Rectangle { - visible: cellIndex === 6 - width: headerBackground.radius - height: headerBackground.radius - color: headerBackground.color - anchors.top: parent.top - anchors.left: parent.left - } - Rectangle { - visible: cellIndex === 6 - width: headerBackground.radius - height: headerBackground.radius - color: headerBackground.color - anchors.bottom: parent.bottom - anchors.left: parent.left - } - Rectangle { - visible: cellIndex === 0 || cellIndex === 6 - width: headerBackground.radius - height: headerBackground.radius - color: headerBackground.color - anchors.bottom: parent.bottom - anchors.right: parent.right - } + Rectangle { visible: cellIndex === 0; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.top: parent.top; anchors.right: parent.right } + Rectangle { visible: cellIndex === 0; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.bottom: parent.bottom; anchors.left: parent.left } + Rectangle { visible: cellIndex === 6; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.top: parent.top; anchors.left: parent.left } + Rectangle { visible: cellIndex === 6; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.bottom: parent.bottom; anchors.left: parent.left } + Rectangle { visible: cellIndex === 0 || cellIndex === 6; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.bottom: parent.bottom; anchors.right: parent.right } Label { text: headerItemContainer.text - color: { - if (cellIndex === 6) { - return "#E4080A" - } else { - return theme.accentText; - } - } + color: (cellIndex === 6) ? "#E4080A" : theme.accentText font.bold: true font.pixelSize: 14 anchors.centerIn: parent diff --git a/qml/CalendarLogic.qml b/qml/CalendarLogic.qml index f2dec23..1fe9ed5 100644 --- a/qml/CalendarLogic.qml +++ b/qml/CalendarLogic.qml @@ -14,6 +14,7 @@ QtObject { property int currentBsYear: 2081 property int currentBsMonthIndex: 1 property var calendarModel: [] + property var currentMonthEvents: [] // Holds events for the current month property string currentBsLabelStr: "" property string currentAdLabelStr: "" property string prevMonthName: "" @@ -59,7 +60,9 @@ QtObject { } function renderCalendarByBs(year, monthIndex, preserveAdState = false) { - calendarModel = []; + var newCalendarModel = []; + var eventsByDay = {}; // Use an object to group events by day + currentBsYear = year; currentBsMonthIndex = monthIndex; var info = Panchanga.getBikramMonthInfo(year, monthIndex); @@ -69,23 +72,18 @@ QtObject { } if (!preserveAdState) { - // LOGIC to determine the representative AD month var bsMonthStartDate = Panchanga.fromBikramSambat(year, monthIndex, 1); var startAdYear = bsMonthStartDate.getUTCFullYear(); var startAdMonth = bsMonthStartDate.getUTCMonth(); - var nextAdMonth = (startAdMonth + 1) % 12; var nextAdYear = (startAdMonth === 11) ? startAdYear + 1 : startAdYear; var firstOfNextAdMonth = new Date(Date.UTC(nextAdYear, nextAdMonth, 1)); - var bsMonthEndDate = Panchanga.fromBikramSambat(year, monthIndex, info.totalDays); if (firstOfNextAdMonth <= bsMonthEndDate) { - // Prefer the later AD month if its first day is in the BS month. currentAdYear = nextAdYear; currentAdMonth = nextAdMonth; } else { - // Otherwise, use the starting AD month. currentAdYear = startAdYear; currentAdMonth = startAdMonth; } @@ -98,13 +96,12 @@ QtObject { var daysInMonth = info.totalDays; var startDay = info.startDayOfWeek; - var model = []; var weekdaysNe = ["आइतबार", "सोमबार", "मङ्गलबार", "बुधबार", "बिहीबार", "शुक्रबार", "शनिबार"]; for (var i = 0; i < 7; ++i) { - model.push({ type: "header", text: weekdaysNe[i] }); + newCalendarModel.push({ type: "header", text: weekdaysNe[i] }); } for (i = 0; i < startDay; ++i) { - model.push({ type: "empty" }); + newCalendarModel.push({ type: "empty" }); } for (var day = 1; day <= daysInMonth; ++day) { var adDate = Panchanga.fromBikramSambat(year, monthIndex, day); @@ -114,14 +111,45 @@ QtObject { } var isToday = adDate.toDateString() === new Date().toDateString(); var isSaturday = (startDay + day - 1) % 7 === 6; + var hasEventForDay = result.events && result.events.length > 0; + + if (hasEventForDay) { + var devanagariDay = toDevanagari(day); + if (!eventsByDay[devanagariDay]) { + eventsByDay[devanagariDay] = []; // Initialize array if it doesn't exist + } + for (var j = 0; j < result.events.length; j++) { + eventsByDay[devanagariDay].push(result.events[j].name); + } + } + result.monthName = info.monthName; - model.push({ + newCalendarModel.push({ type: "day", bsDay: day, adDay: adDate.getDate(), tithi: result.tithi, isToday: isToday, isSaturday: isSaturday, + hasEvent: hasEventForDay, gregorianDate: result.gregorianDate, panchanga: result }); } - calendarModel = model; + + // Process the grouped events + var newMonthEvents = []; + // Sort the days to ensure events are listed in chronological order + var sortedDays = Object.keys(eventsByDay).sort(function(a, b) { + return parseInt(fromDevanagari(a)) - parseInt(fromDevanagari(b)); + }); + + for (i = 0; i < sortedDays.length; i++) { + var bsDay = sortedDays[i]; + newMonthEvents.push({ + bsDay: bsDay, + eventName: eventsByDay[bsDay].join(", ") + }); + } + + calendarModel = newCalendarModel; + currentMonthEvents = newMonthEvents; + currentBsLabelStr = toDevanagari(year) + " " + info.monthName; currentAdLabelStr = getGregorianRange(year, monthIndex); var prevMonthIndex = monthIndex - 1; @@ -143,10 +171,8 @@ QtObject { function renderCalendarByAd(year, monthIndex) { currentAdYear = year; currentAdMonth = monthIndex; - var date = new Date(Date.UTC(year, monthIndex, 1)); var bsInfo = Panchanga.calculate(date); - renderCalendarByBs(bsInfo.bsYear, bsInfo.bsMonthIndex, true); } diff --git a/qml/DayCell.qml b/qml/DayCell.qml index af2e323..f4226b3 100644 --- a/qml/DayCell.qml +++ b/qml/DayCell.qml @@ -12,6 +12,7 @@ Rectangle { property string tithi: "" property bool isToday: false property bool isSaturday: false + property bool hasEvent: false property var theme signal clicked() @@ -32,6 +33,20 @@ Rectangle { } border.width: isToday ? 2 : 1 + // Event Indicator + Rectangle { + id: eventIndicator + width: 6 + height: 6 + radius: 4 + color: "orange" + anchors.left: parent.left + anchors.top: parent.top + anchors.margins: 5 + visible: hasEvent + z: 1 + } + Label { text: Panchanga.toDevanagari(bsDay || 0) font.bold: true diff --git a/qml/EventDisplay.qml b/qml/EventDisplay.qml new file mode 100644 index 0000000..c5c8cb7 --- /dev/null +++ b/qml/EventDisplay.qml @@ -0,0 +1,63 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +// EventDisplay.qml (used in PanchangaDetailDialog +ColumnLayout { + id: eventRoot + Layout.fillWidth: true + spacing: 8 + + // Properties + property var theme + property var events: [] + + // Components + + // Title for the events section. Only visible if there are events. + Label { + text: "कार्यक्रम हरु" + font.pixelSize: 18 + font.bold: true + color: theme ? theme.accentText : "darkblue" + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: 5 + visible: events.length > 0 + } + + //Label to display all events, joined by commas. + Label { + text: { + if (events.length > 0) { + return events.map(function(event) { + return event.name + (event.detail ? ": " + event.detail : ""); + }).join(", "); + } + return ""; + } + font.pixelSize: 16 + color: theme ? theme.primaryText : "black" + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + Layout.fillWidth: true + visible: events.length > 0 + } + + // Message to display if no events are found for the selected day. + Label { + text: "कुनै कार्यक्रम भेटिएन" + font.pixelSize: 16 + font.italic: true + color: theme ? theme.secondaryText : "grey" + horizontalAlignment: Text.AlignHCenter + Layout.fillWidth: true + visible: events.length === 0 + } + + // Bottom margin to the event section. + Rectangle { + height: 20 + color: "transparent" + Layout.fillWidth: true + } +} diff --git a/qml/PanchangaDetailDialog.qml b/qml/PanchangaDetailDialog.qml index 9573ea6..3e9baff 100644 --- a/qml/PanchangaDetailDialog.qml +++ b/qml/PanchangaDetailDialog.qml @@ -6,109 +6,74 @@ import "qrc:/qml/" // PanchangaDetailDialog.qml Dialog { - id: panchangaDetailDialogRoot // Changed id to avoid name collision + id: panchangaDetailDialogRoot width: Math.min(parent.width * 0.9, 600) - height: Math.min(parent.height * 0.8, 550) + height: Math.min(contentItem.implicitHeight, parent.height * 0.8) modal: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside x: (parent.width - width) / 2 y: (parent.height - height) / 2 padding: 0 + background: null + // Properties property var theme property var panchangaData: null property bool debugVisible: false property string currentDebugInfo: "" - background: Rectangle { + // Components + contentItem: Rectangle { + id: contentRect + width: panchangaDetailDialogRoot.width + implicitHeight: contentColumn.implicitHeight color: theme ? theme.secondaryBg : "white" radius: 12 border.color: theme ? theme.borderColor : "grey" border.width: 1 clip: true - } - - contentItem: Item { - width: panchangaDetailDialogRoot.width - height: panchangaDetailDialogRoot.height - - Rectangle { - id: modalHeader - width: parent.width - height: 60 - color: theme ? theme.secondaryBg : "white" - Label { - id: modalTitle - text: "दिनको विवरण" - font.pixelSize: 20 - font.bold: true - color: theme ? theme.modalHeaderText : "black" - anchors.centerIn: parent - z: 1 - } - } - - Rectangle { - id: modalFooter + ColumnLayout { + id: contentColumn width: parent.width - height: 65 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - color: theme ? theme.secondaryBg : "white" - Button { - text: "बन्द गर्नुहोस्" - anchors.centerIn: parent - onClicked: panchangaDetailDialogRoot.close() + // Header section of the dialog. + Rectangle { + id: modalHeader + Layout.fillWidth: true + height: 60 + color: "transparent" - background: Rectangle { - color: theme ? theme.tertiaryBg : "lightgrey" - border.color: parent.hovered && theme ? theme.accent : "gray" - border.width: parent.hovered ? 2 : 1 - radius: 12 - } - - contentItem: Text { - text: parent.text - font: parent.font - color: theme ? theme.primaryText : "black" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - padding: 5 + Label { + id: modalTitle + text: "दिनको विवरण" + font.pixelSize: 20 + font.bold: true + color: theme ? theme.modalHeaderText : "black" + anchors.centerIn: parent + z: 1 } } - } - - Flickable { - id: flickableArea - anchors { - left: parent.left - right: parent.right - top: modalHeader.bottom - bottom: modalFooter.top - leftMargin: 30 - rightMargin: 20 - } - clip: false - contentHeight: scrollContent.height + // The main content area. ColumnLayout { - id: scrollContent - width: parent.width + id: contentArea + Layout.fillWidth: true spacing: 15 Button { id: showDebugButton - visible: !window.debugVisible + visible: !panchangaDetailDialogRoot.debugVisible text: "डिबग जानकारी देखाउनुहोस्" Layout.fillWidth: true height: 40 - onClicked: debugVisible = true + onClicked: panchangaDetailDialogRoot.debugVisible = true + Layout.leftMargin: 30 + Layout.rightMargin: 20 background: Rectangle { color: theme.tertiaryBg - border.color: parent.hovered ? theme.accent : "gray" + border.color: parent.hovered ? theme.accent : "gray" border.width: parent.hovered ? 2 : 1 radius: 12 } @@ -123,28 +88,33 @@ Dialog { } } + // Layout for the Panchanga details। ColumnLayout { id: panchangaDetails - visible: !debugVisible - spacing: 15 + visible: !panchangaDetailDialogRoot.debugVisible + spacing: 8 Layout.fillWidth: true + Layout.leftMargin: 30 + Layout.rightMargin: 20 } Rectangle { id: debugInfoArea - visible: debugVisible + visible: panchangaDetailDialogRoot.debugVisible z: 99 Layout.fillWidth: true - implicitHeight: debugInfoText.paintedHeight + 10 + implicitHeight: debugInfoText.paintedHeight + 20 color: "black" border.color: theme ? theme.accent : "blue" border.width: 1 radius: 8 + Layout.leftMargin: 30 + Layout.rightMargin: 20 Flickable { anchors.fill: parent contentWidth: debugInfoText.paintedWidth - contentHeight: debugInfoText.paintedHeight + 10 + contentHeight: debugInfoText.paintedHeight clip: true TextEdit { @@ -163,11 +133,13 @@ Dialog { Button { id: hideDebugButton - visible: debugVisible + visible: panchangaDetailDialogRoot.debugVisible text: "डिबग लुकाउनुहोस्" Layout.fillWidth: true height: 40 - onClicked: debugVisible = false + onClicked: panchangaDetailDialogRoot.debugVisible = false + Layout.leftMargin: 30 + Layout.rightMargin: 20 background: Rectangle { radius: 8 @@ -184,25 +156,68 @@ Dialog { } } } + + // Footer section with the close button. + Rectangle { + id: modalFooter + Layout.fillWidth: true + height: 65 + color: "transparent" + + Button { + text: "बन्द गर्नुहोस्" + anchors.centerIn: parent + onClicked: panchangaDetailDialogRoot.close() + + background: Rectangle { + color: theme ? theme.tertiaryBg : "lightgrey" + border.color: parent.hovered && theme ? theme.accent : "gray" + border.width: parent.hovered ? 2 : 1 + radius: 12 + } + + contentItem: Text { + text: parent.text + font: parent.font + color: theme ? theme.primaryText : "black" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + padding: 5 + } + } + } } } + + // Handlers and Functions onOpened: { if (panchangaData) { clearPanchangaDetails(); modalTitle.text = panchangaData.gregorianDate; + + var eventComponent = Qt.createComponent("EventDisplay.qml"); + if (eventComponent.status === Component.Ready) { + var eventObj = eventComponent.createObject(panchangaDetails, { + "theme": theme, + "events": panchangaData.events + }); + } else { + console.log("Error creating event component:", eventComponent.errorString()); + } + var details = [ - createDetailRow("बिक्रम संवत", toDevanagari(panchangaData.bsYear) + " " + panchangaData.monthName + " " + toDevanagari(panchangaData.bsDay)), - createDetailRow("वार", panchangaData.weekday), - createDetailRow("तिथि", panchangaData.tithi + " (" + panchangaData.paksha + ")"), - createDetailRow("नक्षत्र", panchangaData.nakshatra), - createDetailRow("योग", panchangaData.yoga), - createDetailRow("करण", panchangaData.karana), - createDetailRow("सूर्य राशि", panchangaData.sunRashi), - createDetailRow("चन्द्र राशि", panchangaData.moonRashi), - createDetailRow("उदयास्त", "सूर्योदय " + panchangaData.sunrise + " | सूर्यास्त " + panchangaData.sunset), - createDetailRow("अधिक/क्षय मास", panchangaData.adhikaMasa) - ]; + createDetailRow("बिक्रम संवत", toDevanagari(panchangaData.bsYear) + " " + panchangaData.monthName + " " + toDevanagari(panchangaData.bsDay)), + createDetailRow("वार", panchangaData.weekday), + createDetailRow("तिथि", panchangaData.tithi + " (" + panchangaData.paksha + ")"), + createDetailRow("नक्षत्र", panchangaData.nakshatra), + createDetailRow("योग", panchangaData.yoga), + createDetailRow("करण", panchangaData.karana), + createDetailRow("सूर्य राशि", panchangaData.sunRashi), + createDetailRow("चन्द्र राशि", panchangaData.moonRashi), + createDetailRow("उदयास्त", "सूर्योदय " + panchangaData.sunrise + " | सूर्यास्त " + panchangaData.sunset), + createDetailRow("अधिक/क्षय मास", panchangaData.adhikaMasa) + ]; for (var i = 0; i < details.length; ++i) { details[i].parent = panchangaDetails; } diff --git a/qml/main.qml b/qml/main.qml index 947fd9d..3049f3f 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -322,8 +322,10 @@ ApplicationWindow { panchangaDetailDialog.panchangaData = panchanga panchangaDetailDialog.open() } + eventListModel: calendarLogic.currentMonthEvents } + Rectangle { Layout.fillWidth: true Layout.preferredHeight: 100 diff --git a/resources.qrc b/resources.qrc index 0a549c2..8688035 100644 --- a/resources.qrc +++ b/resources.qrc @@ -15,5 +15,7 @@ qml/NavigationBar.qml qml/PanchangaDetailDialog.qml qml/Theme.qml + resources/EventData.js + qml/EventDisplay.qml diff --git a/resources/EventData.js b/resources/EventData.js new file mode 100644 index 0000000..c111c57 --- /dev/null +++ b/resources/EventData.js @@ -0,0 +1,80 @@ +// EventsData.js + +// Gregorian events for every year or with specific start/end year ranges. +var gregorianEvents = [ + { + event: "Event1Greg", + dateType: "gregorian", + date: "08/10", // August 10 + detail: "Test event for August 2025.", + category: "Test", + startYear: 2025, + endYear: 2025 + }, + { + event: "Event2Greg", + dateType: "gregorian", + date: "09/05", // September 5 + detail: "Test event for September 2025.", + category: "Test", + startYear: 2025, + endYear: 2025 + }, + { + event: "Event3GregRecu", + dateType: "gregorian", + date: "08/15", // August 15 + detail: "Recurring Gregorian test event.", + category: "Test" + // No startYear or endYear means it recurs every year + }, +]; + +// Bikram recurring events (based on BS month/day) for every year or with specific start/end year ranges. +var bikramRecurringEvents = [ + { + event: "Event0BikramRecu", + dateType: "brecurring", + date: "04/05", // Shrawan 5 + detail: "Recurring test event for Shrawan.", + category: "Test", + startYear: 2082, + endYear: 2085 + }, + { + event: "Event1BikramRecu", + dateType: "brecurring", + date: "04/08", // Shrawan 8 + detail: "Recurring test event for Shrawan.", + category: "Test", + startYear: 2070, + endYear: 2082 + }, + { + event: "Event2BikramRecu", + dateType: "brecurring", + date: "05/10", // Bhadrapad 10 + detail: "Recurring test event for Bhadrapad.", + category: "Test", + startYear: 2082, + endYear: 2089 + } +]; + +// Bikram fixed events (specific BS year/month/day). +var bikramFixedEvents = [ + { + event: "Event1BikramFixed", + dateType: "bikram", + date: "2082/04/15", // BS Year 2082, Month 4 (Shrawan), Day 15 + detail: "Fixed test event for Shrawan 2082.", + category: "Test" + }, + { + event: "Event2BikramFixed", + dateType: "bikram", + date: "2082/05/20", // BS Year 2082, Month 5 (Bhadrapad), Day 20 + detail: "Fixed test event for Bhadrapad 2082.", + category: "Test" + } +]; diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index 932a810..fc5b60e 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -21,14 +21,15 @@ .pragma library .import "qrc:/resources/PreCalculated_Data.js" as Bsdata +.import "qrc:/resources/EventData.js" as EventsData -// --- Caching --- +// Caching var calculationCache = {}; function clearCache() { calculationCache = {}; } -// --- Surya Siddhanta Constants --- +// Surya Siddhanta Constants var YugaRotation = { 'star': 1582237828, 'sun': 4320000, @@ -47,7 +48,7 @@ var PlanetApogee = { 'sun': 77 + 17 / 60 }; var PlanetCircumm = { 'sun': 13 + 50 / 60, 'moon': 31 + 50 / 60 }; -// --- Panchanga Names --- +// Panchanga Names var tithiNamesList = [ "प्रतिपदा", "द्वितीया", "तृतीया", "चतुर्थी", "पञ्चमी", "षष्ठी", "सप्तमी", "अष्टमी", "नवमी", "दशमी", "एकादशी", "द्वादशी", "त्रयोदशी", "चतुर्दशी", "पूर्णिमा", "अमावस्या" @@ -81,7 +82,7 @@ var nepaliGregorianMonths = [ ]; -// --- Helper Functions --- +// Helper Functions function zero360(x) { x = x - Math.floor(x / 360) * 360; return x < 0 ? x + 360 : x; @@ -98,6 +99,10 @@ function toDevanagari(num) { }).join(''); } +function formatMonthDay(month, day) { + return `${(month < 10 ? '0' : '')}${month}/${(day < 10 ? '0' : '')}${day}`; +} + function toJulianDay(year, month, day) { // In QML, month is 0-indexed, so we add 1 for calculations var m = month + 1; @@ -134,7 +139,7 @@ function fromJulianDay(jd) { return new Date(Date.UTC(year, month - 1, day)); } -// --- Surya Siddhanta Core Calculations (Used as fallback) --- +// Surya Siddhanta Core Calculations (Used as fallback) function meanLongitude(ahar, rotation) { return zero360(rotation * ahar * 360 / YugaCivilDays); } @@ -245,7 +250,7 @@ function getSunriseSunset(date, lat, lon, tz) { return { sunrise: formatTime(rise), sunset: formatTime(set) }; } -// --- Data-Driven Conversion and Info Functions --- +// Data-Driven Conversion and Info Functions function fromBikramSambat(bsYear, monthIndex, day) { // Use data if within range, otherwise fallback to astronomical calculation @@ -328,14 +333,75 @@ function getTodayBsInfo() { return getBikramSambatInfo(ahar, sunLong); } -// --- Shared Name Resolution Utility --- +// Shared Name Resolution Utility function resolveTithiName(tithiDay, paksha) { if (paksha === "कृष्ण पक्ष" && tithiDay === 15) return tithiNamesList[15]; // Amavasya if (paksha === "शुक्ल पक्ष" && tithiDay === 15) return tithiNamesList[14]; // Purnima return tithiNamesList[tithiDay - 1]; } -// --- Main Calculation Function --- +// Event Calculation Function +function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { +    const events = []; +    const gregorianMonth = date.getUTCMonth() + 1; // 1-indexed month +    const gregorianDay = date.getUTCDate(); +    const gregorianYear = date.getUTCFullYear(); + +    const formattedGregorianDate = formatMonthDay(gregorianMonth, gregorianDay); +    const formattedBikramRecurringDate = formatMonthDay(bsMonthIndex + 1, bsDay); // bsMonthIndex is 0-indexed + +    // Check Gregorian events +    for (var i = 0; i < EventsData.gregorianEvents.length; i++) { +        var event = EventsData.gregorianEvents[i]; +        if (event.dateType === "gregorian" && event.date === formattedGregorianDate) { +            var isValidYear = (!event.startYear || gregorianYear >= event.startYear) && +                              (!event.endYear || gregorianYear <= event.endYear); +            if (isValidYear) { +                events.push({ +                    name: event.event, +                    detail: event.detail, +                    category: event.category +                }); +            } +        } +    } + +    // Check Bikram recurring events +    for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { +        let event = EventsData.bikramRecurringEvents[j]; +        if (event.dateType === "brecurring" && event.date === formattedBikramRecurringDate) { +            const isValidYear = (!event.startYear || bsYear >= event.startYear) && +                              (!event.endYear || bsYear <= event.endYear); +            if (isValidYear) { +                events.push({ +                    name: event.event, +                    detail: event.detail, +                    category: event.category +                }); +            } +        } +    } + +    // Check Bikram fixed events +    for (var k = 0; k < EventsData.bikramFixedEvents.length; k++) { +        let event = EventsData.bikramFixedEvents[k]; +        if (event.dateType === "bikram") { +            const eventDateParts = event.date.split('/').map(Number); +            if (eventDateParts[0] === bsYear && +                eventDateParts[1] === (bsMonthIndex + 1) && // Convert back to 1-indexed for comparison +                eventDateParts[2] === bsDay) { +                events.push({ +                    name: event.event, +                    detail: event.detail, +                    category: event.category +                }); +            } +        } +    } +    return events; +} + +// Main Calculation Function function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { var cacheKey = "panchanga_" + date.getTime(); if (calculationCache[cacheKey]) return calculationCache[cacheKey]; @@ -362,6 +428,9 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { // Determine if the calculation is a fallback var isComputed = (bsInfo.year < Bsdata.BS_START_YEAR || bsInfo.year > Bsdata.BS_END_YEAR); + // Get events for the current date + var events = getEventsForDate(date, bsInfo.year, bsInfo.monthIndex, bsInfo.day); + var result = { gregorianDate: Qt.formatDateTime(date, "dddd, MMMM d, yyyy"), bikramSambat: `${bsInfo.year} ${bsInfo.monthName} ${bsInfo.day}`, @@ -380,14 +449,14 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { sunRashi: rashis[Math.floor(sunLong / 30) % 12], moonRashi: rashis[Math.floor(moonLong / 30) % 12], adhikaMasa: calculateAdhikaMasa(ahar), + events: events, isComputed: isComputed }; calculationCache[cacheKey] = result; return result; } - -// --- Debug calculations. --- +// Debug calculations. function generateDebugInfo(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { var cacheKey = "debug_" + date.getTime(); if (calculationCache[cacheKey]) return calculationCache[cacheKey]; From e6f6f9e6be30376899b5f7955be77347e5d56d32 Mon Sep 17 00:00:00 2001 From: khumnath Date: Wed, 13 Aug 2025 19:02:28 +0545 Subject: [PATCH 2/8] some core logic fixed in javascript. added some of real events for test --- resources/EventData.js | 413 ++++++++++++++++++++++++++---- resources/PanchangaCalculator.js | 419 +++++++++++++++++++++---------- 2 files changed, 653 insertions(+), 179 deletions(-) diff --git a/resources/EventData.js b/resources/EventData.js index c111c57..2a7f809 100644 --- a/resources/EventData.js +++ b/resources/EventData.js @@ -3,78 +3,403 @@ // Gregorian events for every year or with specific start/end year ranges. var gregorianEvents = [ { - event: "Event1Greg", + event: "New Year's Day", dateType: "gregorian", - date: "08/10", // August 10 - detail: "Test event for August 2025.", - category: "Test", - startYear: 2025, - endYear: 2025 + date: "01/01", // January 1 + detail: "Celebration of the new Gregorian year.", + category: "International Day", }, { - event: "Event2Greg", + event: "Valentine's Day", dateType: "gregorian", - date: "09/05", // September 5 - detail: "Test event for September 2025.", - category: "Test", - startYear: 2025, - endYear: 2025 + date: "02/14", // February 14 + detail: "International day of love. Nepali: प्रणय दिवस.", + category: "International Day" }, { - event: "Event3GregRecu", + event: "International Women's Day", dateType: "gregorian", - date: "08/15", // August 15 - detail: "Recurring Gregorian test event.", - category: "Test" - // No startYear or endYear means it recurs every year + date: "03/08", // March 8 + detail: "Global day celebrating womanhood. Nepali: नारी दिवस.", + category: "International Day" }, + { + event: "World Health Day", + dateType: "gregorian", + date: "04/07", // April 7 + detail: "A global health awareness day. Nepali: विश्व स्वास्थ्य दिवस.", + category: "International Day" + }, + { + event: "International Workers' Day", + dateType: "gregorian", + date: "05/01", // May 1 + detail: "Also known as May Day. Nepali: अन्तर्राष्ट्रिय श्रमिक दिवस.", + category: "International Day" + }, + { + event: "World Environment Day", + dateType: "gregorian", + date: "06/05", // June 5 + detail: "Day for environmental awareness and action. Nepali: विश्व वातावरण दिवस.", + category: "International Day" + }, + { + event: "International Day of Yoga", + dateType: "gregorian", + date: "06/21", // June 21 + detail: "Global day to celebrate yoga. Nepali: विश्व योग दिवस.", + category: "International Day" + }, + { + event: "World Population Day", + dateType: "gregorian", + date: "07/11", // July 11 + detail: "Day to raise awareness of global population issues. Nepali: विश्व जनसंख्या दिवस.", + category: "International Day" + }, + { + event: "International Youth Day", + dateType: "gregorian", + date: "08/12", // August 12 + detail: "Day to celebrate young people as agents of change. Nepali: अन्तर्राष्ट्रिय युवा दिवस.", + category: "International Day" + }, + { + event: "International Human Rights Day", + dateType: "gregorian", + date: "12/10", // December 10 + detail: "Commemorates the adoption of the Universal Declaration of Human Rights. Nepali: अन्तर्राष्ट्रिय मानव अधिकार दिवस.", + category: "International Day" + }, + { + event: "Christmas Day", + dateType: "gregorian", + date: "12/25", // December 25 + detail: "Christian festival celebrating the birth of Jesus. Nepali: क्रिसमस-डे.", + category: "Festival" + } ]; // Bikram recurring events (based on BS month/day) for every year or with specific start/end year ranges. var bikramRecurringEvents = [ { - event: "Event0BikramRecu", + event: "लोकतन्त्र दिवस", dateType: "brecurring", - date: "04/05", // Shrawan 5 - detail: "Recurring test event for Shrawan.", - category: "Test", - startYear: 2082, - endYear: 2085 + date: "01/11", // Baisakh 11 + detail: "Loktantra Diwas (Democracy Day), celebrated annually on Baisakh 11.", + category: "National Day" }, { - event: "Event1BikramRecu", + event: "गणतन्त्र दिवस", dateType: "brecurring", - date: "04/08", // Shrawan 8 - detail: "Recurring test event for Shrawan.", - category: "Test", - startYear: 2070, - endYear: 2082 + date: "02/15", // Jestha 15 + detail: "Gantantra Diwas (Republic Day), celebrated annually on Jestha 15.", + category: "National Day" }, { - event: "Event2BikramRecu", + event: "राष्ट्रिय धान दिवस", dateType: "brecurring", - date: "05/10", // Bhadrapad 10 - detail: "Recurring test event for Bhadrapad.", - category: "Test", - startYear: 2082, - endYear: 2089 - } + date: "03/15", // Asar 15 + detail: "National Paddy Day, celebrated annually on Asar 15.", + category: "National Day" + }, + { + event: "भानु जयन्ती", + dateType: "brecurring", + date: "03/29", // Asar 29 + detail: "Bhanu Jayanti, birth anniversary of poet Bhanubhakta Acharya.", + category: "Jayanti" + }, + { + event: "संविधान दिवस", + dateType: "brecurring", + date: "06/03", // Ashwin 3 + detail: "Constitution Day, celebrated annually on Ashwin 3.", + category: "National Day" + }, + { + event: "पृथ्वी जयन्ती / राष्ट्रिय एकता दिवस", + dateType: "brecurring", + date: "09/27", // Poush 27 + detail: "Prithvi Jayanti / National Unity Day.", + category: "National Day" + }, + { + event: "शहीद दिवस", + dateType: "brecurring", + date: "10/16", // Magh 16 + detail: "Sahid Diwas (Martyrs' Day).", + category: "National Day" + }, + { + event: "प्रजातन्त्र दिवस", + dateType: "brecurring", + date: "11/07", // Falgun 7 + detail: "Prajatantra Diwas (Democracy Day), marking the end of Rana rule.", + category: "National Day" + }, + { + event: "नयाँ वर्ष", + dateType: "brecurring", + date: "01/01", + detail: "Nepali New Year 2082.", + category: "Festival" + }, + { + event: "बिस्का: जात्रा", + dateType: "brecurring", + date: "01/01", + detail: "Biska Jatra festival in Bhaktapur.", + category: "Jatra" + }, + { + event: "साउने सङ्क्रान्ति", + dateType: "brecurring", + date: "04/01", + detail: "Shrawan Sankranti, first day of the month Shrawan.", + category: "Sankranti" + }, + { + event: "माघे संक्रान्ति", + dateType: "brecurring", + date: "10/01", + detail: "Maghe Sankranti, first day of the month Magh.", + category: "Sankranti" + }, ]; // Bikram fixed events (specific BS year/month/day). var bikramFixedEvents = [ { - event: "Event1BikramFixed", + event: "मातातीर्थ औंसी", + dateType: "bikram", + date: "2082/01/14", + detail: "Mother's Day.", + category: "Festival" + }, + { + event: "अक्षय तृतीया", + dateType: "bikram", + date: "2082/01/17", + detail: "Akshaya Tritiya festival.", + category: "Festival" + }, + { + event: "बुद्ध जयन्ती / उभौली पर्व", + dateType: "bikram", + date: "2082/01/29", + detail: "Buddha's Birthday and Kirat festival Ubhauli.", + category: "Festival" + }, + { + event: "भोटो जात्रा", + dateType: "bikram", + date: "2082/02/18", + detail: "The concluding day of Rato Machindranath Jatra.", + category: "Jatra" + }, + { + event: "गुरु पुर्णिमा", + dateType: "bikram", + date: "2082/03/26", + detail: "Guru Purnima, a day to honor teachers.", + category: "Festival" + }, + { + event: "नाग पञ्चमी", + dateType: "bikram", + date: "2082/04/13", + detail: "Day of worshipping the serpent deities (Nagas).", + category: "Festival" + }, + { + event: "जनै पूर्णिमा / रक्षा बन्धन", + dateType: "bikram", + date: "2082/04/24", + detail: "The sacred thread festival.", + category: "Festival" + }, + { + event: "गाईजात्रा", + dateType: "bikram", + date: "2082/04/25", + detail: "Festival of cows, a carnival of humor and satire.", + category: "Jatra" + }, + { + event: "श्रीकृष्ण जन्माष्टमी", + dateType: "bikram", + date: "2082/04/31", + detail: "Lord Krishna's birthday.", + category: "Jayanti" + }, + { + event: "कुशे औंसी (बुबाको मुख हेर्ने दिन)", + dateType: "bikram", + date: "2082/05/07", + detail: "Kushe Aunsi, Father's Day.", + category: "Festival" + }, + { + event: "हरितालिका तीज", + dateType: "bikram", + date: "2082/05/10", + detail: "A major festival for Hindu women.", + category: "Festival" + }, + { + event: "इन्द्रजात्रा", + dateType: "bikram", + date: "2082/05/21", + detail: "Major street festival in Kathmandu.", + category: "Jatra" + }, + { + event: "घटस्थापना", + dateType: "bikram", + date: "2082/06/06", + detail: "Marks the beginning of the Dashain festival.", + category: "Festival" + }, + { + event: "फूलपाती", + dateType: "bikram", + date: "2082/06/13", + detail: "The 7th day of Dashain.", + category: "Festival" + }, + { + event: "महाअष्टमी / कालरात्रि", + dateType: "bikram", + date: "2082/06/14", + detail: "The 8th day of Dashain, involving sacrifices.", + category: "Festival" + }, + { + event: "महानवमी", + dateType: "bikram", + date: "2082/06/15", + detail: "The 9th day of Dashain.", + category: "Festival" + }, + { + event: "विजया दशमी", + dateType: "bikram", + date: "2082/06/16", + detail: "The 10th day of Dashain, the main day of celebration.", + category: "Festival" + }, + { + event: "कोजाग्रत पूर्णिमा", + dateType: "bikram", + date: "2082/06/20", + detail: "The full moon day that marks the end of Dashain.", + category: "Festival" + }, + { + event: "लक्ष्मी पूजा / कुकुर तिहार", + dateType: "bikram", + date: "2082/07/03", + detail: "Day for worshipping Goddess Laxmi and dogs.", + category: "Festival" + }, + { + event: "गाई पूजा / गोवर्धन पूजा / म्हपूजा", + dateType: "bikram", + date: "2082/07/05", + detail: "Day for worshipping cows, oxen, and oneself (Mha Puja).", + category: "Festival" + }, + { + event: "भाइटीका", + dateType: "bikram", + date: "2082/07/06", + detail: "The final and main day of Tihar, celebrating siblings.", + category: "Festival" + }, + { + event: "छठ पर्व", + dateType: "bikram", + date: "2082/07/10", + detail: "Festival dedicated to the Sun God, mainly in Terai.", + category: "Festival" + }, + { + event: "विवाह पञ्चमी", + dateType: "bikram", + date: "2082/08/09", + detail: "Commemorates the wedding of Lord Ram and Sita.", + category: "Festival" + }, + { + event: "य:मरि पुन्हि / धान्यपुर्णिमा", + dateType: "bikram", + date: "2082/08/18", + detail: "Newari festival of Yamari Punhi / Dhanya Purnima.", + category: "Festival" + }, + { + event: "तमु ल्होसार", + dateType: "bikram", + date: "2082/09/15", + detail: "New Year of the Gurung community.", + category: "Lhosar" + }, + { + event: "सोनाम ल्होसार", + dateType: "bikram", + date: "2082/10/05", + detail: "New Year of the Tamang community.", + category: "Lhosar" + }, + { + event: "सरस्वती पूजा / वसन्तपञ्चमी", + dateType: "bikram", + date: "2082/10/09", + detail: "Saraswati Puja / Vasant Panchami, day of learning.", + category: "Festival" + }, + { + event: "महा शिवरात्री / नेपाली सेना दिवस", + dateType: "bikram", + date: "2082/11/04", + detail: "Festival of Lord Shiva and Nepali Army Day.", + category: "Festival" + }, + { + event: "ग्याल्पो ल्होछार", + dateType: "bikram", + date: "2082/11/06", + detail: "New Year of the Sherpa community.", + category: "Lhosar" + }, + { + event: "फागु पुर्णिमा / होली", + dateType: "bikram", + date: "2082/11/18", + detail: "Holi, the festival of colors.", + category: "Festival" + }, + { + event: "घोडेजात्रा", + dateType: "bikram", + date: "2082/12/04", + detail: "Ghode Jatra, the horse parade festival in Kathmandu.", + category: "Jatra" + }, + { + event: "चैते दशैँ", dateType: "bikram", - date: "2082/04/15", // BS Year 2082, Month 4 (Shrawan), Day 15 - detail: "Fixed test event for Shrawan 2082.", - category: "Test" + date: "2082/12/12", + detail: "Chaite Dashain, a smaller version of the great Dashain.", + category: "Festival" }, { - event: "Event2BikramFixed", + event: "श्री राम नवमी", dateType: "bikram", - date: "2082/05/20", // BS Year 2082, Month 5 (Bhadrapad), Day 20 - detail: "Fixed test event for Bhadrapad 2082.", - category: "Test" + date: "2082/12/13", + detail: "Celebration of Lord Ram's birthday.", + category: "Festival" } ]; diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index fc5b60e..92318ee 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -29,7 +29,7 @@ function clearCache() { calculationCache = {}; } -// Surya Siddhanta Constants +// Surya Siddhanta Constants ( all not used ) var YugaRotation = { 'star': 1582237828, 'sun': 4320000, @@ -46,7 +46,7 @@ var YugaCivilDays = 1577917828; // YugaRotation.star - YugaRotation.sun var KaliEpoch = 588465.5; var PlanetApogee = { 'sun': 77 + 17 / 60 }; var PlanetCircumm = { 'sun': 13 + 50 / 60, 'moon': 31 + 50 / 60 }; - +var rad = 57.2957795; // 180 / pi // Panchanga Names var tithiNamesList = [ @@ -94,7 +94,7 @@ function arcsinDeg(x) { return Math.asin(x) * 180 / Math.PI; } function toDevanagari(num) { if (num <= 0) return ""; var devanagariNumerals = ["०", "१", "२", "३", "४", "५", "६", "७", "८", "९"]; - return String(num).split('').map(function(digit) { + return String(num).split('').map(function (digit) { return devanagariNumerals[parseInt(digit, 10)]; }).join(''); } @@ -114,8 +114,8 @@ function toJulianDay(year, month, day) { var a = Math.floor(y / 100); var b = 2 - a + Math.floor(a / 4); return Math.floor(365.25 * (y + 4716)) + - Math.floor(30.6001 * (m + 1)) + - day + b - 1524.5; + Math.floor(30.6001 * (m + 1)) + + day + b - 1524.5; } function fromJulianDay(jd) { @@ -166,30 +166,68 @@ function getTithi(sunLong, moonLong) { return zero360(moonLong - sunLong) / 12; } -function getSolarDay(ahar) { - var intAhar = Math.floor(ahar); - for (var i = 0; i <= 32; i++) { - var t1 = trueLongitudeSun(intAhar - i); - var t2 = trueLongitudeSun(intAhar - i + 1); - if (Math.floor(t1 / 30) !== Math.floor(t2 / 30)) return i + 1; - } - return 1; +// Determine if today is the first day of a new solar month +function todaySauraMasaFirstP(ahar) { + var tslong_today = getTslong(ahar); + var tslong_tomorrow = getTslong(ahar + 1); + tslong_today -= Math.floor(tslong_today / 30) * 30; + tslong_tomorrow -= Math.floor(tslong_tomorrow / 30) * 30; + return (25 < tslong_today && tslong_tomorrow < 5); } -function getVikramYear(ahar) { - var kaliYear = Math.floor(ahar * YugaRotation.sun / YugaCivilDays); - return kaliYear - 3044; +// Calculate solar longitude +function getTslong(ahar) { + var t1 = (YugaRotation.sun * ahar / YugaCivilDays); + t1 -= Math.floor(t1); + var mslong = 360 * t1; + var x1 = mslong - PlanetApogee.sun; + var y1 = PlanetCircumm.sun / 360; + var y2 = sinDeg(x1); + var y3 = y1 * y2; + var x2 = arcsinDeg(y3); + var x3 = mslong - x2; + return x3; +} + +// Recursively determines solar month and day +function getSauraMasaDay(ahar) { + if (todaySauraMasaFirstP(ahar)) { + var day = 1; + var tslong_tomorrow = getTslong(ahar + 1); + var month = Math.floor(tslong_tomorrow / 30) % 12; + month = (month + 12) % 12; + return { m: month, d: day }; + } else { + var yesterday = getSauraMasaDay(ahar - 1); + return { m: yesterday.m, d: yesterday.d + 1 }; + } } -function getBikramSambatInfo(ahar, sunLong) { - var year = getVikramYear(ahar); - var monthIndex = Math.floor(sunLong / 30) % 12; - var day = getSolarDay(ahar); - return { year: year, monthIndex: monthIndex, day: day, monthName: solarMonths[monthIndex] }; +// Astronomical conversion from Gregorian to Bikram +function fromGregorianAstronomical(gYear, gMonth, gDay) { + var julian = toJulianDay(gYear, gMonth - 1, gDay); + var ahar = julian - KaliEpoch; + + var sauraMasaResult = getSauraMasaDay(ahar); + var saura_masa_num = sauraMasaResult.m; + var saura_masa_day = sauraMasaResult.d; + + var YearKali = Math.floor(ahar * YugaRotation.sun / YugaCivilDays); + var YearSaka = YearKali - 3179; + var nepalimonth = saura_masa_num % 12; + var year = YearSaka + 135 + Math.floor((saura_masa_num - nepalimonth) / 12); + var month = (saura_masa_num + 12) % 12 + 1; + + return { + year: year, + monthIndex: month - 1, + day: saura_masa_day, + monthName: solarMonths[month - 1] + }; } function findNewMoon(ahar) { - var getElongation = function(a) { return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); }; + var getElongation = function (a) { return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); }; var lo = ahar - 2, hi = ahar + 2; var el = getElongation(lo), eh = getElongation(hi); if (el < eh) el += 360; @@ -240,7 +278,7 @@ function getSunriseSunset(date, lat, lon, tz) { var rise = noon - H / 15; var set = noon + H / 15; - var formatTime = function(h) { + var formatTime = function (h) { if (!isFinite(h)) return "N/A"; var hr = Math.floor(h); var min = Math.round((h - hr) * 60); @@ -250,51 +288,49 @@ function getSunriseSunset(date, lat, lon, tz) { return { sunrise: formatTime(rise), sunset: formatTime(set) }; } -// Data-Driven Conversion and Info Functions +// Data-Driven Conversion with fallback to astronomical calculations function fromBikramSambat(bsYear, monthIndex, day) { - // Use data if within range, otherwise fallback to astronomical calculation if (bsYear >= Bsdata.BS_START_YEAR && bsYear <= Bsdata.BS_END_YEAR) { var daysOffset = 0; - // Add days for full years between start year and target year for (var y = Bsdata.BS_START_YEAR; y < bsYear; y++) { var yearData = Bsdata.NP_MONTHS_DATA[y - Bsdata.BS_START_YEAR]; var totalDaysInYear = 0; - for(var m = 0; m < 12; m++) { + for (var m = 0; m < 12; m++) { totalDaysInYear += yearData[m]; } daysOffset += totalDaysInYear; } - // Add days for months in the target year var targetYearData = Bsdata.NP_MONTHS_DATA[bsYear - Bsdata.BS_START_YEAR]; for (let m = 0; m < monthIndex; m++) { daysOffset += targetYearData[m]; } - // Add the day of the month daysOffset += (day - 1); var resultDate = new Date(Bsdata.BS_START_DATE_AD.getTime()); resultDate.setUTCDate(resultDate.getUTCDate() + daysOffset); return resultDate; } else { - // Fallback for out-of-range years - var sakaYear = bsYear - 135; - var kaliYear = sakaYear + 3179; - var approxAhar = (kaliYear * YugaCivilDays / YugaRotation.sun); - approxAhar += monthIndex * 30.5; // Start with an approximation - - for (var i = 0; i < 5; i++) { // Iterate to find the start of the solar month - var sunLong = trueLongitudeSun(approxAhar); - var targetLong = monthIndex * 30; - var diff = zero360(targetLong - sunLong); - if (diff > 180) diff -= 360; - if (Math.abs(diff) < 0.01) break; - approxAhar += diff / 0.9856; // Adjust ahar based on Sun's mean motion + // Fallback for out-of-range years - USE TS IMPLEMENTATION + var YearSaka = bsYear - 135; + var YearKali = YearSaka + 3179; + var ahar = Math.floor((YearKali * YugaCivilDays) / YugaRotation.sun); + + // Find the exact date + var currentDay = getSauraMasaDay(ahar); + + // Adjust to find the exact date + while (currentDay.m !== monthIndex || currentDay.d !== day) { + if (currentDay.m < monthIndex || (currentDay.m === monthIndex && currentDay.d < day)) { + ahar += 1; + } else { + ahar -= 1; + } + currentDay = getSauraMasaDay(ahar); } - var targetAhar = approxAhar + (day - 1); - var jd = targetAhar + KaliEpoch; - return fromJulianDay(jd); + var julian_date = ahar + KaliEpoch; + return fromJulianDay(julian_date); } } @@ -325,8 +361,78 @@ function getBikramMonthInfo(bsYear, monthIndex) { } } +function toBikramSambat(gregorianDate, lon = 85.32, tz = 5.75) { + // Ensure we are comparing UTC dates to avoid timezone-related off-by-one errors + const targetUtcDate = new Date(Date.UTC( + gregorianDate.getUTCFullYear(), + gregorianDate.getUTCMonth(), + gregorianDate.getUTCDate() + )); + + const startDate = new Date(Date.UTC( + Bsdata.BS_START_DATE_AD.getUTCFullYear(), + Bsdata.BS_START_DATE_AD.getUTCMonth(), + Bsdata.BS_START_DATE_AD.getUTCDate() + )); + + // Attempt to use the fast, data-driven conversion first + if (targetUtcDate >= startDate) { + let daysOffset = Math.floor((targetUtcDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)); + + for (let y = 0; y < Bsdata.NP_MONTHS_DATA.length; y++) { + const currentBsYear = Bsdata.BS_START_YEAR + y; + const yearData = Bsdata.NP_MONTHS_DATA[y]; + + let daysInYear = 0; + for (var m = 0; m < 12; m++) { + daysInYear += yearData[m]; + } + + if (daysOffset < daysInYear) { + for (let m = 0; m < 12; m++) { + const daysInMonth = yearData[m]; + if (daysOffset < daysInMonth) { + return { + year: currentBsYear, + monthIndex: m, + day: daysOffset + 1, + monthName: solarMonths[m] + }; + } + daysOffset -= daysInMonth; + } + // Should not reach here - if we do, it's an error + break; + } else { + daysOffset -= daysInYear; + } + } + } + + // Fallback to astronomical calculation if the date is outside the pre-calculated range + var jd = toJulianDay( + gregorianDate.getUTCFullYear(), + gregorianDate.getUTCMonth(), + gregorianDate.getUTCDate() + ); + + return fromGregorianAstronomical( + gregorianDate.getUTCFullYear(), + gregorianDate.getUTCMonth() + 1, + gregorianDate.getUTCDate() + ); +} + function getTodayBsInfo() { var now = new Date(); + + // Attempt to use the fast, data-driven conversion first + var bsInfo = toBikramSambat(now); + if (bsInfo) { + return bsInfo; + } + + // Fallback to astronomical calculation if the date is outside the pre-calculated range var jd = toJulianDay(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()); var ahar = jd - KaliEpoch + 0.25 + ((85.3 / 15 - 5.75) / 24); var sunLong = trueLongitudeSun(ahar); @@ -335,70 +441,70 @@ function getTodayBsInfo() { // Shared Name Resolution Utility function resolveTithiName(tithiDay, paksha) { - if (paksha === "कृष्ण पक्ष" && tithiDay === 15) return tithiNamesList[15]; // Amavasya - if (paksha === "शुक्ल पक्ष" && tithiDay === 15) return tithiNamesList[14]; // Purnima + if (paksha === "कृष्ण पक्ष" && tithiDay === 15) return tithiNamesList[15]; + if (paksha === "शुक्ल पक्ष" && tithiDay === 15) return tithiNamesList[14]; return tithiNamesList[tithiDay - 1]; } // Event Calculation Function function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { -    const events = []; -    const gregorianMonth = date.getUTCMonth() + 1; // 1-indexed month -    const gregorianDay = date.getUTCDate(); -    const gregorianYear = date.getUTCFullYear(); - -    const formattedGregorianDate = formatMonthDay(gregorianMonth, gregorianDay); -    const formattedBikramRecurringDate = formatMonthDay(bsMonthIndex + 1, bsDay); // bsMonthIndex is 0-indexed - -    // Check Gregorian events -    for (var i = 0; i < EventsData.gregorianEvents.length; i++) { -        var event = EventsData.gregorianEvents[i]; -        if (event.dateType === "gregorian" && event.date === formattedGregorianDate) { -            var isValidYear = (!event.startYear || gregorianYear >= event.startYear) && -                              (!event.endYear || gregorianYear <= event.endYear); -            if (isValidYear) { -                events.push({ -                    name: event.event, -                    detail: event.detail, -                    category: event.category -                }); -            } -        } -    } - -    // Check Bikram recurring events -    for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { -        let event = EventsData.bikramRecurringEvents[j]; -        if (event.dateType === "brecurring" && event.date === formattedBikramRecurringDate) { -            const isValidYear = (!event.startYear || bsYear >= event.startYear) && -                              (!event.endYear || bsYear <= event.endYear); -            if (isValidYear) { -                events.push({ -                    name: event.event, -                    detail: event.detail, -                    category: event.category -                }); -            } -        } -    } - -    // Check Bikram fixed events -    for (var k = 0; k < EventsData.bikramFixedEvents.length; k++) { -        let event = EventsData.bikramFixedEvents[k]; -        if (event.dateType === "bikram") { -            const eventDateParts = event.date.split('/').map(Number); -            if (eventDateParts[0] === bsYear && -                eventDateParts[1] === (bsMonthIndex + 1) && // Convert back to 1-indexed for comparison -                eventDateParts[2] === bsDay) { -                events.push({ -                    name: event.event, -                    detail: event.detail, -                    category: event.category -                }); -            } -        } -    } -    return events; + const events = []; + const gregorianMonth = date.getUTCMonth() + 1; // 1-indexed month + const gregorianDay = date.getUTCDate(); + const gregorianYear = date.getUTCFullYear(); + + const formattedGregorianDate = formatMonthDay(gregorianMonth, gregorianDay); + const formattedBikramRecurringDate = formatMonthDay(bsMonthIndex + 1, bsDay); + + // Check Gregorian events + for (var i = 0; i < EventsData.gregorianEvents.length; i++) { + var event = EventsData.gregorianEvents[i]; + if (event.dateType === "gregorian" && event.date === formattedGregorianDate) { + var isValidYear = (!event.startYear || gregorianYear >= event.startYear) && + (!event.endYear || gregorianYear <= event.endYear); + if (isValidYear) { + events.push({ + name: event.event, + detail: event.detail, + category: event.category + }); + } + } + } + + // Check Bikram recurring events + for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { + let event = EventsData.bikramRecurringEvents[j]; + if (event.dateType === "brecurring" && event.date === formattedBikramRecurringDate) { + const isValidYear = (!event.startYear || bsYear >= event.startYear) && + (!event.endYear || bsYear <= event.endYear); + if (isValidYear) { + events.push({ + name: event.event, + detail: event.detail, + category: event.category + }); + } + } + } + + // Check Bikram fixed events + for (var k = 0; k < EventsData.bikramFixedEvents.length; k++) { + let event = EventsData.bikramFixedEvents[k]; + if (event.dateType === "bikram") { + const eventDateParts = event.date.split('/').map(Number); + if (eventDateParts[0] === bsYear && + eventDateParts[1] === (bsMonthIndex + 1) && + eventDateParts[2] === bsDay) { + events.push({ + name: event.event, + detail: event.detail, + category: event.category + }); + } + } + } + return events; } // Main Calculation Function @@ -406,7 +512,12 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { var cacheKey = "panchanga_" + date.getTime(); if (calculationCache[cacheKey]) return calculationCache[cacheKey]; - var jd = toJulianDay(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); + var jd = toJulianDay( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate() + ); + var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); var sunLong = trueLongitudeSun(ahar); @@ -422,13 +533,12 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) : karanas[0]; - var bsInfo = getBikramSambatInfo(ahar, sunLong); - var sunriseSunset = getSunriseSunset(date, lat, lon, tz); + // Always use data-driven conversion for Bikram Sambat date + var bsInfo = toBikramSambat(date, lon, tz); - // Determine if the calculation is a fallback + var sunriseSunset = getSunriseSunset(date, lat, lon, tz); var isComputed = (bsInfo.year < Bsdata.BS_START_YEAR || bsInfo.year > Bsdata.BS_END_YEAR); - // Get events for the current date var events = getEventsForDate(date, bsInfo.year, bsInfo.monthIndex, bsInfo.day); var result = { @@ -438,7 +548,7 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { bsMonthIndex: bsInfo.monthIndex, bsDay: bsInfo.day, monthName: bsInfo.monthName, - weekday: weekdays[date.getDay()], + weekday: weekdays[date.getUTCDay()], sunrise: sunriseSunset.sunrise, sunset: sunriseSunset.sunset, tithi: tithiName, @@ -456,12 +566,17 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { return result; } -// Debug calculations. +// Debug calculations function generateDebugInfo(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { var cacheKey = "debug_" + date.getTime(); - if (calculationCache[cacheKey]) return calculationCache[cacheKey]; + if (calculationCache[cacheKey]) return calculationCache[cacheKey]; + var bsInfoData = toBikramSambat(date, lon, tz); - var jd = toJulianDay(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); + var jd = toJulianDay( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate() + ); var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); var sunLong = trueLongitudeSun(ahar); @@ -477,31 +592,65 @@ function generateDebugInfo(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) : karanas[0]; - var bsInfo = getBikramSambatInfo(ahar, sunLong); + var bsInfoCalc = fromGregorianAstronomical( + date.getUTCFullYear(), + date.getUTCMonth() + 1, + date.getUTCDate() + ); + + var dayDifference = 0; + var gregFromAstronomical = fromBikramSambat( + bsInfoCalc.year, + bsInfoCalc.monthIndex, + bsInfoCalc.day + ); + + // Calculate difference in milliseconds + var timeDiff = date.getTime() - gregFromAstronomical.getTime(); + dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); var sunriseSunset = getSunriseSunset(date, lat, lon, tz); - var isComputed = (bsInfo.year < Bsdata.BS_START_YEAR || bsInfo.year > Bsdata.BS_END_YEAR); + var isComputed = (bsInfoData.year < Bsdata.BS_START_YEAR || bsInfoData.year > Bsdata.BS_END_YEAR); + + var dataDrivenInfo = ""; + if (bsInfoData && !isComputed) { + dataDrivenInfo = `Debug Information (Data-Driven for date conversion): +Data-Driven BS Date: ${toDevanagari(bsInfoData.year)} ${bsInfoData.monthName} ${toDevanagari(bsInfoData.day)} +(panchanga is based in computation) +`; + } else { + dataDrivenInfo = `Debug Information (Astronomical Calculation - outside data range): +Data-Driven BS Date: Not available (using astronomical calculation) +`; + } var debugOutput = ` - Debug Information (Surya Siddhanta): - gregorianDate: ${Qt.formatDateTime(date, "dddd, MMMM d, yyyy")} - bikramSambat: ${toDevanagari(bsInfo.year)} ${bsInfo.monthName} ${toDevanagari(bsInfo.day)} - bsMonthIndex: ${bsInfo.monthIndex} - weekday(local): ${weekdays[date.getDay()]} - sunrise: ${sunriseSunset.sunrise} - sunset: ${sunriseSunset.sunset} - tithi: ${tithiName} | index: ${tithiDay} - tithiAngle: ${(tithiVal * 12).toFixed(4)}° - paksha: ${paksha} - nakshatra: ${nakshatras[Math.floor(moonLong * 27 / 360) % 27]} | index: ${Math.floor(moonLong * 27 / 360) % 27 + 1} - yoga: ${yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27]} | index: ${Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1} - yogaAngle: ${zero360(sunLong + moonLong).toFixed(4)}° - karana: ${karanaName} | index: ${karanaIdx} - karanaAngle: ${(2 * tithiVal).toFixed(4)} - sunRashi: ${rashis[Math.floor(sunLong / 30) % 12]} | index: ${Math.floor(sunLong / 30) % 12 + 1} - moonRashi: ${rashis[Math.floor(moonLong / 30) % 12]} | index: ${Math.floor(moonLong / 30) % 12 + 1} - adhikaMasa: ${calculateAdhikaMasa(ahar)} - isComputed: ${isComputed} +${dataDrivenInfo}Consistency Check: +Data-Driven BS Date: ${bsInfoData ? `${toDevanagari(bsInfoData.year)} ${bsInfoData.monthName} ${toDevanagari(bsInfoData.day)}` : 'N/A'} +Astronomical BS Date (Corrected): ${toDevanagari(bsInfoCalc.year)} ${bsInfoCalc.monthName} ${toDevanagari(bsInfoCalc.day)} +Day Difference: ${dayDifference} ${Math.abs(dayDifference) === 1 ? 'day' : 'days'} +(Note: Positive = Astronomical date is behind; Negative = Astronomical date is ahead) + +Detailed Astronomical Calculation: +gregorianDate: ${Qt.formatDateTime(date, "dddd, MMMM d, yyyy")} +bsMonthIndex(0 based index): ${bsInfoCalc.monthIndex} +weekday(UTC): ${weekdays[date.getUTCDay()]} +sunrise: ${sunriseSunset.sunrise} +sunset: ${sunriseSunset.sunset} +tithi: ${tithiName} | index: ${tithiDay} +tithiAngle: ${(tithiVal * 12).toFixed(4)}° +paksha: ${paksha} +nakshatra: ${nakshatras[Math.floor(moonLong * 27 / 360) % 27]} | index: ${Math.floor(moonLong * 27 / 360) % 27 + 1} +yoga: ${yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27]} | index: ${Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1} +yogaAngle: ${zero360(sunLong + moonLong).toFixed(4)}° +karana: ${karanaName} | index: ${karanaIdx} +karanaAngle: ${(2 * tithiVal).toFixed(4)} +sunRashi: ${rashis[Math.floor(sunLong / 30) % 12]} | index: ${Math.floor(sunLong / 30) % 12 + 1} +moonRashi: ${rashis[Math.floor(moonLong / 30) % 12]} | index: ${Math.floor(moonLong / 30) % 12 + 1} +adhikaMasa: ${calculateAdhikaMasa(ahar)} +isComputed: ${isComputed} `.trim(); - return { debug: debugOutput }; + var result = { debug: debugOutput.replace(/^\s*[\r\n]/gm, "") }; + calculationCache[cacheKey] = result; + return result; } From f2f738b480e77bd6f710175b0f51165e6d63d38f Mon Sep 17 00:00:00 2001 From: khumnath Date: Thu, 14 Aug 2025 10:19:09 +0545 Subject: [PATCH 3/8] adhik mas calculation improved. testing lunar month. # added lunar month in debug. # lunar month is considered to starts from new moon. # lunar adhik and kshaya month calculation improved # resized day day detail modal hight to full if content is more like while opening debug information. --- qml/PanchangaDetailDialog.qml | 54 ++++++----- resources/PanchangaCalculator.js | 158 ++++++++++++++++++++++++++----- 2 files changed, 165 insertions(+), 47 deletions(-) diff --git a/qml/PanchangaDetailDialog.qml b/qml/PanchangaDetailDialog.qml index 3e9baff..1b03247 100644 --- a/qml/PanchangaDetailDialog.qml +++ b/qml/PanchangaDetailDialog.qml @@ -8,7 +8,7 @@ import "qrc:/qml/" Dialog { id: panchangaDetailDialogRoot width: Math.min(parent.width * 0.9, 600) - height: Math.min(contentItem.implicitHeight, parent.height * 0.8) + height: Math.min(contentItem.implicitHeight, parent.height) modal: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside x: (parent.width - width) / 2 @@ -88,7 +88,7 @@ Dialog { } } - // Layout for the Panchanga details। + // Layout for the Panchanga details. ColumnLayout { id: panchangaDetails visible: !panchangaDetailDialogRoot.debugVisible @@ -113,20 +113,26 @@ Dialog { Flickable { anchors.fill: parent - contentWidth: debugInfoText.paintedWidth + contentWidth: Math.min(parent.width * 0.96, 600) contentHeight: debugInfoText.paintedHeight clip: true - TextEdit { - id: debugInfoText - text: currentDebugInfo - color: "white" - font.family: "monospace" - font.pointSize: 9 - readOnly: true - wrapMode: TextEdit.NoWrap - selectByMouse: true - padding: 10 + ScrollView { + anchors.fill: parent + clip: true + + TextEdit { + id: debugInfoText + text: currentDebugInfo + color: "white" + font.family: "monospace" + font.pointSize: 9 + readOnly: true + wrapMode: TextEdit.NoWrap + textFormat: TextEdit.RichText + selectByMouse: true + padding: 10 + } } } } @@ -207,17 +213,17 @@ Dialog { } var details = [ - createDetailRow("बिक्रम संवत", toDevanagari(panchangaData.bsYear) + " " + panchangaData.monthName + " " + toDevanagari(panchangaData.bsDay)), - createDetailRow("वार", panchangaData.weekday), - createDetailRow("तिथि", panchangaData.tithi + " (" + panchangaData.paksha + ")"), - createDetailRow("नक्षत्र", panchangaData.nakshatra), - createDetailRow("योग", panchangaData.yoga), - createDetailRow("करण", panchangaData.karana), - createDetailRow("सूर्य राशि", panchangaData.sunRashi), - createDetailRow("चन्द्र राशि", panchangaData.moonRashi), - createDetailRow("उदयास्त", "सूर्योदय " + panchangaData.sunrise + " | सूर्यास्त " + panchangaData.sunset), - createDetailRow("अधिक/क्षय मास", panchangaData.adhikaMasa) - ]; + createDetailRow("बिक्रम संवत", toDevanagari(panchangaData.bsYear) + " " + panchangaData.monthName + " " + toDevanagari(panchangaData.bsDay)), + createDetailRow("वार", panchangaData.weekday), + createDetailRow("तिथि", panchangaData.tithi + " (" + panchangaData.paksha + ")"), + createDetailRow("नक्षत्र", panchangaData.nakshatra), + createDetailRow("योग", panchangaData.yoga), + createDetailRow("करण", panchangaData.karana), + createDetailRow("सूर्य राशि", panchangaData.sunRashi), + createDetailRow("चन्द्र राशि", panchangaData.moonRashi), + createDetailRow("उदयास्त", "सूर्योदय " + panchangaData.sunrise + " | सूर्यास्त " + panchangaData.sunset), + createDetailRow("अधिक/क्षय मास", panchangaData.adhikaMasa) + ]; for (var i = 0; i < details.length; ++i) { details[i].parent = panchangaDetails; } diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index 92318ee..7fdff95 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -226,39 +226,134 @@ function fromGregorianAstronomical(gYear, gMonth, gDay) { }; } + + function findNewMoon(ahar) { - var getElongation = function (a) { return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); }; - var lo = ahar - 2, hi = ahar + 2; - var el = getElongation(lo), eh = getElongation(hi); - if (el < eh) el += 360; - for (var i = 0; i < 30; i++) { + var getElongation = function(a) { + return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); + }; + + var guess = ahar; + var step = 0.5; + + for (var i = 0; i < 10; i++) { + var elong = getElongation(guess); + + if (elong < 5 || elong > 355) { + break; + } + + if (elong < 180) { + guess -= (elong / 360) * 29.53; + } else { + guess += ((360 - elong) / 360) * 29.53; + } + } + + var lo = guess - 1; + var hi = guess + 1; + + for (let i = 0; i < 50; i++) { var mid = (lo + hi) / 2; var em = getElongation(mid); - if (el < em) em -= 360; - if (em > 0) { lo = mid; el = em; } - else { hi = mid; eh = em; } + + if (em < 180) { + hi = mid; + } else { + lo = mid; + } } + return (lo + hi) / 2; } function calculateAdhikaMasa(ahar) { - const tithi = getTithi(trueLongitudeSun(ahar), trueLongitudeMoon(ahar)); - const daysPerTithi = 29.530588 / 30; // ~0.9843 days - const nextNewMoon = findNewMoon(ahar + (30 - tithi) * daysPerTithi); - const prevNewMoon = findNewMoon(nextNewMoon - 29.6); + var lunarMonthStart = findNewMoon(ahar); + if (lunarMonthStart > ahar) { + lunarMonthStart = findNewMoon(lunarMonthStart - 29.530588853); + } + + var lunarMonthEnd = findNewMoon(lunarMonthStart + 29.530588853); + var sunLongStart = trueLongitudeSun(lunarMonthStart); + var sunLongEnd = trueLongitudeSun(lunarMonthEnd); + + var startSign = Math.floor(sunLongStart / 30); + var endSign = Math.floor(sunLongEnd / 30); + + var signCrossings = 0; + var currentSign = startSign; + + for (var i = 1; i <= 29; i++) { + var checkAhar = lunarMonthStart + i; + var checkSunLong = trueLongitudeSun(checkAhar); + var checkSign = Math.floor(checkSunLong / 30); + + if (checkSign < currentSign) { + checkSign += 12; + } + + if (checkSign > currentSign) { + signCrossings += (checkSign - currentSign); + currentSign = checkSign % 12; + } + } + + if (endSign < currentSign) { + endSign += 12; + } + if (endSign > currentSign) { + signCrossings += (endSign - currentSign); + } + + var result = "छैन"; + + if (signCrossings === 0) { + result = "अधिक " + solarMonths[startSign] + } + + if (signCrossings >= 2) { + var skippedSign = (startSign + 1) % 12; + result = "क्षय " + solarMonths[skippedSign] + } - const signAtPrev = Math.floor(trueLongitudeSun(prevNewMoon) / 30); - const signAtNext = Math.floor(trueLongitudeSun(nextNewMoon) / 30); + return result; +} - if (signAtPrev === signAtNext) { - return "अधिक " + solarMonths[signAtNext]; +function getLunarMonthNameWithAdhik(ahar) { + var lunarMonthStart = findNewMoon(ahar); + if (lunarMonthStart > ahar) { + lunarMonthStart = findNewMoon(lunarMonthStart - 29.53); } - if ((signAtNext - signAtPrev + 12) % 12 === 2) { - return "क्षय मास"; + var purnima = findNewMoon(lunarMonthStart + 14.77); // ~14.77 days after new moon + + var sunLongPurnima = trueLongitudeSun(purnima); + var purnimaSign = Math.floor(sunLongPurnima / 30); + + var signCrossings = 0; + var currentSign = Math.floor(trueLongitudeSun(lunarMonthStart) / 30); + + for (var i = 1; i <= 29; i++) { + var checkAhar = lunarMonthStart + i; + var checkSunLong = trueLongitudeSun(checkAhar); + var checkSign = Math.floor(checkSunLong / 30); + + if (checkSign < currentSign) { + checkSign += 12; + } + + if (checkSign > currentSign) { + signCrossings += (checkSign - currentSign); + currentSign = checkSign % 12; + } } - return "छैन"; + var isAdhik = (signCrossings === 0); + var result = { + monthName: solarMonths[purnimaSign], + isAdhik: isAdhik + }; + return result; } function getSunriseSunset(date, lat, lon, tz) { @@ -608,6 +703,12 @@ function generateDebugInfo(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { // Calculate difference in milliseconds var timeDiff = date.getTime() - gregFromAstronomical.getTime(); dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); + var dayDifferenceDisplay = dayDifference; + if (Math.abs(dayDifference) > 2) { // Show in red if difference is more than 2 days + dayDifferenceDisplay = `${dayDifference}`; + } else if (Math.abs(dayDifference) > 0) { + dayDifferenceDisplay = `${dayDifference}`; + } var sunriseSunset = getSunriseSunset(date, lat, lon, tz); var isComputed = (bsInfoData.year < Bsdata.BS_START_YEAR || bsInfoData.year > Bsdata.BS_END_YEAR); @@ -623,13 +724,23 @@ Data-Driven BS Date: Not available (using astronomical calculation) `; } + var lunarMonthInfo = getLunarMonthNameWithAdhik(ahar); + var lunarMonthDisplay; + if (lunarMonthInfo.isAdhik) { + lunarMonthDisplay = "अधिक " + lunarMonthInfo.monthName + " " + paksha; + } else { + lunarMonthDisplay = lunarMonthInfo.monthName + " " + paksha; + } + var debugOutput = ` +
 ${dataDrivenInfo}Consistency Check:
 Data-Driven BS Date: ${bsInfoData ? `${toDevanagari(bsInfoData.year)} ${bsInfoData.monthName} ${toDevanagari(bsInfoData.day)}` : 'N/A'}
 Astronomical BS Date (Corrected): ${toDevanagari(bsInfoCalc.year)} ${bsInfoCalc.monthName} ${toDevanagari(bsInfoCalc.day)}
-Day Difference: ${dayDifference} ${Math.abs(dayDifference) === 1 ? 'day' : 'days'}
-(Note: Positive = Astronomical date is behind; Negative = Astronomical date is ahead)
-
+Day Difference: ${dayDifferenceDisplay} ${Math.abs(dayDifference) === 1 ? 'day' : 'days'}
+lunar Month(testing): ${lunarMonthDisplay}
+Note: Positive = Astronomical date is behind;
+Negative = Astronomical date is ahead)
 Detailed Astronomical Calculation:
 gregorianDate: ${Qt.formatDateTime(date, "dddd, MMMM d, yyyy")}
 bsMonthIndex(0 based index): ${bsInfoCalc.monthIndex}
@@ -646,8 +757,9 @@ karana: ${karanaName} | index: ${karanaIdx}
 karanaAngle: ${(2 * tithiVal).toFixed(4)}
 sunRashi: ${rashis[Math.floor(sunLong / 30) % 12]} | index: ${Math.floor(sunLong / 30) % 12 + 1}
 moonRashi: ${rashis[Math.floor(moonLong / 30) % 12]} | index: ${Math.floor(moonLong / 30) % 12 + 1}
-adhikaMasa: ${calculateAdhikaMasa(ahar)}
+adhikaMasa: ${calculateAdhikaMasa(ahar)}(approximation)
 isComputed: ${isComputed}
+    
`.trim(); var result = { debug: debugOutput.replace(/^\s*[\r\n]/gm, "") }; From 2de95a876dc2692bc20f30421f240901e96a1bbc Mon Sep 17 00:00:00 2001 From: khumnath Date: Thu, 14 Aug 2025 15:24:03 +0545 Subject: [PATCH 4/8] moved fixed events to lunar based events. need more test for lunar based events. if accuracy is identical for available festival data or concisely tithi data then lunar based events works, no need to add fixed events every year. still need to refine events for adhik and kshaya lunar months. --- qml/CalendarGrid.qml | 2 +- qml/EventDisplay.qml | 31 +- qml/PanchangaDetailDialog.qml | 4 +- resources/EventData.js | 624 ++++++++++++---------- resources/PanchangaCalculator.js | 851 ++++++++++++++----------------- 5 files changed, 742 insertions(+), 770 deletions(-) diff --git a/qml/CalendarGrid.qml b/qml/CalendarGrid.qml index 4706b6c..87130a3 100644 --- a/qml/CalendarGrid.qml +++ b/qml/CalendarGrid.qml @@ -106,7 +106,7 @@ ColumnLayout { return str; } - font.pixelSize: 14 + font.pixelSize: 12 color: theme ? theme.secondaryText : "black" wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter diff --git a/qml/EventDisplay.qml b/qml/EventDisplay.qml index c5c8cb7..2ede6fa 100644 --- a/qml/EventDisplay.qml +++ b/qml/EventDisplay.qml @@ -14,16 +14,7 @@ ColumnLayout { // Components - // Title for the events section. Only visible if there are events. - Label { - text: "कार्यक्रम हरु" - font.pixelSize: 18 - font.bold: true - color: theme ? theme.accentText : "darkblue" - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: 5 - visible: events.length > 0 - } + //Label to display all events, joined by commas. Label { @@ -35,29 +26,11 @@ ColumnLayout { } return ""; } - font.pixelSize: 16 + font.pixelSize: 12 color: theme ? theme.primaryText : "black" wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true visible: events.length > 0 } - - // Message to display if no events are found for the selected day. - Label { - text: "कुनै कार्यक्रम भेटिएन" - font.pixelSize: 16 - font.italic: true - color: theme ? theme.secondaryText : "grey" - horizontalAlignment: Text.AlignHCenter - Layout.fillWidth: true - visible: events.length === 0 - } - - // Bottom margin to the event section. - Rectangle { - height: 20 - color: "transparent" - Layout.fillWidth: true - } } diff --git a/qml/PanchangaDetailDialog.qml b/qml/PanchangaDetailDialog.qml index 1b03247..1a524a6 100644 --- a/qml/PanchangaDetailDialog.qml +++ b/qml/PanchangaDetailDialog.qml @@ -114,7 +114,7 @@ Dialog { Flickable { anchors.fill: parent contentWidth: Math.min(parent.width * 0.96, 600) - contentHeight: debugInfoText.paintedHeight + contentHeight: parent.height clip: true ScrollView { @@ -126,7 +126,7 @@ Dialog { text: currentDebugInfo color: "white" font.family: "monospace" - font.pointSize: 9 + font.pointSize: 8 readOnly: true wrapMode: TextEdit.NoWrap textFormat: TextEdit.RichText diff --git a/resources/EventData.js b/resources/EventData.js index 2a7f809..13e17da 100644 --- a/resources/EventData.js +++ b/resources/EventData.js @@ -1,405 +1,513 @@ // EventsData.js +// This file contains event data for the Panchanga Calculator. -// Gregorian events for every year or with specific start/end year ranges. +.pragma library + +// Lunar based events, defined by month, fortnight (paksha), and lunar day (tithi). +var lunarEvents = [ + { + eventType: "lunar", + lunarMonth: "चैत्र", + paksha: "शुक्ल पक्ष", + tithi: "अष्टमी", + event: "चैते दशैँ", + detail: "चैत्र महिनामा मनाइने दशैँ, ठूलो दशैँको सानो रूप।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "चैत्र", + paksha: "शुक्ल पक्ष", + tithi: "नवमी", + event: "रामनवमी", + detail: "भगवान रामको जन्मदिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "चैत्र", + paksha: "कृष्ण पक्ष", + tithi: "अमावस्या", + event: "मातातीर्थ औंसी", + detail: "आमाको मुख हेर्ने दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "चैत्र", + paksha: "कृष्ण पक्ष", + tithi: "अमावस्या", + event: "घोडेजात्रा", + detail: "काठमाडौँमा मनाइने घोडे जात्रा उत्सव।", + category: "Jatra" + }, + { + eventType: "lunar", + lunarMonth: "वैशाख", + paksha: "शुक्ल पक्ष", + tithi: "तृतीया", + event: "अक्षय तृतीया", + detail: "जौ सातु खाने दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "वैशाख", + paksha: "शुक्ल पक्ष", + tithi: "पूर्णिमा", + event: "बुद्ध जयन्ती / उभौली पर्व", + detail: "भगवान बुद्धको जन्मदिन र किरात समुदायको उभौली पर्व।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "आषाढ", + paksha: "शुक्ल पक्ष", + tithi: "पूर्णिमा", + event: "गुरु पूर्णिमा", + detail: "गुरु र शिक्षकहरूलाई सम्मान गर्ने दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "श्रावण", + paksha: "शुक्ल पक्ष", + tithi: "पञ्चमी", + event: "नाग पञ्चमी", + detail: "सर्प देवताको पूजा गर्ने दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "श्रावण", + paksha: "शुक्ल पक्ष", + tithi: "पूर्णिमा", + event: "जनै पूर्णिमा / रक्षा बन्धन", + detail: "जनै बदल्ने तथा रक्षा बन्धन बांध्ने पवित्र उत्सव।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "श्रावण", + paksha: "कृष्ण पक्ष", + tithi: "अष्टमी", + event: "कृष्ण जन्माष्टमी", + detail: "भगवान कृष्णको जन्मदिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "भाद्रपद", + paksha: "कृष्ण पक्ष", + tithi: "प्रतिपदा", + event: "गाईजात्रा", + detail: "गाईको उत्सव, हास्य र व्यङ्ग्यको मेल।", + category: "Jatra" + }, + { + eventType: "lunar", + lunarMonth: "भाद्रपद", + paksha: "कृष्ण पक्ष", + tithi: "अमावस्या", + event: "कुशे औंसी", + detail: "बुवाको मुख हेर्ने दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "भाद्रपद", + paksha: "शुक्ल पक्ष", + tithi: "तृतीया", + event: "हरितालिका तीज", + detail: "महिलाहरूले को महान उत्सव।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "भाद्रपद", + paksha: "शुक्ल पक्ष", + tithi: "चतुर्थी", + event: "गणेश चतुर्थी", + detail: "भगवान गणेशको जन्मदिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "भाद्रपद", + paksha: "शुक्ल पक्ष", + tithi: "चतुर्दशी", + event: "इन्द्रजात्रा", + detail: "काठमाडौँको प्रमुख सडक उत्सवको मुख्य दिन।", + category: "Jatra" + }, + { + eventType: "lunar", + lunarMonth: "आश्विन", + paksha: "शुक्ल पक्ष", + tithi: "प्रतिपदा", + event: "घटस्थापना", + detail: "दशैँको सुरुवात, नवरात्रिको पहिलो दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "आश्विन", + paksha: "शुक्ल पक्ष", + tithi: "सप्तमी", + event: "फूलपाती", + detail: "दशैँको सातौँ दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "आश्विन", + paksha: "शुक्ल पक्ष", + tithi: "अष्टमी", + event: "महाअष्टमी", + detail: "दशैँको आठौँ दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "आश्विन", + paksha: "शुक्ल पक्ष", + tithi: "नवमी", + event: "महानवमी", + detail: "दशैँको नवौं दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "आश्विन", + paksha: "शुक्ल पक्ष", + tithi: "दशमी", + event: "विजयादशमी (दशैं)", + detail: "दशैँको दशौँ दिन, विजयको दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "आश्विन", + paksha: "शुक्ल पक्ष", + tithi: "पूर्णिमा", + event: "कोजाग्रत पूर्णिमा", + detail: "दशैँको अन्त्य।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "कृष्ण पक्ष", + tithi: "त्रयोदशी", + event: "काग तिहार", + detail: "तिहारको पहिलो दिन, कागलाई समर्पित।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "कृष्ण पक्ष", + tithi: "चतुर्दशी", + event: "कुकुर तिहार", + detail: "तिहारको दोस्रो दिन, कुकुरलाई समर्पित।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "कृष्ण पक्ष", + tithi: "अमावस्या", + event: "लक्ष्मी पूजा", + detail: "तिहारको तेस्रो दिन, देवी लक्ष्मीको पूजा।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "शुक्ल पक्ष", + tithi: "प्रतिपदा", + event: "गोवर्धन पूजा / म्ह पूजा", + detail: "तिहारको चौथो दिन, आत्म-पूजाको दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "शुक्ल पक्ष", + tithi: "द्वितीया", + event: "भाइटीका", + detail: "तिहारको पाँचौँ दिन, दिदी-भाइबीचको प्रेमको दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "शुक्ल पक्ष", + tithi: "षष्ठी", + event: "छठ पर्व", + detail: "सूर्य देवतालाई समर्पित उत्सव, मुख्यतया तराईमा मनाइन्छ।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "कार्तिक", + paksha: "शुक्ल पक्ष", + tithi: "एकादशी", + event: "हरिबोधिनी एकादशी", + detail: "भगवान विष्णुको जागरणको दिन।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "मार्गशीर्ष", + paksha: "शुक्ल पक्ष", + tithi: "पञ्चमी", + event: "विवाह पञ्चमी", + detail: "भगवान राम र सीताको विवाहको सम्झना।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "मार्गशीर्ष", + paksha: "शुक्ल पक्ष", + tithi: "पूर्णिमा", + event: "य:मरि पुन्हि / धान्यपुर्णिमा", + detail: "नेवार समुदायको यमरि पुन्हि / धान्य पूर्णिमाको उत्सव।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "माघ", + paksha: "शुक्ल पक्ष", + tithi: "पञ्चमी", + event: "सरस्वती पूजा / वसन्तपञ्चमी", + detail: "ज्ञान र शिक्षाको देवी सरस्वतीको पूजा।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "फाल्गुन", + paksha: "कृष्ण पक्ष", + tithi: "चतुर्दशी", + event: "महाशिवरात्रि", + detail: "भगवान शिवको महान रात्रि।", + category: "धार्मिक" + }, + { + eventType: "lunar", + lunarMonth: "फाल्गुन", + paksha: "शुक्ल पक्ष", + tithi: "पूर्णिमा", + event: "होली पूर्णिमा", + detail: "रङ्गहरूको उत्सव।", + category: "धार्मिक" + } +]; + +// Gregorian events for every year. var gregorianEvents = [ { event: "New Year's Day", dateType: "gregorian", - date: "01/01", // January 1 + date: "01/01", detail: "Celebration of the new Gregorian year.", - category: "International Day", + category: "International Day" }, { event: "Valentine's Day", dateType: "gregorian", - date: "02/14", // February 14 + date: "02/14", detail: "International day of love. Nepali: प्रणय दिवस.", category: "International Day" }, { event: "International Women's Day", dateType: "gregorian", - date: "03/08", // March 8 + date: "03/08", detail: "Global day celebrating womanhood. Nepali: नारी दिवस.", category: "International Day" }, { event: "World Health Day", dateType: "gregorian", - date: "04/07", // April 7 + date: "04/07", detail: "A global health awareness day. Nepali: विश्व स्वास्थ्य दिवस.", category: "International Day" }, { event: "International Workers' Day", dateType: "gregorian", - date: "05/01", // May 1 + date: "05/01", detail: "Also known as May Day. Nepali: अन्तर्राष्ट्रिय श्रमिक दिवस.", category: "International Day" }, { event: "World Environment Day", dateType: "gregorian", - date: "06/05", // June 5 + date: "06/05", detail: "Day for environmental awareness and action. Nepali: विश्व वातावरण दिवस.", category: "International Day" }, { event: "International Day of Yoga", dateType: "gregorian", - date: "06/21", // June 21 + date: "06/21", detail: "Global day to celebrate yoga. Nepali: विश्व योग दिवस.", category: "International Day" }, { event: "World Population Day", dateType: "gregorian", - date: "07/11", // July 11 + date: "07/11", detail: "Day to raise awareness of global population issues. Nepali: विश्व जनसंख्या दिवस.", category: "International Day" }, { event: "International Youth Day", dateType: "gregorian", - date: "08/12", // August 12 + date: "08/12", detail: "Day to celebrate young people as agents of change. Nepali: अन्तर्राष्ट्रिय युवा दिवस.", category: "International Day" }, { event: "International Human Rights Day", dateType: "gregorian", - date: "12/10", // December 10 + date: "12/10", detail: "Commemorates the adoption of the Universal Declaration of Human Rights. Nepali: अन्तर्राष्ट्रिय मानव अधिकार दिवस.", category: "International Day" }, { event: "Christmas Day", dateType: "gregorian", - date: "12/25", // December 25 + date: "12/25", detail: "Christian festival celebrating the birth of Jesus. Nepali: क्रिसमस-डे.", category: "Festival" } ]; -// Bikram recurring events (based on BS month/day) for every year or with specific start/end year ranges. +// Bikram recurring events (based on BS month/day). var bikramRecurringEvents = [ { event: "लोकतन्त्र दिवस", dateType: "brecurring", - date: "01/11", // Baisakh 11 - detail: "Loktantra Diwas (Democracy Day), celebrated annually on Baisakh 11.", + date: "01/11", + detail: "लोकतन्त्र दिवस, हरेक वर्ष बैशाख ११ गते मनाइन्छ।", category: "National Day" }, { event: "गणतन्त्र दिवस", dateType: "brecurring", - date: "02/15", // Jestha 15 - detail: "Gantantra Diwas (Republic Day), celebrated annually on Jestha 15.", + date: "02/15", + detail: "गणतन्त्र दिवस, हरेक वर्ष जेठ १५ गते मनाइन्छ।", category: "National Day" }, { event: "राष्ट्रिय धान दिवस", dateType: "brecurring", - date: "03/15", // Asar 15 - detail: "National Paddy Day, celebrated annually on Asar 15.", + date: "03/15", + detail: "राष्ट्रिय धान दिवस, हरेक वर्ष असार १५ गते मनाइन्छ।", category: "National Day" }, { event: "भानु जयन्ती", dateType: "brecurring", - date: "03/29", // Asar 29 - detail: "Bhanu Jayanti, birth anniversary of poet Bhanubhakta Acharya.", + date: "03/29", + detail: "कवि भानुभक्त आचार्यको जन्म जयन्ती।", category: "Jayanti" }, { event: "संविधान दिवस", dateType: "brecurring", - date: "06/03", // Ashwin 3 - detail: "Constitution Day, celebrated annually on Ashwin 3.", + date: "06/03", + detail: "संविधान दिवस, हरेक वर्ष असोज ३ गते मनाइन्छ।", category: "National Day" }, { event: "पृथ्वी जयन्ती / राष्ट्रिय एकता दिवस", dateType: "brecurring", - date: "09/27", // Poush 27 - detail: "Prithvi Jayanti / National Unity Day.", + date: "09/27", + detail: "पृथ्वी जयन्ती / राष्ट्रिय एकता दिवस।", category: "National Day" }, { event: "शहीद दिवस", dateType: "brecurring", - date: "10/16", // Magh 16 - detail: "Sahid Diwas (Martyrs' Day).", + date: "10/16", + detail: "शहीद दिवस।", category: "National Day" }, { event: "प्रजातन्त्र दिवस", dateType: "brecurring", - date: "11/07", // Falgun 7 - detail: "Prajatantra Diwas (Democracy Day), marking the end of Rana rule.", + date: "11/07", + detail: "राणा शासनको अन्त्यको सम्झनामा मनाइने प्रजातन्त्र दिवस।", category: "National Day" }, - { - event: "नयाँ वर्ष", - dateType: "brecurring", - date: "01/01", - detail: "Nepali New Year 2082.", - category: "Festival" - }, - { - event: "बिस्का: जात्रा", - dateType: "brecurring", - date: "01/01", - detail: "Biska Jatra festival in Bhaktapur.", - category: "Jatra" - }, - { - event: "साउने सङ्क्रान्ति", - dateType: "brecurring", - date: "04/01", - detail: "Shrawan Sankranti, first day of the month Shrawan.", - category: "Sankranti" - }, - { - event: "माघे संक्रान्ति", - dateType: "brecurring", - date: "10/01", - detail: "Maghe Sankranti, first day of the month Magh.", - category: "Sankranti" - }, -]; - -// Bikram fixed events (specific BS year/month/day). -var bikramFixedEvents = [ { - event: "मातातीर्थ औंसी", - dateType: "bikram", - date: "2082/01/14", - detail: "Mother's Day.", - category: "Festival" - }, - { - event: "अक्षय तृतीया", - dateType: "bikram", - date: "2082/01/17", - detail: "Akshaya Tritiya festival.", - category: "Festival" - }, - { - event: "बुद्ध जयन्ती / उभौली पर्व", - dateType: "bikram", - date: "2082/01/29", - detail: "Buddha's Birthday and Kirat festival Ubhauli.", - category: "Festival" - }, - { - event: "भोटो जात्रा", - dateType: "bikram", - date: "2082/02/18", - detail: "The concluding day of Rato Machindranath Jatra.", - category: "Jatra" - }, - { - event: "गुरु पुर्णिमा", - dateType: "bikram", - date: "2082/03/26", - detail: "Guru Purnima, a day to honor teachers.", - category: "Festival" - }, - { - event: "नाग पञ्चमी", - dateType: "bikram", - date: "2082/04/13", - detail: "Day of worshipping the serpent deities (Nagas).", - category: "Festival" - }, - { - event: "जनै पूर्णिमा / रक्षा बन्धन", - dateType: "bikram", - date: "2082/04/24", - detail: "The sacred thread festival.", + event: "नयाँ वर्ष", + dateType: "brecurring", + date: "01/01", + detail: "नेपाली नयाँ वर्ष।", category: "Festival" }, { - event: "गाईजात्रा", - dateType: "bikram", - date: "2082/04/25", - detail: "Festival of cows, a carnival of humor and satire.", + event: "बिस्का: जात्रा", + dateType: "brecurring", + date: "01/01", + detail: "भक्तपुरमा मनाइने बिस्का जात्राको उत्सव।", category: "Jatra" }, { - event: "श्रीकृष्ण जन्माष्टमी", - dateType: "bikram", - date: "2082/04/31", - detail: "Lord Krishna's birthday.", - category: "Jayanti" - }, - { - event: "कुशे औंसी (बुबाको मुख हेर्ने दिन)", - dateType: "bikram", - date: "2082/05/07", - detail: "Kushe Aunsi, Father's Day.", - category: "Festival" + event: "साउने सङ्क्रान्ति", + dateType: "brecurring", + date: "04/01", + detail: "श्रावण सङ्क्रान्ति, श्रावण महिनाको पहिलो दिन।", + category: "Sankranti" }, { - event: "हरितालिका तीज", - dateType: "bikram", - date: "2082/05/10", - detail: "A major festival for Hindu women.", - category: "Festival" - }, + event: "माघे संक्रान्ति", + dateType: "brecurring", + date: "10/01", + detail: "माघे सङ्क्रान्ति, माघ महिनाको पहिलो दिन।", + category: "Sankranti" + } +]; + +// Bikram fixed events (specific BS year/month/day). +var bikramFixedEvents = [ { - event: "इन्द्रजात्रा", + event: "भोटो जात्रा", dateType: "bikram", - date: "2082/05/21", - detail: "Major street festival in Kathmandu.", + date: "2082/02/18", + detail: "रातो मच्छिन्द्रनाथ जात्राको समापन दिन।", category: "Jatra" }, - { - event: "घटस्थापना", - dateType: "bikram", - date: "2082/06/06", - detail: "Marks the beginning of the Dashain festival.", - category: "Festival" - }, - { - event: "फूलपाती", - dateType: "bikram", - date: "2082/06/13", - detail: "The 7th day of Dashain.", - category: "Festival" - }, - { - event: "महाअष्टमी / कालरात्रि", - dateType: "bikram", - date: "2082/06/14", - detail: "The 8th day of Dashain, involving sacrifices.", - category: "Festival" - }, - { - event: "महानवमी", - dateType: "bikram", - date: "2082/06/15", - detail: "The 9th day of Dashain.", - category: "Festival" - }, - { - event: "विजया दशमी", - dateType: "bikram", - date: "2082/06/16", - detail: "The 10th day of Dashain, the main day of celebration.", - category: "Festival" - }, - { - event: "कोजाग्रत पूर्णिमा", - dateType: "bikram", - date: "2082/06/20", - detail: "The full moon day that marks the end of Dashain.", - category: "Festival" - }, - { - event: "लक्ष्मी पूजा / कुकुर तिहार", - dateType: "bikram", - date: "2082/07/03", - detail: "Day for worshipping Goddess Laxmi and dogs.", - category: "Festival" - }, - { - event: "गाई पूजा / गोवर्धन पूजा / म्हपूजा", - dateType: "bikram", - date: "2082/07/05", - detail: "Day for worshipping cows, oxen, and oneself (Mha Puja).", - category: "Festival" - }, - { - event: "भाइटीका", - dateType: "bikram", - date: "2082/07/06", - detail: "The final and main day of Tihar, celebrating siblings.", - category: "Festival" - }, - { - event: "छठ पर्व", - dateType: "bikram", - date: "2082/07/10", - detail: "Festival dedicated to the Sun God, mainly in Terai.", - category: "Festival" - }, - { - event: "विवाह पञ्चमी", - dateType: "bikram", - date: "2082/08/09", - detail: "Commemorates the wedding of Lord Ram and Sita.", - category: "Festival" - }, - { - event: "य:मरि पुन्हि / धान्यपुर्णिमा", - dateType: "bikram", - date: "2082/08/18", - detail: "Newari festival of Yamari Punhi / Dhanya Purnima.", - category: "Festival" - }, { event: "तमु ल्होसार", dateType: "bikram", date: "2082/09/15", - detail: "New Year of the Gurung community.", + detail: "गुरुङ समुदायको नयाँ वर्ष।", category: "Lhosar" }, { event: "सोनाम ल्होसार", dateType: "bikram", date: "2082/10/05", - detail: "New Year of the Tamang community.", + detail: "तमाङ समुदायको नयाँ वर्ष।", category: "Lhosar" }, - { - event: "सरस्वती पूजा / वसन्तपञ्चमी", - dateType: "bikram", - date: "2082/10/09", - detail: "Saraswati Puja / Vasant Panchami, day of learning.", - category: "Festival" - }, - { - event: "महा शिवरात्री / नेपाली सेना दिवस", - dateType: "bikram", - date: "2082/11/04", - detail: "Festival of Lord Shiva and Nepali Army Day.", - category: "Festival" - }, { event: "ग्याल्पो ल्होछार", dateType: "bikram", date: "2082/11/06", - detail: "New Year of the Sherpa community.", + detail: "शेर्पा समुदायको नयाँ वर्ष।", category: "Lhosar" }, { - event: "फागु पुर्णिमा / होली", - dateType: "bikram", - date: "2082/11/18", - detail: "Holi, the festival of colors.", - category: "Festival" - }, - { - event: "घोडेजात्रा", - dateType: "bikram", - date: "2082/12/04", - detail: "Ghode Jatra, the horse parade festival in Kathmandu.", - category: "Jatra" - }, - { - event: "चैते दशैँ", - dateType: "bikram", - date: "2082/12/12", - detail: "Chaite Dashain, a smaller version of the great Dashain.", - category: "Festival" - }, - { - event: "श्री राम नवमी", + event: "महा शिवरात्री / नेपाली सेना दिवस", dateType: "bikram", - date: "2082/12/13", - detail: "Celebration of Lord Ram's birthday.", + date: "2082/11/04", + detail: "भगवान शिवको महान रात्रि र नेपाली सेनाको दिवस।", category: "Festival" } ]; diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index 7fdff95..ab0415c 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -83,13 +83,10 @@ var nepaliGregorianMonths = [ // Helper Functions -function zero360(x) { - x = x - Math.floor(x / 360) * 360; - return x < 0 ? x + 360 : x; -} -function sinDeg(deg) { return Math.sin(deg * Math.PI / 180); } -function cosDeg(deg) { return Math.cos(deg * Math.PI / 180); } -function arcsinDeg(x) { return Math.asin(x) * 180 / Math.PI; } +function zero360(x) { return x - Math.floor(x / 360) * 360; } +function sinDeg(deg) { return Math.sin(deg / rad); } +function cosDeg(deg) { return Math.cos(deg / rad); } +function arcsinDeg(x) { return Math.asin(x) * rad; } function toDevanagari(num) { if (num <= 0) return ""; @@ -139,7 +136,7 @@ function fromJulianDay(jd) { return new Date(Date.UTC(year, month - 1, day)); } -// Surya Siddhanta Core Calculations (Used as fallback) +// Core Surya Siddhanta Calculations function meanLongitude(ahar, rotation) { return zero360(rotation * ahar * 360 / YugaCivilDays); } @@ -166,225 +163,64 @@ function getTithi(sunLong, moonLong) { return zero360(moonLong - sunLong) / 12; } -// Determine if today is the first day of a new solar month -function todaySauraMasaFirstP(ahar) { - var tslong_today = getTslong(ahar); - var tslong_tomorrow = getTslong(ahar + 1); - tslong_today -= Math.floor(tslong_today / 30) * 30; - tslong_tomorrow -= Math.floor(tslong_tomorrow / 30) * 30; - return (25 < tslong_today && tslong_tomorrow < 5); -} - -// Calculate solar longitude -function getTslong(ahar) { - var t1 = (YugaRotation.sun * ahar / YugaCivilDays); - t1 -= Math.floor(t1); - var mslong = 360 * t1; - var x1 = mslong - PlanetApogee.sun; - var y1 = PlanetCircumm.sun / 360; - var y2 = sinDeg(x1); - var y3 = y1 * y2; - var x2 = arcsinDeg(y3); - var x3 = mslong - x2; - return x3; -} - -// Recursively determines solar month and day -function getSauraMasaDay(ahar) { - if (todaySauraMasaFirstP(ahar)) { - var day = 1; - var tslong_tomorrow = getTslong(ahar + 1); - var month = Math.floor(tslong_tomorrow / 30) % 12; - month = (month + 12) % 12; - return { m: month, d: day }; - } else { - var yesterday = getSauraMasaDay(ahar - 1); - return { m: yesterday.m, d: yesterday.d + 1 }; - } -} - -// Astronomical conversion from Gregorian to Bikram -function fromGregorianAstronomical(gYear, gMonth, gDay) { - var julian = toJulianDay(gYear, gMonth - 1, gDay); - var ahar = julian - KaliEpoch; - - var sauraMasaResult = getSauraMasaDay(ahar); - var saura_masa_num = sauraMasaResult.m; - var saura_masa_day = sauraMasaResult.d; - - var YearKali = Math.floor(ahar * YugaRotation.sun / YugaCivilDays); - var YearSaka = YearKali - 3179; - var nepalimonth = saura_masa_num % 12; - var year = YearSaka + 135 + Math.floor((saura_masa_num - nepalimonth) / 12); - var month = (saura_masa_num + 12) % 12 + 1; - - return { - year: year, - monthIndex: month - 1, - day: saura_masa_day, - monthName: solarMonths[month - 1] - }; -} - - - function findNewMoon(ahar) { - var getElongation = function(a) { - return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); - }; - + var getElongation = function(a) { return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); }; var guess = ahar; - var step = 0.5; - for (var i = 0; i < 10; i++) { var elong = getElongation(guess); - - if (elong < 5 || elong > 355) { - break; - } - - if (elong < 180) { - guess -= (elong / 360) * 29.53; - } else { - guess += ((360 - elong) / 360) * 29.53; - } + if (elong < 5 || elong > 355) break; + var correction = (elong < 180 ? -elong : 360 - elong) / 12.19; + guess += correction; } - - var lo = guess - 1; - var hi = guess + 1; - - for (let i = 0; i < 50; i++) { + var lo = guess - 2, hi = guess + 2; + for (var j = 0; j < 30; j++) { var mid = (lo + hi) / 2; var em = getElongation(mid); - - if (em < 180) { - hi = mid; - } else { - lo = mid; - } + if (em < 180) { hi = mid; } else { lo = mid; } } - return (lo + hi) / 2; } -function calculateAdhikaMasa(ahar) { - var lunarMonthStart = findNewMoon(ahar); - if (lunarMonthStart > ahar) { - lunarMonthStart = findNewMoon(lunarMonthStart - 29.530588853); +function getLunarMonthInfo(ahar) { + var lunarMonthStartAhar = findNewMoon(ahar); + if (lunarMonthStartAhar > ahar) { + lunarMonthStartAhar = findNewMoon(lunarMonthStartAhar - 29.53); } - - var lunarMonthEnd = findNewMoon(lunarMonthStart + 29.530588853); - var sunLongStart = trueLongitudeSun(lunarMonthStart); - var sunLongEnd = trueLongitudeSun(lunarMonthEnd); - + var lunarMonthEndAhar = findNewMoon(lunarMonthStartAhar + 29.53); + var sunLongStart = trueLongitudeSun(lunarMonthStartAhar); + var sunLongEnd = trueLongitudeSun(lunarMonthEndAhar); var startSign = Math.floor(sunLongStart / 30); var endSign = Math.floor(sunLongEnd / 30); - - var signCrossings = 0; - var currentSign = startSign; - - for (var i = 1; i <= 29; i++) { - var checkAhar = lunarMonthStart + i; - var checkSunLong = trueLongitudeSun(checkAhar); - var checkSign = Math.floor(checkSunLong / 30); - - if (checkSign < currentSign) { - checkSign += 12; - } - - if (checkSign > currentSign) { - signCrossings += (checkSign - currentSign); - currentSign = checkSign % 12; - } - } - - if (endSign < currentSign) { - endSign += 12; - } - if (endSign > currentSign) { - signCrossings += (endSign - currentSign); - } - - var result = "छैन"; - - if (signCrossings === 0) { - result = "अधिक " + solarMonths[startSign] - } - - if (signCrossings >= 2) { - var skippedSign = (startSign + 1) % 12; - result = "क्षय " + solarMonths[skippedSign] - } - - return result; -} - -function getLunarMonthNameWithAdhik(ahar) { - var lunarMonthStart = findNewMoon(ahar); - if (lunarMonthStart > ahar) { - lunarMonthStart = findNewMoon(lunarMonthStart - 29.53); - } - - var purnima = findNewMoon(lunarMonthStart + 14.77); // ~14.77 days after new moon - - var sunLongPurnima = trueLongitudeSun(purnima); - var purnimaSign = Math.floor(sunLongPurnima / 30); - - var signCrossings = 0; - var currentSign = Math.floor(trueLongitudeSun(lunarMonthStart) / 30); - - for (var i = 1; i <= 29; i++) { - var checkAhar = lunarMonthStart + i; - var checkSunLong = trueLongitudeSun(checkAhar); - var checkSign = Math.floor(checkSunLong / 30); - - if (checkSign < currentSign) { - checkSign += 12; - } - - if (checkSign > currentSign) { - signCrossings += (checkSign - currentSign); - currentSign = checkSign % 12; - } - } - - var isAdhik = (signCrossings === 0); - var result = { - monthName: solarMonths[purnimaSign], - isAdhik: isAdhik - }; - return result; + var isAdhika = (startSign === endSign); + var newMoonRashiIndex = Math.floor(sunLongStart / 30); + var monthName = solarMonths[newMoonRashiIndex]; + return { monthName: monthName, isAdhika: isAdhika }; } function getSunriseSunset(date, lat, lon, tz) { - lat = lat || 27.71; - lon = lon || 85.32; + lat = lat || 27.7172; + lon = lon || 85.3240; tz = tz || 5.75; - var oneDay = 86400000; - var dayOfYear = Math.ceil((date.getTime() - new Date(date.getUTCFullYear(), 0, 0).getTime()) / oneDay); - - var declination = 23.45 * sinDeg(360 / 365 * (dayOfYear - 81)); - var B = (360 / 365) * (dayOfYear - 81); - var eot = 9.87 * sinDeg(2 * B) - 7.53 * cosDeg(B) - 1.5 * sinDeg(B); - var timeCorr = (4 * (lon - 15 * tz) + eot) / 60; - var cosH = (sinDeg(-0.833) - sinDeg(lat) * sinDeg(declination)) / (cosDeg(lat) * cosDeg(declination)); - var H = (cosH >= -1 && cosH <= 1) ? Math.acos(cosH) * 180 / Math.PI : 90; - var noon = 12 - timeCorr; - var rise = noon - H / 15; - var set = noon + H / 15; - - var formatTime = function (h) { + var dayOfYear = Math.floor((date - new Date(date.getUTCFullYear(), 0, 0)) / 86400000); + var B = (360 / 365) * (dayOfYear - 81) / rad; + var eot = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B); + var lstm = 15 * tz; + var tc = (4 * (lon - lstm) + eot) / 60; + var declination = -23.45 * cosDeg(360 / 365 * (dayOfYear + 10)); + var hourAngleRad = Math.acos((sinDeg(-0.833) - sinDeg(lat) * sinDeg(declination)) / (cosDeg(lat) * cosDeg(declination))); + var hourAngle = hourAngleRad * rad; + var sunrise = 12 - hourAngle / 15 - tc; + var sunset = 12 + hourAngle / 15 - tc; + var formatTime = function(h) { if (!isFinite(h)) return "N/A"; var hr = Math.floor(h); var min = Math.round((h - hr) * 60); if (min === 60) { hr++; min = 0; } return (hr < 10 ? '0' : '') + hr + ":" + (min < 10 ? '0' : '') + min; }; - return { sunrise: formatTime(rise), sunset: formatTime(set) }; + return { sunrise: formatTime(sunrise), sunset: formatTime(sunset) }; } -// Data-Driven Conversion with fallback to astronomical calculations - function fromBikramSambat(bsYear, monthIndex, day) { if (bsYear >= Bsdata.BS_START_YEAR && bsYear <= Bsdata.BS_END_YEAR) { var daysOffset = 0; @@ -397,41 +233,21 @@ function fromBikramSambat(bsYear, monthIndex, day) { daysOffset += totalDaysInYear; } var targetYearData = Bsdata.NP_MONTHS_DATA[bsYear - Bsdata.BS_START_YEAR]; - for (let m = 0; m < monthIndex; m++) { + for (var m = 0; m < monthIndex; m++) { daysOffset += targetYearData[m]; } daysOffset += (day - 1); - var resultDate = new Date(Bsdata.BS_START_DATE_AD.getTime()); resultDate.setUTCDate(resultDate.getUTCDate() + daysOffset); return resultDate; - } else { - // Fallback for out-of-range years - USE TS IMPLEMENTATION - var YearSaka = bsYear - 135; - var YearKali = YearSaka + 3179; - var ahar = Math.floor((YearKali * YugaCivilDays) / YugaRotation.sun); - - // Find the exact date - var currentDay = getSauraMasaDay(ahar); - - // Adjust to find the exact date - while (currentDay.m !== monthIndex || currentDay.d !== day) { - if (currentDay.m < monthIndex || (currentDay.m === monthIndex && currentDay.d < day)) { - ahar += 1; - } else { - ahar -= 1; - } - currentDay = getSauraMasaDay(ahar); - } - - var julian_date = ahar + KaliEpoch; - return fromJulianDay(julian_date); } + return null; } function getBikramMonthInfo(bsYear, monthIndex) { if (bsYear >= Bsdata.BS_START_YEAR && bsYear <= Bsdata.BS_END_YEAR) { var firstDayAd = fromBikramSambat(bsYear, monthIndex, 1); + if (!firstDayAd) return null; var monthData = Bsdata.NP_MONTHS_DATA[bsYear - Bsdata.BS_START_YEAR]; return { totalDays: monthData[monthIndex], @@ -439,182 +255,131 @@ function getBikramMonthInfo(bsYear, monthIndex) { monthName: solarMonths[monthIndex], year: bsYear }; - } else { - // Fallback for out-of-range years - var first = fromBikramSambat(bsYear, monthIndex, 1); - var nextMon = monthIndex === 11 ? 0 : monthIndex + 1; - var nextYear = monthIndex === 11 ? bsYear + 1 : bsYear; - var nextFirst = fromBikramSambat(nextYear, nextMon, 1); - var jd1 = toJulianDay(first.getUTCFullYear(), first.getUTCMonth(), first.getUTCDate()); - var jd2 = toJulianDay(nextFirst.getUTCFullYear(), nextFirst.getUTCMonth(), nextFirst.getUTCDate()); - return { - totalDays: Math.round(jd2 - jd1), - startDayOfWeek: first.getUTCDay(), - monthName: solarMonths[monthIndex], - year: bsYear - }; } + return null; } -function toBikramSambat(gregorianDate, lon = 85.32, tz = 5.75) { - // Ensure we are comparing UTC dates to avoid timezone-related off-by-one errors - const targetUtcDate = new Date(Date.UTC( - gregorianDate.getUTCFullYear(), - gregorianDate.getUTCMonth(), - gregorianDate.getUTCDate() - )); - - const startDate = new Date(Date.UTC( - Bsdata.BS_START_DATE_AD.getUTCFullYear(), - Bsdata.BS_START_DATE_AD.getUTCMonth(), - Bsdata.BS_START_DATE_AD.getUTCDate() - )); - - // Attempt to use the fast, data-driven conversion first - if (targetUtcDate >= startDate) { - let daysOffset = Math.floor((targetUtcDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)); - - for (let y = 0; y < Bsdata.NP_MONTHS_DATA.length; y++) { - const currentBsYear = Bsdata.BS_START_YEAR + y; - const yearData = Bsdata.NP_MONTHS_DATA[y]; - - let daysInYear = 0; - for (var m = 0; m < 12; m++) { - daysInYear += yearData[m]; - } - +function toBikramSambat(gregorianDate) { + var targetUtcDate = new Date(Date.UTC(gregorianDate.getFullYear(), gregorianDate.getMonth(), gregorianDate.getDate())); + var startDate = new Date(Date.UTC(Bsdata.BS_START_DATE_AD.getFullYear(), Bsdata.BS_START_DATE_AD.getMonth(), Bsdata.BS_START_DATE_AD.getDate())); + if (targetUtcDate >= startDate && Bsdata.NP_MONTHS_DATA) { + var daysOffset = Math.floor((targetUtcDate.getTime() - startDate.getTime()) / 86400000); + for (var y = 0; y < Bsdata.NP_MONTHS_DATA.length; y++) { + var currentBsYear = Bsdata.BS_START_YEAR + y; + var yearData = Bsdata.NP_MONTHS_DATA[y]; + var daysInYear = 0; + for (var m_idx = 0; m_idx < 12; m_idx++) { daysInYear += yearData[m_idx]; } if (daysOffset < daysInYear) { - for (let m = 0; m < 12; m++) { - const daysInMonth = yearData[m]; + for (var m = 0; m < 12; m++) { + var daysInMonth = yearData[m]; if (daysOffset < daysInMonth) { - return { - year: currentBsYear, - monthIndex: m, - day: daysOffset + 1, - monthName: solarMonths[m] - }; + return { year: currentBsYear, monthIndex: m, day: daysOffset + 1, monthName: solarMonths[m] }; } daysOffset -= daysInMonth; } - // Should not reach here - if we do, it's an error - break; - } else { - daysOffset -= daysInYear; } + daysOffset -= daysInYear; } } - - // Fallback to astronomical calculation if the date is outside the pre-calculated range - var jd = toJulianDay( - gregorianDate.getUTCFullYear(), - gregorianDate.getUTCMonth(), - gregorianDate.getUTCDate() - ); - - return fromGregorianAstronomical( - gregorianDate.getUTCFullYear(), - gregorianDate.getUTCMonth() + 1, - gregorianDate.getUTCDate() - ); -} - -function getTodayBsInfo() { - var now = new Date(); - - // Attempt to use the fast, data-driven conversion first - var bsInfo = toBikramSambat(now); - if (bsInfo) { - return bsInfo; - } - - // Fallback to astronomical calculation if the date is outside the pre-calculated range - var jd = toJulianDay(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()); - var ahar = jd - KaliEpoch + 0.25 + ((85.3 / 15 - 5.75) / 24); - var sunLong = trueLongitudeSun(ahar); - return getBikramSambatInfo(ahar, sunLong); + return null; } -// Shared Name Resolution Utility function resolveTithiName(tithiDay, paksha) { if (paksha === "कृष्ण पक्ष" && tithiDay === 15) return tithiNamesList[15]; if (paksha === "शुक्ल पक्ष" && tithiDay === 15) return tithiNamesList[14]; return tithiNamesList[tithiDay - 1]; } -// Event Calculation Function +function _getPanchangaBasics(date) { + var jd = toJulianDay(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); + var ahar = jd - KaliEpoch + 0.25 + ((85.3240 / 15 - 5.75) / 24); // Standard location for consistency + var sunLong = trueLongitudeSun(ahar); + var moonLong = trueLongitudeMoon(ahar); + var tithiVal = getTithi(sunLong, moonLong); + var tithiNum = Math.floor(tithiVal) + 1; + var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; + var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; + var tithiName = resolveTithiName(tithiDay, paksha); + var lunarMonthInfo = getLunarMonthInfo(ahar); + return { + lunarMonthName: lunarMonthInfo.monthName, + paksha: paksha, + tithiName: tithiName, + tithiDay: tithiDay + }; +} + function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { - const events = []; - const gregorianMonth = date.getUTCMonth() + 1; // 1-indexed month - const gregorianDay = date.getUTCDate(); - const gregorianYear = date.getUTCFullYear(); - - const formattedGregorianDate = formatMonthDay(gregorianMonth, gregorianDay); - const formattedBikramRecurringDate = formatMonthDay(bsMonthIndex + 1, bsDay); - - // Check Gregorian events - for (var i = 0; i < EventsData.gregorianEvents.length; i++) { - var event = EventsData.gregorianEvents[i]; - if (event.dateType === "gregorian" && event.date === formattedGregorianDate) { - var isValidYear = (!event.startYear || gregorianYear >= event.startYear) && - (!event.endYear || gregorianYear <= event.endYear); - if (isValidYear) { - events.push({ - name: event.event, - detail: event.detail, - category: event.category - }); + var events = []; + var gregorianMonth = date.getUTCMonth() + 1; + var gregorianDay = date.getUTCDate(); + var formattedGregorianDate = formatMonthDay(gregorianMonth, gregorianDay); + var formattedBikramRecurringDate = formatMonthDay(bsMonthIndex + 1, bsDay); + + if (EventsData.gregorianEvents) { + for (var i = 0; i < EventsData.gregorianEvents.length; i++) { + var event = EventsData.gregorianEvents[i]; + if (event.date === formattedGregorianDate) { + events.push({ name: event.event, detail: event.detail, category: event.category }); } } } - - // Check Bikram recurring events - for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { - let event = EventsData.bikramRecurringEvents[j]; - if (event.dateType === "brecurring" && event.date === formattedBikramRecurringDate) { - const isValidYear = (!event.startYear || bsYear >= event.startYear) && - (!event.endYear || bsYear <= event.endYear); - if (isValidYear) { - events.push({ - name: event.event, - detail: event.detail, - category: event.category - }); + if (EventsData.bikramRecurringEvents) { + for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { + var event = EventsData.bikramRecurringEvents[j]; + if (event.date === formattedBikramRecurringDate) { + events.push({ name: event.event, detail: event.detail, category: event.category }); } } } - // Check Bikram fixed events - for (var k = 0; k < EventsData.bikramFixedEvents.length; k++) { - let event = EventsData.bikramFixedEvents[k]; - if (event.dateType === "bikram") { - const eventDateParts = event.date.split('/').map(Number); - if (eventDateParts[0] === bsYear && - eventDateParts[1] === (bsMonthIndex + 1) && - eventDateParts[2] === bsDay) { - events.push({ - name: event.event, - detail: event.detail, - category: event.category - }); + if (EventsData.lunarEvents) { + var todayInfo = _getPanchangaBasics(date); + var yesterday = new Date(date.getTime() - 86400000); + var yesterdayInfo = _getPanchangaBasics(yesterday); + + var tithiDayMap = {}; + tithiNamesList.forEach(function(name, index) { + if (name === "पूर्णिमा" || name === "अमावस्या") { + tithiDayMap[name] = 15; + } else { + tithiDayMap[name] = index + 1; + } + }); + + for (var k = 0; k < EventsData.lunarEvents.length; k++) { + var lunarEvent = EventsData.lunarEvents[k]; + var eventTithiDay = tithiDayMap[lunarEvent.tithi]; + if (!eventTithiDay) continue; + + var eventStartedToday = false; + if (todayInfo.lunarMonthName === yesterdayInfo.lunarMonthName && todayInfo.paksha === yesterdayInfo.paksha) { + if (eventTithiDay > yesterdayInfo.tithiDay && eventTithiDay <= todayInfo.tithiDay) { + eventStartedToday = true; + } + } else { + if (lunarEvent.lunarMonth === todayInfo.lunarMonthName && + lunarEvent.paksha === todayInfo.paksha && + eventTithiDay <= todayInfo.tithiDay) { + eventStartedToday = true; + } + } + + if (eventStartedToday) { + if (lunarEvent.lunarMonth === todayInfo.lunarMonthName && lunarEvent.paksha === todayInfo.paksha) { + events.push({ name: lunarEvent.event, detail: lunarEvent.detail, category: lunarEvent.category }); + } } } } return events; } -// Main Calculation Function -function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { +function calculate(date, lat, lon, tz) { var cacheKey = "panchanga_" + date.getTime(); if (calculationCache[cacheKey]) return calculationCache[cacheKey]; - - var jd = toJulianDay( - date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDate() - ); - - var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); - + var jd = toJulianDay(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); + var ahar = jd - KaliEpoch + 0.25 + (((lon || 85.3240) / 15 - (tz || 5.75)) / 24); var sunLong = trueLongitudeSun(ahar); var moonLong = trueLongitudeMoon(ahar); var tithiVal = getTithi(sunLong, moonLong); @@ -622,147 +387,273 @@ function calculate(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; var tithiName = resolveTithiName(tithiDay, paksha); - var karanaIdx = Math.floor(2 * tithiVal); - var karanaName = karanaIdx > 0 - ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) - : karanas[0]; - - // Always use data-driven conversion for Bikram Sambat date - var bsInfo = toBikramSambat(date, lon, tz); - + var karanaName = karanaIdx > 0 ? (karanaIdx < 57 ? karanas[(karanaIdx-1) % 7 + 1] : karanas[karanaIdx - 57 + 8]) : karanas[0]; + var bsInfo = toBikramSambat(date); + if (!bsInfo) return { error: "Date out of range" }; + var lunarMonthInfo = getLunarMonthInfo(ahar); + var events = getEventsForDate(date, bsInfo.year, bsInfo.monthIndex, bsInfo.day); + var lunarMonthDisplayName = lunarMonthInfo.isAdhika ? "अधिक " + lunarMonthInfo.monthName : lunarMonthInfo.monthName; var sunriseSunset = getSunriseSunset(date, lat, lon, tz); var isComputed = (bsInfo.year < Bsdata.BS_START_YEAR || bsInfo.year > Bsdata.BS_END_YEAR); - - var events = getEventsForDate(date, bsInfo.year, bsInfo.monthIndex, bsInfo.day); + var adhikaMasa = calculateAdhikaMasa(ahar); var result = { gregorianDate: Qt.formatDateTime(date, "dddd, MMMM d, yyyy"), - bikramSambat: `${bsInfo.year} ${bsInfo.monthName} ${bsInfo.day}`, + bikramSambat: toDevanagari(bsInfo.year) + " " + bsInfo.monthName + " " + toDevanagari(bsInfo.day), bsYear: bsInfo.year, bsMonthIndex: bsInfo.monthIndex, bsDay: bsInfo.day, - monthName: bsInfo.monthName, weekday: weekdays[date.getUTCDay()], sunrise: sunriseSunset.sunrise, sunset: sunriseSunset.sunset, tithi: tithiName, paksha: paksha, - nakshatra: nakshatras[Math.floor(moonLong * 27 / 360) % 27], - yoga: yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27], + lunarMonth: lunarMonthDisplayName, + nakshatra: nakshatras[Math.floor(moonLong / (360 / 27))], + yoga: yogas[Math.floor(zero360(sunLong + moonLong) / (360 / 27))], karana: karanaName, - sunRashi: rashis[Math.floor(sunLong / 30) % 12], - moonRashi: rashis[Math.floor(moonLong / 30) % 12], - adhikaMasa: calculateAdhikaMasa(ahar), + sunRashi: rashis[Math.floor(sunLong / 30)], + moonRashi: rashis[Math.floor(moonLong / 30)], events: events, - isComputed: isComputed + isComputed: isComputed, + adhikaMasa: adhikaMasa }; calculationCache[cacheKey] = result; return result; } -// Debug calculations -function generateDebugInfo(date, lat = 27.7172, lon = 85.3240, tz = 5.75) { - var cacheKey = "debug_" + date.getTime(); - if (calculationCache[cacheKey]) return calculationCache[cacheKey]; - var bsInfoData = toBikramSambat(date, lon, tz); +// --- START: Restored Debug Function and Dependencies --- +function getTslong(ahar) { + var t1 = (YugaRotation.sun * ahar / YugaCivilDays); + t1 -= Math.floor(t1); + var mslong = 360 * t1; + var x1 = mslong - PlanetApogee.sun; + var y1 = PlanetCircumm.sun / 360; + var y2 = sinDeg(x1); + var y3 = y1 * y2; + var x2 = arcsinDeg(y3); + var x3 = mslong - x2; + return x3; +} - var jd = toJulianDay( - date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDate() - ); - var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); +function todaySauraMasaFirstP(ahar) { + var tslong_today = getTslong(ahar); + var tslong_tomorrow = getTslong(ahar + 1); + tslong_today -= Math.floor(tslong_today / 30) * 30; + tslong_tomorrow -= Math.floor(tslong_tomorrow / 30) * 30; + return (25 < tslong_today && tslong_tomorrow < 5); +} - var sunLong = trueLongitudeSun(ahar); - var moonLong = trueLongitudeMoon(ahar); - var tithiVal = getTithi(sunLong, moonLong); - var tithiNum = Math.floor(tithiVal) + 1; - var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; - var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; - var tithiName = resolveTithiName(tithiDay, paksha); +function getSauraMasaDay(ahar) { + try { + if (todaySauraMasaFirstP(ahar)) { + var day = 1; + var tslong_tomorrow = getTslong(ahar + 1); + var month = Math.floor(tslong_tomorrow / 30) % 12; + month = (month + 12) % 12; + return { m: month, d: day }; + } else { + var yesterday = getSauraMasaDay(ahar - 1); + return { m: yesterday.m, d: yesterday.d + 1 }; + } + } catch (e) { + return { m: 0, d: 1 }; + } +} - var karanaIdx = Math.floor(2 * tithiVal); - var karanaName = karanaIdx > 0 - ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) - : karanas[0]; - - var bsInfoCalc = fromGregorianAstronomical( - date.getUTCFullYear(), - date.getUTCMonth() + 1, - date.getUTCDate() - ); - - var dayDifference = 0; - var gregFromAstronomical = fromBikramSambat( - bsInfoCalc.year, - bsInfoCalc.monthIndex, - bsInfoCalc.day - ); - - // Calculate difference in milliseconds - var timeDiff = date.getTime() - gregFromAstronomical.getTime(); - dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); - var dayDifferenceDisplay = dayDifference; - if (Math.abs(dayDifference) > 2) { // Show in red if difference is more than 2 days - dayDifferenceDisplay = `${dayDifference}`; - } else if (Math.abs(dayDifference) > 0) { - dayDifferenceDisplay = `${dayDifference}`; +function fromGregorianAstronomical(gYear, gMonth, gDay) { + var julian = toJulianDay(gYear, gMonth - 1, gDay); + var ahar = julian - KaliEpoch; + var sauraMasaResult = getSauraMasaDay(ahar); + var saura_masa_num = sauraMasaResult.m; + var saura_masa_day = sauraMasaResult.d; + var YearKali = Math.floor(ahar * YugaRotation.sun / YugaCivilDays); + var YearSaka = YearKali - 3179; + var nepalimonth = saura_masa_num % 12; + var year = YearSaka + 135 + Math.floor((saura_masa_num - nepalimonth) / 12); + var month = (saura_masa_num + 12) % 12 + 1; + return { + year: year, + monthIndex: month - 1, + day: saura_masa_day, + monthName: solarMonths[month - 1] + }; +} + +function calculateAdhikaMasa(ahar) { + var lunarMonthStart = findNewMoon(ahar); + if (lunarMonthStart > ahar) { + lunarMonthStart = findNewMoon(lunarMonthStart - 29.530588853); + } + var lunarMonthEnd = findNewMoon(lunarMonthStart + 29.530588853); + var sunLongStart = trueLongitudeSun(lunarMonthStart); + var sunLongEnd = trueLongitudeSun(lunarMonthEnd); + var startSign = Math.floor(sunLongStart / 30); + var endSign = Math.floor(sunLongEnd / 30); + var signCrossings = 0; + var currentSign = startSign; + for (var i = 1; i <= 29; i++) { + var checkAhar = lunarMonthStart + i; + var checkSunLong = trueLongitudeSun(checkAhar); + var checkSign = Math.floor(checkSunLong / 30); + if (checkSign < currentSign) { + checkSign += 12; + } + if (checkSign > currentSign) { + signCrossings += (checkSign - currentSign); + currentSign = checkSign % 12; } - var sunriseSunset = getSunriseSunset(date, lat, lon, tz); - var isComputed = (bsInfoData.year < Bsdata.BS_START_YEAR || bsInfoData.year > Bsdata.BS_END_YEAR); - - var dataDrivenInfo = ""; - if (bsInfoData && !isComputed) { - dataDrivenInfo = `Debug Information (Data-Driven for date conversion): -Data-Driven BS Date: ${toDevanagari(bsInfoData.year)} ${bsInfoData.monthName} ${toDevanagari(bsInfoData.day)} -(panchanga is based in computation) -`; - } else { - dataDrivenInfo = `Debug Information (Astronomical Calculation - outside data range): -Data-Driven BS Date: Not available (using astronomical calculation) -`; } + if (endSign < currentSign) { + endSign += 12; + } + if (endSign > currentSign) { + signCrossings += (endSign - currentSign); + } + if (signCrossings === 0) { + return "अधिक " + solarMonths[startSign]; + } + if (signCrossings >= 2) { + var skippedSign = (startSign + 1) % 12; + return "क्षय " + solarMonths[skippedSign]; + } + return "छैन"; +} - var lunarMonthInfo = getLunarMonthNameWithAdhik(ahar); - var lunarMonthDisplay; - if (lunarMonthInfo.isAdhik) { - lunarMonthDisplay = "अधिक " + lunarMonthInfo.monthName + " " + paksha; - } else { - lunarMonthDisplay = lunarMonthInfo.monthName + " " + paksha; - } - - var debugOutput = ` -
-${dataDrivenInfo}Consistency Check:
-Data-Driven BS Date: ${bsInfoData ? `${toDevanagari(bsInfoData.year)} ${bsInfoData.monthName} ${toDevanagari(bsInfoData.day)}` : 'N/A'}
-Astronomical BS Date (Corrected): ${toDevanagari(bsInfoCalc.year)} ${bsInfoCalc.monthName} ${toDevanagari(bsInfoCalc.day)}
-Day Difference: ${dayDifferenceDisplay} ${Math.abs(dayDifference) === 1 ? 'day' : 'days'}
-lunar Month(testing): ${lunarMonthDisplay}
-Note: Positive = Astronomical date is behind;
-Negative = Astronomical date is ahead)
-Detailed Astronomical Calculation:
-gregorianDate: ${Qt.formatDateTime(date, "dddd, MMMM d, yyyy")}
-bsMonthIndex(0 based index): ${bsInfoCalc.monthIndex}
-weekday(UTC): ${weekdays[date.getUTCDay()]}
-sunrise: ${sunriseSunset.sunrise}
-sunset: ${sunriseSunset.sunset}
-tithi: ${tithiName} | index: ${tithiDay}
-tithiAngle: ${(tithiVal * 12).toFixed(4)}°
-paksha: ${paksha}
-nakshatra: ${nakshatras[Math.floor(moonLong * 27 / 360) % 27]} | index: ${Math.floor(moonLong * 27 / 360) % 27 + 1}
-yoga: ${yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27]} | index: ${Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1}
-yogaAngle: ${zero360(sunLong + moonLong).toFixed(4)}°
-karana: ${karanaName} | index: ${karanaIdx}
-karanaAngle: ${(2 * tithiVal).toFixed(4)}
-sunRashi: ${rashis[Math.floor(sunLong / 30) % 12]} | index: ${Math.floor(sunLong / 30) % 12 + 1}
-moonRashi: ${rashis[Math.floor(moonLong / 30) % 12]} | index: ${Math.floor(moonLong / 30) % 12 + 1}
-adhikaMasa: ${calculateAdhikaMasa(ahar)}(approximation)
-isComputed: ${isComputed}
-    
- `.trim(); - - var result = { debug: debugOutput.replace(/^\s*[\r\n]/gm, "") }; - calculationCache[cacheKey] = result; +function getLunarMonthNameWithAdhik(ahar) { + var lunarMonthStart = findNewMoon(ahar); + if (lunarMonthStart > ahar) { + lunarMonthStart = findNewMoon(lunarMonthStart - 29.53); + } + var purnima = findNewMoon(lunarMonthStart + 14.77); + var sunLongPurnima = trueLongitudeSun(purnima); + var purnimaSign = Math.floor(sunLongPurnima / 30); + var signCrossings = 0; + var currentSign = Math.floor(trueLongitudeSun(lunarMonthStart) / 30); + for (var i = 1; i <= 29; i++) { + var checkAhar = lunarMonthStart + i; + var checkSunLong = trueLongitudeSun(checkAhar); + var checkSign = Math.floor(checkSunLong / 30); + if (checkSign < currentSign) { + checkSign += 12; + } + if (checkSign > currentSign) { + signCrossings += (checkSign - currentSign); + currentSign = checkSign % 12; + } + } + var isAdhika = (signCrossings === 0); + var result = { + monthName: solarMonths[purnimaSign], + isAdhika: isAdhika + }; return result; } + +// Debug calculations +function generateDebugInfo(date, lat, lon, tz) { +    lat = lat || 27.7172; +    lon = lon || 85.3240; +    tz = tz || 5.75; +    var cacheKey = "debug_" + date.getTime(); +    if (calculationCache[cacheKey]) return calculationCache[cacheKey]; +    var bsInfoData = toBikramSambat(date, lon, tz); + +    if (!bsInfoData) { +        return { debug: "Date out of pre-calculated range." }; +    } + +    var jd = toJulianDay( +        date.getUTCFullYear(), +        date.getUTCMonth(), +        date.getUTCDate() +    ); +    var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); + +    var sunLong = trueLongitudeSun(ahar); +    var moonLong = trueLongitudeMoon(ahar); +    var tithiVal = getTithi(sunLong, moonLong); +    var tithiNum = Math.floor(tithiVal) + 1; +    var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; +    var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; +    var tithiName = resolveTithiName(tithiDay, paksha); + +    var karanaIdx = Math.floor(2 * tithiVal); +    var karanaName = karanaIdx > 0 +        ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) +        : karanas[0]; + +    var bsInfoCalc = fromGregorianAstronomical( +        date.getUTCFullYear(), +        date.getUTCMonth() + 1, +        date.getUTCDate() +    ); + +    var dayDifference = 0; +    var gregFromAstronomical = fromBikramSambat( +        bsInfoCalc.year, +        bsInfoCalc.monthIndex, +        bsInfoCalc.day +    ); + +    if (gregFromAstronomical) { +        var timeDiff = date.getTime() - gregFromAstronomical.getTime(); +        dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); +    } + +    var dayDifferenceDisplay = dayDifference; +        if (Math.abs(dayDifference) > 2) {  // Show in red if difference is more than 2 days +            dayDifferenceDisplay = '' + dayDifference + ''; +        } else if (Math.abs(dayDifference) > 0) { +            dayDifferenceDisplay = '' + dayDifference + ''; +        } +    var sunriseSunset = getSunriseSunset(date, lat, lon, tz); +    var isComputed = (bsInfoData.year < Bsdata.BS_START_YEAR || bsInfoData.year > Bsdata.BS_END_YEAR); + +    var dataDrivenInfo = ""; +    if (bsInfoData && !isComputed) { +        dataDrivenInfo = "Debug Information (Data-Driven for date conversion):\n" + +                         "Data-Driven BS Date: " + toDevanagari(bsInfoData.year) + " " + bsInfoData.monthName + " " + toDevanagari(bsInfoData.day) + "\n" + +                         "(panchanga is based in computation)\n"; +    } else { +        dataDrivenInfo = "Debug Information (Astronomical Calculation - outside data range):\n" + +                         "Data-Driven BS Date: Not available (using astronomical calculation)\n"; +    } + +    var lunarMonthInfo = getLunarMonthInfo(ahar); + var lunarMonthDisplay = lunarMonthInfo.isAdhika ? "अधिक " + lunarMonthInfo.monthName + " " + paksha + " " + tithiName : lunarMonthInfo.monthName + " " + paksha + " " + tithiName; + +    var debugOutput = +    '
' +
+    dataDrivenInfo + "Consistency Check:\n" +
+    "Data-Driven BS Date: " + (bsInfoData ? (toDevanagari(bsInfoData.year) + " " + bsInfoData.monthName + " " + toDevanagari(bsInfoData.day)) : 'N/A') + "\n" +
+    "Astronomical BS Date (Computed): " + toDevanagari(bsInfoCalc.year) + " " + bsInfoCalc.monthName + " " + toDevanagari(bsInfoCalc.day) + "\n" +
+    "Day Difference: " + dayDifferenceDisplay + " " + (Math.abs(dayDifference) === 1 ? 'day' : 'days') + "\n" +
+    'lunar Month(testing): ' + lunarMonthDisplay + '\n' +
+    'Note: Positive = Astronomical date is behind;\nNegative = Astronomical date is ahead)\n' +
+    "Detailed Astronomical Calculation:\n" +
+    "gregorianDate: " + Qt.formatDateTime(date, "dddd, MMMM d, yyyy") + "\n" +
+    "bsMonthIndex(0 based index): " + bsInfoCalc.monthIndex + "\n" +
+    "weekday(UTC): " + weekdays[date.getUTCDay()] + "\n" +
+    "sunrise: " + sunriseSunset.sunrise + "\n" +
+    "sunset: " + sunriseSunset.sunset + "\n" +
+    "tithi: " + tithiName + " | index: " + tithiDay + "\n" +
+    "tithiAngle: " + (tithiVal * 12).toFixed(4) + "°\n" +
+    "paksha: " + paksha + "\n" +
+    "nakshatra: " + nakshatras[Math.floor(moonLong * 27 / 360) % 27] + " | index: " + (Math.floor(moonLong * 27 / 360) % 27 + 1) + "\n" +
+    "yoga: " + yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27] + " | index: " + (Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1) + "\n" +
+    "yogaAngle: " + zero360(sunLong + moonLong).toFixed(4) + "°\n" +
+    "karana: " + karanaName + " | index: " + karanaIdx + "\n" +
+    "karanaAngle: " + (2 * tithiVal).toFixed(4) + "\n" +
+    "sunRashi: " + rashis[Math.floor(sunLong / 30) % 12] + " | index: " + (Math.floor(sunLong / 30) % 12 + 1) + "\n" +
+    "moonRashi: " + rashis[Math.floor(moonLong / 30) % 12] + " | index: " + (Math.floor(moonLong / 30) % 12 + 1) + "\n" +
+    "adhikaMasa: " + calculateAdhikaMasa(ahar) + "(approximation)\n" +
+    "isComputed: " + isComputed +
+    '
'; + +    var result = { debug: debugOutput.trim().replace(/^\s*[\r\n]/gm, "") }; +    calculationCache[cacheKey] = result; +    return result; +} +// --- END: Restored Debug Function and Dependencies --- From 5fa3f33d26dd02c15f7d43ca14c7cba4fb2abb2c Mon Sep 17 00:00:00 2001 From: khumnath Date: Thu, 14 Aug 2025 18:51:11 +0545 Subject: [PATCH 5/8] added back fallback calculation with lunar month logic change. --- resources/PanchangaCalculator.js | 458 +++++++++++++++++-------------- 1 file changed, 256 insertions(+), 202 deletions(-) diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index ab0415c..9b77b01 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -1,5 +1,3 @@ -// PanchangaCalculator.js - /** * Bikram Calculator - Hindu Astrological Calendar with panchanga * Copyright (C) 2025 Khumnath Cg @@ -11,11 +9,11 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program.  If not, see . */ .pragma library @@ -29,57 +27,51 @@ function clearCache() { calculationCache = {}; } -// Surya Siddhanta Constants ( all not used ) +// Surya Siddhanta Constants var YugaRotation = { - 'star': 1582237828, - 'sun': 4320000, - 'moon': 57753336, - 'mercury': 17937060, - 'venus': 7022376, - 'mars': 2296832, - 'jupiter': 364220, - 'saturn': 146568, - 'Candrocca': 488203, + 'star': 1582237828, 'sun': 4320000, 'moon': 57753336, + 'mercury': 17937060, 'venus': 7022376, 'mars': 2296832, + 'jupiter': 364220, 'saturn': 146568, 'Candrocca': 488203, 'Rahu': -232238 }; var YugaCivilDays = 1577917828; // YugaRotation.star - YugaRotation.sun var KaliEpoch = 588465.5; var PlanetApogee = { 'sun': 77 + 17 / 60 }; var PlanetCircumm = { 'sun': 13 + 50 / 60, 'moon': 31 + 50 / 60 }; -var rad = 57.2957795; // 180 / pi +var rad = 180 / Math.PI; // Panchanga Names var tithiNamesList = [ - "प्रतिपदा", "द्वितीया", "तृतीया", "चतुर्थी", "पञ्चमी", "षष्ठी", "सप्तमी", "अष्टमी", "नवमी", "दशमी", - "एकादशी", "द्वादशी", "त्रयोदशी", "चतुर्दशी", "पूर्णिमा", "अमावस्या" -]; + "प्रतिपदा", "द्वितीया", "तृतीया", "चतुर्थी", "पञ्चमी", "षष्ठी", "सप्तमी", "अष्टमी", "नवमी", "दशमी", + "एकादशी", "द्वादशी", "त्रयोदशी", "चतुर्दशी", "पूर्णिमा", "अमावस्या" + ]; var nakshatras = [ - "अश्विनी", "भरणी", "कृत्तिका", "रोहिणी", "मृगशिरा", "आर्द्रा", "पुनर्वसु", "पुष्य", "अश्लेषा", - "मघा", "पूर्व फाल्गुनी", "उत्तर फाल्गुनी", "हस्त", "चित्रा", "स्वाती", "विशाखा", "अनुराधा", - "ज्येष्ठा", "मूल", "पूर्वाषाढा", "उत्तराषाढा", "श्रवण", "धनिष्ठा", "शतभिषा", "पूर्व भाद्रपद", - "उत्तर भाद्रपद", "रेवती" -]; + "अश्विनी", "भरणी", "कृत्तिका", "रोहिणी", "मृगशिरा", "आर्द्रा", "पुनर्वसु", "पुष्य", "अश्लेषा", + "मघा", "पूर्व फाल्गुनी", "उत्तर फाल्गुनी", "हस्त", "चित्रा", "स्वाती", "विशाखा", "अनुराधा", + "ज्येष्ठा", "मूल", "पूर्वाषाढा", "उत्तराषाढा", "श्रवण", "धनिष्ठा", "शतभिषा", "पूर्व भाद्रपद", + "उत्तर भाद्रपद", "रेवती" + ]; var yogas = [ - "विष्कम्भ", "प्रीति", "आयुष्मान्", "सौभाग्य", "शोभन", "अतिगण्ड", "सुकर्म", "धृति", "शूल", "गण्ड", - "वृद्धि", "ध्रुव", "व्याघात", "हर्षण", "वज्र", "सिद्धि", "व्यतिपात", "वरीयान्", "परिघ", "शिव", - "सिद्ध", "साध्य", "शुभ", "शुक्ल", "ब्रह्म", "इन्द्र", "वैधृति" -]; + "विष्कम्भ", "प्रीति", "आयुष्मान्", "सौभाग्य", "शोभन", "अतिगण्ड", "सुकर्म", "धृति", "शूल", "गण्ड", + "वृद्धि", "ध्रुव", "व्याघात", "हर्षण", "वज्र", "सिद्धि", "व्यतिपात", "वरीयान्", "परिघ", "शिव", + "सिद्ध", "साध्य", "शुभ", "शुक्ल", "ब्रह्म", "इन्द्र", "वैधृति" + ]; var karanas = [ - "किंस्तुघ्न", "बव", "बालव", "कौलव", "तैतिल", "गर", "वणिज", "विष्टि", "शकुनि", "चतुष्पाद", "नाग" -]; + "किंस्तुघ्न", "बव", "बालव", "कौलव", "तैतिल", "गर", "वणिज", "विष्टि", "शकुनि", "चतुष्पाद", "नाग" + ]; var rashis = [ - "मेष", "वृषभ", "मिथुन", "कर्क", "सिंह", "कन्या", - "तुला", "वृश्चिक", "धनु", "मकर", "कुम्भ", "मीन" -]; + "मेष", "वृषभ", "मिथुन", "कर्क", "सिंह", "कन्या", + "तुला", "वृश्चिक", "धनु", "मकर", "कुम्भ", "मीन" + ]; var solarMonths = [ - "वैशाख", "ज्येष्ठ", "आषाढ", "श्रावण", "भाद्रपद", "आश्विन", - "कार्तिक", "मार्गशीर्ष", "पौष", "माघ", "फाल्गुन", "चैत्र" -]; + "वैशाख", "ज्येष्ठ", "आषाढ", "श्रावण", "भाद्रपद", "आश्विन", + "कार्तिक", "मार्गशीर्ष", "पौष", "माघ", "फाल्गुन", "चैत्र" + ]; var weekdays = ["आइतबार", "सोमबार", "मङ्गलबार", "बुधबार", "बिहीबार", "शुक्रबार", "शनिबार"]; var nepaliGregorianMonths = [ - "जनवरी", "फेब्रुअरी", "मार्च", "अप्रिल", "मे", "जून", - "जुलाई", "अगस्ट", "सेप्टेम्बर", "अक्टोबर", "नोभेम्बर", "डिसेम्बर" -]; + "जनवरी", "फेब्रुअरी", "मार्च", "अप्रिल", "मे", "जून", + "जुलाई", "अगस्ट", "सेप्टेम्बर", "अक्टोबर", "नोभेम्बर", "डिसेम्बर" + ]; // Helper Functions @@ -97,22 +89,16 @@ function toDevanagari(num) { } function formatMonthDay(month, day) { - return `${(month < 10 ? '0' : '')}${month}/${(day < 10 ? '0' : '')}${day}`; + return (month < 10 ? '0' : '') + month + '/' + (day < 10 ? '0' : '') + day; } function toJulianDay(year, month, day) { - // In QML, month is 0-indexed, so we add 1 for calculations var m = month + 1; var y = year; - if (m <= 2) { - y--; - m += 12; - } + if (m <= 2) { y--; m += 12; } var a = Math.floor(y / 100); var b = 2 - a + Math.floor(a / 4); - return Math.floor(365.25 * (y + 4716)) + - Math.floor(30.6001 * (m + 1)) + - day + b - 1524.5; + return Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + day + b - 1524.5; } function fromJulianDay(jd) { @@ -181,20 +167,22 @@ function findNewMoon(ahar) { return (lo + hi) / 2; } -function getLunarMonthInfo(ahar) { - var lunarMonthStartAhar = findNewMoon(ahar); - if (lunarMonthStartAhar > ahar) { - lunarMonthStartAhar = findNewMoon(lunarMonthStartAhar - 29.53); +function findPurnima(ahar) { + var getElongation = function(a) { return zero360(trueLongitudeMoon(a) - trueLongitudeSun(a)); }; + var guess = ahar; + for (var i = 0; i < 10; i++) { + var elong = getElongation(guess); + if (Math.abs(elong - 180) < 5) break; + var correction = (180 - elong) / 12.19; + guess += correction; } - var lunarMonthEndAhar = findNewMoon(lunarMonthStartAhar + 29.53); - var sunLongStart = trueLongitudeSun(lunarMonthStartAhar); - var sunLongEnd = trueLongitudeSun(lunarMonthEndAhar); - var startSign = Math.floor(sunLongStart / 30); - var endSign = Math.floor(sunLongEnd / 30); - var isAdhika = (startSign === endSign); - var newMoonRashiIndex = Math.floor(sunLongStart / 30); - var monthName = solarMonths[newMoonRashiIndex]; - return { monthName: monthName, isAdhika: isAdhika }; + var lo = guess - 2, hi = guess + 2; + for (var j = 0; j < 30; j++) { + var mid = (lo + hi) / 2; + var em = getElongation(mid); + if (em < 180) { lo = mid; } else { hi = mid; } + } + return (lo + hi) / 2; } function getSunriseSunset(date, lat, lon, tz) { @@ -233,15 +221,30 @@ function fromBikramSambat(bsYear, monthIndex, day) { daysOffset += totalDaysInYear; } var targetYearData = Bsdata.NP_MONTHS_DATA[bsYear - Bsdata.BS_START_YEAR]; - for (var m = 0; m < monthIndex; m++) { + for (let m = 0; m < monthIndex; m++) { daysOffset += targetYearData[m]; } daysOffset += (day - 1); var resultDate = new Date(Bsdata.BS_START_DATE_AD.getTime()); resultDate.setUTCDate(resultDate.getUTCDate() + daysOffset); return resultDate; + } else { + // Fallback for out-of-range years + var YearSaka = bsYear - 135; + var YearKali = YearSaka + 3179; + var ahar = Math.floor((YearKali * YugaCivilDays) / YugaRotation.sun); + var currentDay = getSauraMasaDay(ahar); + while (currentDay.m !== monthIndex || currentDay.d !== day) { + if (currentDay.m < monthIndex || (currentDay.m === monthIndex && currentDay.d < day)) { + ahar += 1; + } else { + ahar -= 1; + } + currentDay = getSauraMasaDay(ahar); + } + var julian_date = ahar + KaliEpoch; + return fromJulianDay(julian_date); } - return null; } function getBikramMonthInfo(bsYear, monthIndex) { @@ -255,14 +258,34 @@ function getBikramMonthInfo(bsYear, monthIndex) { monthName: solarMonths[monthIndex], year: bsYear }; + } else { + // Fallback for out-of-range years + var first = fromBikramSambat(bsYear, monthIndex, 1); + var nextMon = monthIndex === 11 ? 0 : monthIndex + 1; + var nextYear = monthIndex === 11 ? bsYear + 1 : bsYear; + var nextFirst = fromBikramSambat(nextYear, nextMon, 1); + var jd1 = toJulianDay(first.getUTCFullYear(), first.getUTCMonth(), first.getUTCDate()); + var jd2 = toJulianDay(nextFirst.getUTCFullYear(), nextFirst.getUTCMonth(), nextFirst.getUTCDate()); + return { + totalDays: Math.round(jd2 - jd1), + startDayOfWeek: first.getUTCDay(), + monthName: solarMonths[monthIndex], + year: bsYear + }; } - return null; } function toBikramSambat(gregorianDate) { - var targetUtcDate = new Date(Date.UTC(gregorianDate.getFullYear(), gregorianDate.getMonth(), gregorianDate.getDate())); - var startDate = new Date(Date.UTC(Bsdata.BS_START_DATE_AD.getFullYear(), Bsdata.BS_START_DATE_AD.getMonth(), Bsdata.BS_START_DATE_AD.getDate())); - if (targetUtcDate >= startDate && Bsdata.NP_MONTHS_DATA) { + var isDataAvailable = false; + if (Bsdata && Bsdata.BS_START_DATE_AD) { + var targetUtcDate = new Date(Date.UTC(gregorianDate.getFullYear(), gregorianDate.getMonth(), gregorianDate.getDate())); + var startDate = new Date(Date.UTC(Bsdata.BS_START_DATE_AD.getFullYear(), Bsdata.BS_START_DATE_AD.getMonth(), Bsdata.BS_START_DATE_AD.getDate())); + if (targetUtcDate >= startDate && gregorianDate.getFullYear() <= (Bsdata.BS_END_YEAR - 56)) { + isDataAvailable = true; + } + } + + if (isDataAvailable) { var daysOffset = Math.floor((targetUtcDate.getTime() - startDate.getTime()) / 86400000); for (var y = 0; y < Bsdata.NP_MONTHS_DATA.length; y++) { var currentBsYear = Bsdata.BS_START_YEAR + y; @@ -273,7 +296,7 @@ function toBikramSambat(gregorianDate) { for (var m = 0; m < 12; m++) { var daysInMonth = yearData[m]; if (daysOffset < daysInMonth) { - return { year: currentBsYear, monthIndex: m, day: daysOffset + 1, monthName: solarMonths[m] }; + return { year: currentBsYear, monthIndex: m, day: daysOffset + 1, monthName: solarMonths[m], isComputed: false }; } daysOffset -= daysInMonth; } @@ -281,7 +304,14 @@ function toBikramSambat(gregorianDate) { daysOffset -= daysInYear; } } - return null; + // Fallback to astronomical calculation + var result = fromGregorianAstronomical( + gregorianDate.getUTCFullYear(), + gregorianDate.getUTCMonth() + 1, + gregorianDate.getUTCDate() + ); + result.isComputed = true; + return result; } function resolveTithiName(tithiDay, paksha) { @@ -292,7 +322,7 @@ function resolveTithiName(tithiDay, paksha) { function _getPanchangaBasics(date) { var jd = toJulianDay(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); - var ahar = jd - KaliEpoch + 0.25 + ((85.3240 / 15 - 5.75) / 24); // Standard location for consistency + var ahar = jd - KaliEpoch + 0.25 + ((85.3240 / 15 - 5.75) / 24); var sunLong = trueLongitudeSun(ahar); var moonLong = trueLongitudeMoon(ahar); var tithiVal = getTithi(sunLong, moonLong); @@ -300,9 +330,11 @@ function _getPanchangaBasics(date) { var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; var tithiName = resolveTithiName(tithiDay, paksha); - var lunarMonthInfo = getLunarMonthInfo(ahar); + var lunarMonthInfo = getLunarMonthNameWithAdhik(ahar); return { + ahar: ahar, lunarMonthName: lunarMonthInfo.monthName, + isAdhika: lunarMonthInfo.isAdhika, paksha: paksha, tithiName: tithiName, tithiDay: tithiDay @@ -326,7 +358,7 @@ function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { } if (EventsData.bikramRecurringEvents) { for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { - var event = EventsData.bikramRecurringEvents[j]; + let event = EventsData.bikramRecurringEvents[j]; if (event.date === formattedBikramRecurringDate) { events.push({ name: event.event, detail: event.detail, category: event.category }); } @@ -335,38 +367,37 @@ function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { if (EventsData.lunarEvents) { var todayInfo = _getPanchangaBasics(date); + if (todayInfo.isAdhika) { + return events; + } + var yesterday = new Date(date.getTime() - 86400000); var yesterdayInfo = _getPanchangaBasics(yesterday); - var tithiDayMap = {}; - tithiNamesList.forEach(function(name, index) { - if (name === "पूर्णिमा" || name === "अमावस्या") { - tithiDayMap[name] = 15; - } else { - tithiDayMap[name] = index + 1; - } - }); + var prevLunarMonthAhar = todayInfo.ahar - 29.53; + var prevLunarMonthAdhikaKshaya = calculateAdhikaMasa(prevLunarMonthAhar); + var kshayaMonthName = null; + if (prevLunarMonthAdhikaKshaya.startsWith("क्षय")) { + kshayaMonthName = prevLunarMonthAdhikaKshaya.split(" ")[1]; + } for (var k = 0; k < EventsData.lunarEvents.length; k++) { var lunarEvent = EventsData.lunarEvents[k]; - var eventTithiDay = tithiDayMap[lunarEvent.tithi]; - if (!eventTithiDay) continue; + var isEventForToday = (lunarEvent.lunarMonth === todayInfo.lunarMonthName && + lunarEvent.paksha === todayInfo.paksha && + lunarEvent.tithi === todayInfo.tithiName); - var eventStartedToday = false; - if (todayInfo.lunarMonthName === yesterdayInfo.lunarMonthName && todayInfo.paksha === yesterdayInfo.paksha) { - if (eventTithiDay > yesterdayInfo.tithiDay && eventTithiDay <= todayInfo.tithiDay) { - eventStartedToday = true; - } - } else { - if (lunarEvent.lunarMonth === todayInfo.lunarMonthName && - lunarEvent.paksha === todayInfo.paksha && - eventTithiDay <= todayInfo.tithiDay) { - eventStartedToday = true; - } - } + var isEventFromKshayaMonth = (kshayaMonthName !== null && + lunarEvent.lunarMonth === kshayaMonthName && + lunarEvent.paksha === todayInfo.paksha && + lunarEvent.tithi === todayInfo.tithiName); + + if (isEventForToday || isEventFromKshayaMonth) { + var isFirstDayOfTithi = !(yesterdayInfo.lunarMonthName === todayInfo.lunarMonthName && + yesterdayInfo.paksha === todayInfo.paksha && + yesterdayInfo.tithiName === todayInfo.tithiName); - if (eventStartedToday) { - if (lunarEvent.lunarMonth === todayInfo.lunarMonthName && lunarEvent.paksha === todayInfo.paksha) { + if (isFirstDayOfTithi) { events.push({ name: lunarEvent.event, detail: lunarEvent.detail, category: lunarEvent.category }); } } @@ -375,6 +406,7 @@ function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { return events; } +// Main calculations function calculate(date, lat, lon, tz) { var cacheKey = "panchanga_" + date.getTime(); if (calculationCache[cacheKey]) return calculationCache[cacheKey]; @@ -391,11 +423,11 @@ function calculate(date, lat, lon, tz) { var karanaName = karanaIdx > 0 ? (karanaIdx < 57 ? karanas[(karanaIdx-1) % 7 + 1] : karanas[karanaIdx - 57 + 8]) : karanas[0]; var bsInfo = toBikramSambat(date); if (!bsInfo) return { error: "Date out of range" }; - var lunarMonthInfo = getLunarMonthInfo(ahar); + var lunarMonthInfo = getLunarMonthNameWithAdhik(ahar); var events = getEventsForDate(date, bsInfo.year, bsInfo.monthIndex, bsInfo.day); var lunarMonthDisplayName = lunarMonthInfo.isAdhika ? "अधिक " + lunarMonthInfo.monthName : lunarMonthInfo.monthName; var sunriseSunset = getSunriseSunset(date, lat, lon, tz); - var isComputed = (bsInfo.year < Bsdata.BS_START_YEAR || bsInfo.year > Bsdata.BS_END_YEAR); + var isComputed = bsInfo.isComputed; var adhikaMasa = calculateAdhikaMasa(ahar); var result = { @@ -423,7 +455,6 @@ function calculate(date, lat, lon, tz) { return result; } -// --- START: Restored Debug Function and Dependencies --- function getTslong(ahar) { var t1 = (YugaRotation.sun * ahar / YugaCivilDays); t1 -= Math.floor(t1); @@ -526,7 +557,7 @@ function getLunarMonthNameWithAdhik(ahar) { if (lunarMonthStart > ahar) { lunarMonthStart = findNewMoon(lunarMonthStart - 29.53); } - var purnima = findNewMoon(lunarMonthStart + 14.77); + var purnima = findPurnima(lunarMonthStart + 14.77); var sunLongPurnima = trueLongitudeSun(purnima); var purnimaSign = Math.floor(sunLongPurnima / 30); var signCrossings = 0; @@ -553,107 +584,130 @@ function getLunarMonthNameWithAdhik(ahar) { // Debug calculations function generateDebugInfo(date, lat, lon, tz) { -    lat = lat || 27.7172; -    lon = lon || 85.3240; -    tz = tz || 5.75; -    var cacheKey = "debug_" + date.getTime(); -    if (calculationCache[cacheKey]) return calculationCache[cacheKey]; -    var bsInfoData = toBikramSambat(date, lon, tz); - -    if (!bsInfoData) { -        return { debug: "Date out of pre-calculated range." }; -    } - -    var jd = toJulianDay( -        date.getUTCFullYear(), -        date.getUTCMonth(), -        date.getUTCDate() -    ); -    var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); - -    var sunLong = trueLongitudeSun(ahar); -    var moonLong = trueLongitudeMoon(ahar); -    var tithiVal = getTithi(sunLong, moonLong); -    var tithiNum = Math.floor(tithiVal) + 1; -    var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; -    var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; -    var tithiName = resolveTithiName(tithiDay, paksha); - -    var karanaIdx = Math.floor(2 * tithiVal); -    var karanaName = karanaIdx > 0 -        ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) -        : karanas[0]; - -    var bsInfoCalc = fromGregorianAstronomical( -        date.getUTCFullYear(), -        date.getUTCMonth() + 1, -        date.getUTCDate() -    ); - -    var dayDifference = 0; -    var gregFromAstronomical = fromBikramSambat( -        bsInfoCalc.year, -        bsInfoCalc.monthIndex, -        bsInfoCalc.day -    ); - -    if (gregFromAstronomical) { -        var timeDiff = date.getTime() - gregFromAstronomical.getTime(); -        dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); -    } - -    var dayDifferenceDisplay = dayDifference; -        if (Math.abs(dayDifference) > 2) {  // Show in red if difference is more than 2 days -            dayDifferenceDisplay = '' + dayDifference + ''; -        } else if (Math.abs(dayDifference) > 0) { -            dayDifferenceDisplay = '' + dayDifference + ''; -        } -    var sunriseSunset = getSunriseSunset(date, lat, lon, tz); -    var isComputed = (bsInfoData.year < Bsdata.BS_START_YEAR || bsInfoData.year > Bsdata.BS_END_YEAR); - -    var dataDrivenInfo = ""; -    if (bsInfoData && !isComputed) { -        dataDrivenInfo = "Debug Information (Data-Driven for date conversion):\n" + -                         "Data-Driven BS Date: " + toDevanagari(bsInfoData.year) + " " + bsInfoData.monthName + " " + toDevanagari(bsInfoData.day) + "\n" + -                         "(panchanga is based in computation)\n"; -    } else { -        dataDrivenInfo = "Debug Information (Astronomical Calculation - outside data range):\n" + -                         "Data-Driven BS Date: Not available (using astronomical calculation)\n"; -    } - -    var lunarMonthInfo = getLunarMonthInfo(ahar); - var lunarMonthDisplay = lunarMonthInfo.isAdhika ? "अधिक " + lunarMonthInfo.monthName + " " + paksha + " " + tithiName : lunarMonthInfo.monthName + " " + paksha + " " + tithiName; - -    var debugOutput = -    '
' +
-    dataDrivenInfo + "Consistency Check:\n" +
-    "Data-Driven BS Date: " + (bsInfoData ? (toDevanagari(bsInfoData.year) + " " + bsInfoData.monthName + " " + toDevanagari(bsInfoData.day)) : 'N/A') + "\n" +
-    "Astronomical BS Date (Computed): " + toDevanagari(bsInfoCalc.year) + " " + bsInfoCalc.monthName + " " + toDevanagari(bsInfoCalc.day) + "\n" +
-    "Day Difference: " + dayDifferenceDisplay + " " + (Math.abs(dayDifference) === 1 ? 'day' : 'days') + "\n" +
-    'lunar Month(testing): ' + lunarMonthDisplay + '\n' +
-    'Note: Positive = Astronomical date is behind;\nNegative = Astronomical date is ahead)\n' +
-    "Detailed Astronomical Calculation:\n" +
-    "gregorianDate: " + Qt.formatDateTime(date, "dddd, MMMM d, yyyy") + "\n" +
-    "bsMonthIndex(0 based index): " + bsInfoCalc.monthIndex + "\n" +
-    "weekday(UTC): " + weekdays[date.getUTCDay()] + "\n" +
-    "sunrise: " + sunriseSunset.sunrise + "\n" +
-    "sunset: " + sunriseSunset.sunset + "\n" +
-    "tithi: " + tithiName + " | index: " + tithiDay + "\n" +
-    "tithiAngle: " + (tithiVal * 12).toFixed(4) + "°\n" +
-    "paksha: " + paksha + "\n" +
-    "nakshatra: " + nakshatras[Math.floor(moonLong * 27 / 360) % 27] + " | index: " + (Math.floor(moonLong * 27 / 360) % 27 + 1) + "\n" +
-    "yoga: " + yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27] + " | index: " + (Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1) + "\n" +
-    "yogaAngle: " + zero360(sunLong + moonLong).toFixed(4) + "°\n" +
-    "karana: " + karanaName + " | index: " + karanaIdx + "\n" +
-    "karanaAngle: " + (2 * tithiVal).toFixed(4) + "\n" +
-    "sunRashi: " + rashis[Math.floor(sunLong / 30) % 12] + " | index: " + (Math.floor(sunLong / 30) % 12 + 1) + "\n" +
-    "moonRashi: " + rashis[Math.floor(moonLong / 30) % 12] + " | index: " + (Math.floor(moonLong / 30) % 12 + 1) + "\n" +
-    "adhikaMasa: " + calculateAdhikaMasa(ahar) + "(approximation)\n" +
-    "isComputed: " + isComputed +
-    '
'; - -    var result = { debug: debugOutput.trim().replace(/^\s*[\r\n]/gm, "") }; -    calculationCache[cacheKey] = result; -    return result; + lat = lat || 27.7172; + lon = lon || 85.3240; + tz = tz || 5.75; + var cacheKey = "debug_" + date.getTime(); + if (calculationCache[cacheKey]) return calculationCache[cacheKey]; + var bsInfoData = toBikramSambat(date, lon, tz); + + if (!bsInfoData) { + return { debug: "Date out of pre-calculated range." }; + } + + var jd = toJulianDay( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate() + ); + var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); + + var sunLong = trueLongitudeSun(ahar); + var moonLong = trueLongitudeMoon(ahar); + var tithiVal = getTithi(sunLong, moonLong); + var tithiNum = Math.floor(tithiVal) + 1; + var paksha = tithiNum <= 15 ? "शुक्ल पक्ष" : "कृष्ण पक्ष"; + var tithiDay = tithiNum > 15 ? tithiNum - 15 : tithiNum; + var tithiName = resolveTithiName(tithiDay, paksha); + + var karanaIdx = Math.floor(2 * tithiVal); + var karanaName = karanaIdx > 0 + ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) + : karanas[0]; + + var bsInfoCalc = fromGregorianAstronomical( + date.getUTCFullYear(), + date.getUTCMonth() + 1, + date.getUTCDate() + ); + + var dayDifference = 0; + var gregFromAstronomical = fromBikramSambat( + bsInfoCalc.year, + bsInfoCalc.monthIndex, + bsInfoCalc.day + ); + + if (gregFromAstronomical) { + var timeDiff = date.getTime() - gregFromAstronomical.getTime(); + dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); + } + + var dayDifferenceDisplay = dayDifference; + if (Math.abs(dayDifference) > 2) {  // Show in red if difference is more than 2 days + dayDifferenceDisplay = '' + dayDifference + ''; + } else if (Math.abs(dayDifference) > 0) { + dayDifferenceDisplay = '' + dayDifference + ''; + } + var sunriseSunset = getSunriseSunset(date, lat, lon, tz); + var isComputed = bsInfoData.isComputed; + var computedbsdate = toDevanagari(bsInfoCalc.year) + " " + bsInfoCalc.monthName + " " + toDevanagari(bsInfoCalc.day); + + var dataDrivenBsDateString = "N/A"; + var acceptedBsDate = computedbsdate; // fallback by default + var dataDrivenInfo = ""; + + if (bsInfoData && !isComputed) { + dataDrivenBsDateString = toDevanagari(bsInfoData.year) + " " + bsInfoData.monthName + " " + toDevanagari(bsInfoData.day); + acceptedBsDate = dataDrivenBsDateString; + dataDrivenInfo = + `Debug Information\n` + + `(Data-Driven for date conversion):\n` + + "Gregorian Date: " + date + "\n" + + "accepted BS Date: " + acceptedBsDate + "\n" + + "(panchanga is based on data-driven conversion)\n"; + } else { + dataDrivenInfo = + `Debug Information\n` + + `(Astronomical Calculation - outside data range):\n` + + "Gregorian Date: " + date + "\n" + + "accepted BS Date: " + acceptedBsDate + "\n" + + "(panchanga is based on astronomical computation)\n"; + } + + + + var lunarMonthInfo = getLunarMonthNameWithAdhik(ahar); + var lunarMonthDisplay = lunarMonthInfo.isAdhika ? "अधिक " + lunarMonthInfo.monthName + " " + paksha : lunarMonthInfo.monthName + " " + paksha; + + var debugOutput = + '
' +
+            dataDrivenInfo +
+            `Consistency Check:\n` +
+            "Data-Driven BS Date: " + dataDrivenBsDateString + "\n" +
+            "Astronomical BS Date (Computed): " + computedbsdate + "\n" +
+            "Day Difference: " + dayDifferenceDisplay + " " + (Math.abs(dayDifference) === 1 ? 'day' : 'days') + "\n" +
+            `Note: Positive = Astronomical date is behind;\n` +
+            `Negative = Astronomical date is ahead\n` +
+
+            " " +`Lunar Month (Purnimanta): ` + lunarMonthDisplay + "\n" +
+
+            `--- Solar Outputs ---\n` +
+            "gregorianDate: " + Qt.formatDateTime(date, "dddd, MMMM d, yyyy") + "\n" +
+            "sunrise: " + sunriseSunset.sunrise + "\n" +
+            "sunset: " + sunriseSunset.sunset + "\n" +
+            "sunRashi: " + rashis[Math.floor(sunLong / 30) % 12] + " | index: " + (Math.floor(sunLong / 30) % 12 + 1) + "\n" +
+
+            " " +`--- Lunar Outputs ---\n` +
+            "tithi: " + tithiName + " | index: " + tithiDay + "\n" +
+            "tithiAngle: " + (tithiVal * 12).toFixed(4) + "°\n" +
+            "paksha: " + paksha + "\n" +
+            "nakshatra: " + nakshatras[Math.floor(moonLong * 27 / 360) % 27] + " | index: " + (Math.floor(moonLong * 27 / 360) % 27 + 1) + "\n" +
+            "yoga: " + yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27] + " | index: " + (Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1) + "\n" +
+            "yogaAngle: " + zero360(sunLong + moonLong).toFixed(4) + "°\n" +
+            "karana: " + karanaName + " | index: " + karanaIdx + "\n" +
+            "karanaAngle: " + (2 * tithiVal).toFixed(4) + "\n" +
+            "moonRashi: " + rashis[Math.floor(moonLong / 30) % 12] + " | index: " + (Math.floor(moonLong / 30) % 12 + 1) + "\n" +
+            "adhikaMasa: " + calculateAdhikaMasa(ahar) + " (computed)\n" +
+
+            " " + `--- Metadata ---\n` +
+            "bsMonthIndex (0-based): " + bsInfoCalc.monthIndex + "\n" +
+            "weekday (UTC): " + weekdays[date.getUTCDay()] + "\n" +
+            "isComputed: " + isComputed +
+            '
'; + + + var result = { debug: debugOutput.trim().replace(/^\s*[\r\n]/gm, "") }; + calculationCache[cacheKey] = result; + return result; } -// --- END: Restored Debug Function and Dependencies --- From 2a53ce48777fa076abe53b21b068a315b2669304 Mon Sep 17 00:00:00 2001 From: khumnath Date: Fri, 15 Aug 2025 07:43:09 +0545 Subject: [PATCH 6/8] added back bikram fixed events parsing. handling events for holiday too. --- qml/CalendarGrid.qml | 17 +- qml/DayCell.qml | 20 ++ qml/Theme.qml | 2 + resources/EventData.js | 382 ++++++++++++++++++++----------- resources/PanchangaCalculator.js | 45 +++- 5 files changed, 321 insertions(+), 145 deletions(-) diff --git a/qml/CalendarGrid.qml b/qml/CalendarGrid.qml index 87130a3..897c6bc 100644 --- a/qml/CalendarGrid.qml +++ b/qml/CalendarGrid.qml @@ -28,7 +28,6 @@ ColumnLayout { Layout.preferredHeight: parent.width Layout.margins: 10 Layout.topMargin: 10 - //Layout.bottomMargin: 10 Repeater { id: repeater @@ -60,6 +59,18 @@ ColumnLayout { item.isSaturday = modelData.isSaturday; item.hasEvent = modelData.hasEvent; item.theme = calendarGridRoot.theme; + + var isHoliday = false; + if (modelData.panchanga && modelData.panchanga.events) { + for (var i = 0; i < modelData.panchanga.events.length; i++) { + if (modelData.panchanga.events[i].holiday) { + isHoliday = true; + break; + } + } + } + item.isHoliday = isHoliday; + item.clicked.connect(function() { calendarGridRoot.dayClicked(modelData.panchanga) }); @@ -78,7 +89,6 @@ ColumnLayout { Rectangle { id: eventFooter Layout.fillWidth: true - //Layout.topMargin: 10 implicitHeight: eventLabel.paintedHeight + 20 color: theme.secondaryBg radius: 6 @@ -91,7 +101,6 @@ ColumnLayout { property var eventModel: [] // Model reference - // Bind the text property to a function that builds the string text: { var str = ""; if (eventModel) { @@ -99,7 +108,7 @@ ColumnLayout { var item = eventModel[i]; str += item.bsDay + " :\u00A0" + item.eventName; if (i < eventModel.length - 1) { - str += " • "; + str += "  •  "; } } } diff --git a/qml/DayCell.qml b/qml/DayCell.qml index f4226b3..4ffa207 100644 --- a/qml/DayCell.qml +++ b/qml/DayCell.qml @@ -13,13 +13,17 @@ Rectangle { property bool isToday: false property bool isSaturday: false property bool hasEvent: false + property bool isHoliday: false property var theme + property var cellDate signal clicked() color: { if (!theme) return "white"; if (cellMouseArea.containsMouse) return theme.tertiaryBg; + //holiday background disabled now + //if (isHoliday) return theme.holidayBg; if (isSaturday) return theme.saturdayBg; if (isToday) return theme.todayBg; return theme.secondaryBg; @@ -29,10 +33,26 @@ Rectangle { if (!theme) return "grey"; if (isToday) return theme.todayBorder; if (isSaturday) return theme.saturdayBorder; + if (isHoliday) return theme.holidayBorder; return theme.borderColor; } border.width: isToday ? 2 : 1 + Component.onCompleted: { + if (cellDate) { + var dayInfo = Panchanga.calculate(cellDate); + if (dayInfo.events && dayInfo.events.length > 0) { + for (var i = 0; i < dayInfo.events.length; i++) { + if (dayInfo.events[i].holiday) { + isHoliday = true; + break; + } + } + } + } + } + + // Event Indicator Rectangle { id: eventIndicator diff --git a/qml/Theme.qml b/qml/Theme.qml index f480933..d53dd57 100644 --- a/qml/Theme.qml +++ b/qml/Theme.qml @@ -35,10 +35,12 @@ QtObject { readonly property color borderColor: isDark ? "#334155" : "#e2e8f0" readonly property color todayBorder: isDark ? "#0ea5e9" : "#0284c7" readonly property color saturdayBorder: isDark ? "#334155" : "#fda4af" + readonly property color holidayBorder: isDark ? "#334155" : "#fda4af" // === Highlighted Days === readonly property color todayBg: isDark ? "#082f49" : "#f0f9ff" readonly property color saturdayBg: isDark ? "#6E3233" : "#FEDDDF" + //readonly property color holidayBg: isDark ? "#6E3233" : "#FEDDDF" readonly property color adDayText: isDark ? "#BBCFFA" : "#6E9BFD" // === Modal / Dialogs === diff --git a/resources/EventData.js b/resources/EventData.js index 13e17da..9887b26 100644 --- a/resources/EventData.js +++ b/resources/EventData.js @@ -1,387 +1,476 @@ // EventsData.js -// This file contains event data for the Panchanga Calculator. +// This file contains event data for the Panchanga Calculator, organized by type. +// All events have a consistent structure including a 'holiday' boolean. .pragma library // Lunar based events, defined by month, fortnight (paksha), and lunar day (tithi). var lunarEvents = [ { + event: "चैते दशैँ", eventType: "lunar", lunarMonth: "चैत्र", paksha: "शुक्ल पक्ष", tithi: "अष्टमी", - event: "चैते दशैँ", + startYear: null, + endYear: null, detail: "चैत्र महिनामा मनाइने दशैँ, ठूलो दशैँको सानो रूप।", - category: "धार्मिक" + holiday: true }, { + event: "रामनवमी", eventType: "lunar", lunarMonth: "चैत्र", paksha: "शुक्ल पक्ष", tithi: "नवमी", - event: "रामनवमी", + startYear: null, + endYear: null, detail: "भगवान रामको जन्मदिन।", - category: "धार्मिक" + holiday: true }, { + event: "मातातीर्थ औंसी", eventType: "lunar", lunarMonth: "चैत्र", paksha: "कृष्ण पक्ष", tithi: "अमावस्या", - event: "मातातीर्थ औंसी", - detail: "आमाको मुख हेर्ने दिन।", - category: "धार्मिक" + startYear: null, + endYear: null, + detail: "आमाको मुख हेर्ने दिन。", + holiday: true }, { + event: "घोडेजात्रा", eventType: "lunar", lunarMonth: "चैत्र", paksha: "कृष्ण पक्ष", tithi: "अमावस्या", - event: "घोडेजात्रा", + startYear: null, + endYear: null, detail: "काठमाडौँमा मनाइने घोडे जात्रा उत्सव।", - category: "Jatra" + holiday: true }, { + event: "अक्षय तृतीया", eventType: "lunar", lunarMonth: "वैशाख", paksha: "शुक्ल पक्ष", tithi: "तृतीया", - event: "अक्षय तृतीया", - detail: "जौ सातु खाने दिन।", - category: "धार्मिक" + startYear: null, + endYear: null, + detail: "जौ सातु खाने दिन。", + holiday: false }, { + event: "बुद्ध जयन्ती / उभौली पर्व", eventType: "lunar", lunarMonth: "वैशाख", paksha: "शुक्ल पक्ष", tithi: "पूर्णिमा", - event: "बुद्ध जयन्ती / उभौली पर्व", + startYear: null, + endYear: null, detail: "भगवान बुद्धको जन्मदिन र किरात समुदायको उभौली पर्व।", - category: "धार्मिक" + holiday: true }, { + event: "गुरु पूर्णिमा", eventType: "lunar", lunarMonth: "आषाढ", paksha: "शुक्ल पक्ष", tithi: "पूर्णिमा", - event: "गुरु पूर्णिमा", + startYear: null, + endYear: null, detail: "गुरु र शिक्षकहरूलाई सम्मान गर्ने दिन।", - category: "धार्मिक" + holiday: false }, { + event: "नाग पञ्चमी", eventType: "lunar", lunarMonth: "श्रावण", paksha: "शुक्ल पक्ष", tithi: "पञ्चमी", - event: "नाग पञ्चमी", + startYear: null, + endYear: null, detail: "सर्प देवताको पूजा गर्ने दिन।", - category: "धार्मिक" + holiday: false }, { + event: "जनै पूर्णिमा / रक्षा बन्धन", eventType: "lunar", lunarMonth: "श्रावण", paksha: "शुक्ल पक्ष", tithi: "पूर्णिमा", - event: "जनै पूर्णिमा / रक्षा बन्धन", - detail: "जनै बदल्ने तथा रक्षा बन्धन बांध्ने पवित्र उत्सव।", - category: "धार्मिक" + startYear: null, + endYear: null, + detail: "जनै बदल्ने तथा रक्षा बन्धन बांध्ने  पवित्र उत्सव।", + holiday: true }, { + event: "कृष्ण जन्माष्टमी", eventType: "lunar", lunarMonth: "श्रावण", paksha: "कृष्ण पक्ष", tithi: "अष्टमी", - event: "कृष्ण जन्माष्टमी", + startYear: null, + endYear: null, detail: "भगवान कृष्णको जन्मदिन।", - category: "धार्मिक" + holiday: true }, { + event: "गाईजात्रा", eventType: "lunar", lunarMonth: "भाद्रपद", paksha: "कृष्ण पक्ष", tithi: "प्रतिपदा", - event: "गाईजात्रा", + startYear: null, + endYear: null, detail: "गाईको उत्सव, हास्य र व्यङ्ग्यको मेल।", - category: "Jatra" + holiday: true }, { + event: "कुशे औंसी", eventType: "lunar", lunarMonth: "भाद्रपद", paksha: "कृष्ण पक्ष", tithi: "अमावस्या", - event: "कुशे औंसी", + startYear: null, + endYear: null, detail: "बुवाको मुख हेर्ने दिन।", - category: "धार्मिक" + holiday: true }, { + event: "हरितालिका तीज", eventType: "lunar", lunarMonth: "भाद्रपद", paksha: "शुक्ल पक्ष", tithi: "तृतीया", - event: "हरितालिका तीज", + startYear: null, + endYear: null, detail: "महिलाहरूले को महान उत्सव।", - category: "धार्मिक" + holiday: true }, { + event: "गणेश चतुर्थी", eventType: "lunar", lunarMonth: "भाद्रपद", paksha: "शुक्ल पक्ष", tithi: "चतुर्थी", - event: "गणेश चतुर्थी", + startYear: null, + endYear: null, detail: "भगवान गणेशको जन्मदिन।", - category: "धार्मिक" + holiday: true }, { + event: "इन्द्रजात्रा", eventType: "lunar", lunarMonth: "भाद्रपद", paksha: "शुक्ल पक्ष", tithi: "चतुर्दशी", - event: "इन्द्रजात्रा", + startYear: null, + endYear: null, detail: "काठमाडौँको प्रमुख सडक उत्सवको मुख्य दिन।", - category: "Jatra" + holiday: true }, { + event: "घटस्थापना", eventType: "lunar", lunarMonth: "आश्विन", paksha: "शुक्ल पक्ष", tithi: "प्रतिपदा", - event: "घटस्थापना", + startYear: null, + endYear: null, detail: "दशैँको सुरुवात, नवरात्रिको पहिलो दिन।", - category: "धार्मिक" + holiday: true }, { + event: "फूलपाती", eventType: "lunar", lunarMonth: "आश्विन", paksha: "शुक्ल पक्ष", tithi: "सप्तमी", - event: "फूलपाती", + startYear: null, + endYear: null, detail: "दशैँको सातौँ दिन।", - category: "धार्मिक" + holiday: true }, { + event: "महाअष्टमी", eventType: "lunar", lunarMonth: "आश्विन", paksha: "शुक्ल पक्ष", tithi: "अष्टमी", - event: "महाअष्टमी", + startYear: null, + endYear: null, detail: "दशैँको आठौँ दिन।", - category: "धार्मिक" + holiday: true }, { + event: "महानवमी", eventType: "lunar", lunarMonth: "आश्विन", paksha: "शुक्ल पक्ष", tithi: "नवमी", - event: "महानवमी", + startYear: null, + endYear: null, detail: "दशैँको नवौं दिन।", - category: "धार्मिक" + holiday: true }, { + event: "विजयादशमी (दशैं)", eventType: "lunar", lunarMonth: "आश्विन", paksha: "शुक्ल पक्ष", tithi: "दशमी", - event: "विजयादशमी (दशैं)", + startYear: null, + endYear: null, detail: "दशैँको दशौँ दिन, विजयको दिन।", - category: "धार्मिक" + holiday: true }, { + event: "कोजाग्रत पूर्णिमा", eventType: "lunar", lunarMonth: "आश्विन", paksha: "शुक्ल पक्ष", tithi: "पूर्णिमा", - event: "कोजाग्रत पूर्णिमा", + startYear: null, + endYear: null, detail: "दशैँको अन्त्य।", - category: "धार्मिक" + holiday: true }, { + event: "काग तिहार", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "कृष्ण पक्ष", tithi: "त्रयोदशी", - event: "काग तिहार", + startYear: null, + endYear: null, detail: "तिहारको पहिलो दिन, कागलाई समर्पित।", - category: "धार्मिक" + holiday: true }, { + event: "कुकुर तिहार", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "कृष्ण पक्ष", tithi: "चतुर्दशी", - event: "कुकुर तिहार", + startYear: null, + endYear: null, detail: "तिहारको दोस्रो दिन, कुकुरलाई समर्पित।", - category: "धार्मिक" + holiday: true }, { + event: "लक्ष्मी पूजा", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "कृष्ण पक्ष", tithi: "अमावस्या", - event: "लक्ष्मी पूजा", + startYear: null, + endYear: null, detail: "तिहारको तेस्रो दिन, देवी लक्ष्मीको पूजा।", - category: "धार्मिक" + holiday: true }, { + event: "गोवर्धन पूजा / म्ह पूजा", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "शुक्ल पक्ष", tithi: "प्रतिपदा", - event: "गोवर्धन पूजा / म्ह पूजा", - detail: "तिहारको चौथो दिन, आत्म-पूजाको दिन।", - category: "धार्मिक" + startYear: null, + endYear: null, + detail: "तिहारको चौथो दिन,  आत्म-पूजाको दिन।", + holiday: true }, { + event: "भाइटीका", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "शुक्ल पक्ष", tithi: "द्वितीया", - event: "भाइटीका", + startYear: null, + endYear: null, detail: "तिहारको पाँचौँ दिन, दिदी-भाइबीचको प्रेमको दिन।", - category: "धार्मिक" + holiday: true }, { + event: "छठ पर्व", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "शुक्ल पक्ष", tithi: "षष्ठी", - event: "छठ पर्व", + startYear: null, + endYear: null, detail: "सूर्य देवतालाई समर्पित उत्सव, मुख्यतया तराईमा मनाइन्छ।", - category: "धार्मिक" + holiday: true }, { + event: "हरिबोधिनी एकादशी", eventType: "lunar", lunarMonth: "कार्तिक", paksha: "शुक्ल पक्ष", tithi: "एकादशी", - event: "हरिबोधिनी एकादशी", + startYear: null, + endYear: null, detail: "भगवान विष्णुको जागरणको दिन।", - category: "धार्मिक" + holiday: false }, { + event: "विवाह पञ्चमी", eventType: "lunar", lunarMonth: "मार्गशीर्ष", paksha: "शुक्ल पक्ष", tithi: "पञ्चमी", - event: "विवाह पञ्चमी", + startYear: null, + endYear: null, detail: "भगवान राम र सीताको विवाहको सम्झना।", - category: "धार्मिक" + holiday: true }, { + event: "य:मरि पुन्हि / धान्यपुर्णिमा", eventType: "lunar", lunarMonth: "मार्गशीर्ष", paksha: "शुक्ल पक्ष", tithi: "पूर्णिमा", - event: "य:मरि पुन्हि / धान्यपुर्णिमा", + startYear: null, + endYear: null, detail: "नेवार समुदायको यमरि पुन्हि / धान्य पूर्णिमाको उत्सव।", - category: "धार्मिक" + holiday: true }, { + event: "सरस्वती पूजा / वसन्तपञ्चमी", eventType: "lunar", lunarMonth: "माघ", paksha: "शुक्ल पक्ष", tithi: "पञ्चमी", - event: "सरस्वती पूजा / वसन्तपञ्चमी", + startYear: null, + endYear: null, detail: "ज्ञान र शिक्षाको देवी सरस्वतीको पूजा।", - category: "धार्मिक" + holiday: true }, { + event: "महाशिवरात्रि", eventType: "lunar", lunarMonth: "फाल्गुन", paksha: "कृष्ण पक्ष", tithi: "चतुर्दशी", - event: "महाशिवरात्रि", + startYear: null, + endYear: null, detail: "भगवान शिवको महान रात्रि।", - category: "धार्मिक" + holiday: true }, { + event: "होली पूर्णिमा", eventType: "lunar", lunarMonth: "फाल्गुन", paksha: "शुक्ल पक्ष", tithi: "पूर्णिमा", - event: "होली पूर्णिमा", + startYear: null, + endYear: null, detail: "रङ्गहरूको उत्सव।", - category: "धार्मिक" + holiday: true } ]; -// Gregorian events for every year. +// Gregorian recurring events. var gregorianEvents = [ { event: "New Year's Day", - dateType: "gregorian", + eventType: "gregorian", date: "01/01", + startYear: null, + endYear: null, detail: "Celebration of the new Gregorian year.", - category: "International Day" + holiday: true }, { event: "Valentine's Day", - dateType: "gregorian", + eventType: "gregorian", date: "02/14", + startYear: null, + endYear: null, detail: "International day of love. Nepali: प्रणय दिवस.", - category: "International Day" + holiday: false }, { event: "International Women's Day", - dateType: "gregorian", + eventType: "gregorian", date: "03/08", + startYear: null, + endYear: null, detail: "Global day celebrating womanhood. Nepali: नारी दिवस.", - category: "International Day" + holiday: true }, { event: "World Health Day", - dateType: "gregorian", + eventType: "gregorian", date: "04/07", + startYear: null, + endYear: null, detail: "A global health awareness day. Nepali: विश्व स्वास्थ्य दिवस.", - category: "International Day" + holiday: false }, { event: "International Workers' Day", - dateType: "gregorian", + eventType: "gregorian", date: "05/01", + startYear: null, + endYear: null, detail: "Also known as May Day. Nepali: अन्तर्राष्ट्रिय श्रमिक दिवस.", - category: "International Day" + holiday: true }, { event: "World Environment Day", - dateType: "gregorian", + eventType: "gregorian", date: "06/05", + startYear: null, + endYear: null, detail: "Day for environmental awareness and action. Nepali: विश्व वातावरण दिवस.", - category: "International Day" + holiday: false }, { event: "International Day of Yoga", - dateType: "gregorian", + eventType: "gregorian", date: "06/21", + startYear: null, + endYear: null, detail: "Global day to celebrate yoga. Nepali: विश्व योग दिवस.", - category: "International Day" + holiday: false }, { event: "World Population Day", - dateType: "gregorian", + eventType: "gregorian", date: "07/11", + startYear: null, + endYear: null, detail: "Day to raise awareness of global population issues. Nepali: विश्व जनसंख्या दिवस.", - category: "International Day" + holiday: false }, { event: "International Youth Day", - dateType: "gregorian", + eventType: "gregorian", date: "08/12", + startYear: null, + endYear: null, detail: "Day to celebrate young people as agents of change. Nepali: अन्तर्राष्ट्रिय युवा दिवस.", - category: "International Day" + holiday: false }, { event: "International Human Rights Day", - dateType: "gregorian", + eventType: "gregorian", date: "12/10", + startYear: null, + endYear: null, detail: "Commemorates the adoption of the Universal Declaration of Human Rights. Nepali: अन्तर्राष्ट्रिय मानव अधिकार दिवस.", - category: "International Day" + holiday: false }, { event: "Christmas Day", - dateType: "gregorian", + eventType: "gregorian", date: "12/25", + startYear: null, + endYear: null, detail: "Christian festival celebrating the birth of Jesus. Nepali: क्रिसमस-डे.", - category: "Festival" + holiday: true } ]; @@ -389,87 +478,111 @@ var gregorianEvents = [ var bikramRecurringEvents = [ { event: "लोकतन्त्र दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "01/11", + startYear: 2063, + endYear: null, detail: "लोकतन्त्र दिवस, हरेक वर्ष बैशाख ११ गते मनाइन्छ।", - category: "National Day" + holiday: true }, { event: "गणतन्त्र दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "02/15", + startYear: 2065, + endYear: null, detail: "गणतन्त्र दिवस, हरेक वर्ष जेठ १५ गते मनाइन्छ।", - category: "National Day" + holiday: true }, { event: "राष्ट्रिय धान दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "03/15", - detail: "राष्ट्रिय धान दिवस, हरेक वर्ष असार १५ गते मनाइन्छ।", - category: "National Day" + startYear: null, + endYear: null, + detail: "राष्ट्रिय धान दिवस, हरेक वर्ष असार १५ गते मनाइन्छ。", + holiday: false }, { event: "भानु जयन्ती", - dateType: "brecurring", + eventType: "bikramRecurring", date: "03/29", + startYear: null, + endYear: null, detail: "कवि भानुभक्त आचार्यको जन्म जयन्ती।", - category: "Jayanti" + holiday: false }, { event: "संविधान दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "06/03", + startYear: 2072, + endYear: null, detail: "संविधान दिवस, हरेक वर्ष असोज ३ गते मनाइन्छ।", - category: "National Day" + holiday: true }, { event: "पृथ्वी जयन्ती / राष्ट्रिय एकता दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "09/27", + startYear: null, + endYear: null, detail: "पृथ्वी जयन्ती / राष्ट्रिय एकता दिवस।", - category: "National Day" + holiday: true }, { event: "शहीद दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "10/16", + startYear: null, + endYear: null, detail: "शहीद दिवस।", - category: "National Day" + holiday: true }, { event: "प्रजातन्त्र दिवस", - dateType: "brecurring", + eventType: "bikramRecurring", date: "11/07", + startYear: 2007, + endYear: 2062, detail: "राणा शासनको अन्त्यको सम्झनामा मनाइने प्रजातन्त्र दिवस।", - category: "National Day" + holiday: true }, { event: "नयाँ वर्ष", - dateType: "brecurring", + eventType: "bikramRecurring", date: "01/01", + startYear: null, + endYear: null, detail: "नेपाली नयाँ वर्ष।", - category: "Festival" + holiday: true }, { event: "बिस्का: जात्रा", - dateType: "brecurring", + eventType: "bikramRecurring", date: "01/01", + startYear: null, + endYear: null, detail: "भक्तपुरमा मनाइने बिस्का जात्राको उत्सव।", - category: "Jatra" + holiday: true }, { event: "साउने सङ्क्रान्ति", - dateType: "brecurring", + eventType: "bikramRecurring", date: "04/01", + startYear: null, + endYear: null, detail: "श्रावण सङ्क्रान्ति, श्रावण महिनाको पहिलो दिन।", - category: "Sankranti" + holiday: false }, { event: "माघे संक्रान्ति", - dateType: "brecurring", + eventType: "bikramRecurring", date: "10/01", + startYear: null, + endYear: null, detail: "माघे सङ्क्रान्ति, माघ महिनाको पहिलो दिन।", - category: "Sankranti" + holiday: true } ]; @@ -477,37 +590,38 @@ var bikramRecurringEvents = [ var bikramFixedEvents = [ { event: "भोटो जात्रा", - dateType: "bikram", + eventType: "bikramFixed", date: "2082/02/18", + startYear: null, + endYear: null, detail: "रातो मच्छिन्द्रनाथ जात्राको समापन दिन।", - category: "Jatra" + holiday: true }, { event: "तमु ल्होसार", - dateType: "bikram", + eventType: "bikramFixed", date: "2082/09/15", + startYear: null, + endYear: null, detail: "गुरुङ समुदायको नयाँ वर्ष।", - category: "Lhosar" + holiday: true }, { event: "सोनाम ल्होसार", - dateType: "bikram", + eventType: "bikramFixed", date: "2082/10/05", + startYear: null, + endYear: null, detail: "तमाङ समुदायको नयाँ वर्ष।", - category: "Lhosar" + holiday: true }, { event: "ग्याल्पो ल्होछार", - dateType: "bikram", + eventType: "bikramFixed", date: "2082/11/06", + startYear: null, + endYear: null, detail: "शेर्पा समुदायको नयाँ वर्ष।", - category: "Lhosar" - }, - { - event: "महा शिवरात्री / नेपाली सेना दिवस", - dateType: "bikram", - date: "2082/11/04", - detail: "भगवान शिवको महान रात्रि र नेपाली सेनाको दिवस।", - category: "Festival" + holiday: true } ]; diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index 9b77b01..c005bb8 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -343,46 +343,76 @@ function _getPanchangaBasics(date) { function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { var events = []; + var gregorianYear = date.getUTCFullYear(); var gregorianMonth = date.getUTCMonth() + 1; var gregorianDay = date.getUTCDate(); var formattedGregorianDate = formatMonthDay(gregorianMonth, gregorianDay); var formattedBikramRecurringDate = formatMonthDay(bsMonthIndex + 1, bsDay); + // Handle Gregorian events if (EventsData.gregorianEvents) { for (var i = 0; i < EventsData.gregorianEvents.length; i++) { var event = EventsData.gregorianEvents[i]; + // Check year constraints using Gregorian year + if (event.startYear && gregorianYear < event.startYear) continue; + if (event.endYear && gregorianYear > event.endYear) continue; + if (event.date === formattedGregorianDate) { - events.push({ name: event.event, detail: event.detail, category: event.category }); + events.push({ name: event.event, detail: event.detail, holiday: event.holiday }); } } } + + // Handle Bikram recurring events if (EventsData.bikramRecurringEvents) { for (var j = 0; j < EventsData.bikramRecurringEvents.length; j++) { let event = EventsData.bikramRecurringEvents[j]; + // Check year constraints using BS year + if (event.startYear && bsYear < event.startYear) continue; + if (event.endYear && bsYear > event.endYear) continue; + if (event.date === formattedBikramRecurringDate) { - events.push({ name: event.event, detail: event.detail, category: event.category }); + events.push({ name: event.event, detail: event.detail, holiday: event.holiday }); + } + } + } + + // Handle Bikram fixed events + if (EventsData.bikramFixedEvents) { + var formattedFixedDate = bsYear + "/" + formatMonthDay(bsMonthIndex + 1, bsDay); + for(let i = 0; i < EventsData.bikramFixedEvents.length; i++) { + let event = EventsData.bikramFixedEvents[i]; + if (event.date === formattedFixedDate) { + events.push({ name: event.event, detail: event.detail, holiday: event.holiday }); } } } + // Handle Lunar events if (EventsData.lunarEvents) { var todayInfo = _getPanchangaBasics(date); if (todayInfo.isAdhika) { - return events; + return events; // Assuming no lunar events in Adhika masa } var yesterday = new Date(date.getTime() - 86400000); var yesterdayInfo = _getPanchangaBasics(yesterday); + // Check if the *previous* lunar month was a kshaya month. If so, its events are observed in the current month. var prevLunarMonthAhar = todayInfo.ahar - 29.53; - var prevLunarMonthAdhikaKshaya = calculateAdhikaMasa(prevLunarMonthAhar); + var prevMonthStatus = calculateAdhikaMasa(prevLunarMonthAhar); var kshayaMonthName = null; - if (prevLunarMonthAdhikaKshaya.startsWith("क्षय")) { - kshayaMonthName = prevLunarMonthAdhikaKshaya.split(" ")[1]; + if (prevMonthStatus.startsWith("क्षय")) { + kshayaMonthName = prevMonthStatus.split(" ")[1]; } for (var k = 0; k < EventsData.lunarEvents.length; k++) { var lunarEvent = EventsData.lunarEvents[k]; + + // Check year constraints using BS year + if (lunarEvent.startYear && bsYear < lunarEvent.startYear) continue; + if (lunarEvent.endYear && bsYear > lunarEvent.endYear) continue; + var isEventForToday = (lunarEvent.lunarMonth === todayInfo.lunarMonthName && lunarEvent.paksha === todayInfo.paksha && lunarEvent.tithi === todayInfo.tithiName); @@ -398,7 +428,7 @@ function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { yesterdayInfo.tithiName === todayInfo.tithiName); if (isFirstDayOfTithi) { - events.push({ name: lunarEvent.event, detail: lunarEvent.detail, category: lunarEvent.category }); + events.push({ name: lunarEvent.event, detail: lunarEvent.detail, holiday: lunarEvent.holiday }); } } } @@ -406,6 +436,7 @@ function getEventsForDate(date, bsYear, bsMonthIndex, bsDay) { return events; } + // Main calculations function calculate(date, lat, lon, tz) { var cacheKey = "panchanga_" + date.getTime(); From 64cf547750813d3f02872a1deb84cf4c1d40f784 Mon Sep 17 00:00:00 2001 From: khumnath Date: Sun, 17 Aug 2025 14:16:54 +0545 Subject: [PATCH 7/8] changed border for holiday to visible color --- qml/Theme.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qml/Theme.qml b/qml/Theme.qml index d53dd57..9444585 100644 --- a/qml/Theme.qml +++ b/qml/Theme.qml @@ -35,7 +35,7 @@ QtObject { readonly property color borderColor: isDark ? "#334155" : "#e2e8f0" readonly property color todayBorder: isDark ? "#0ea5e9" : "#0284c7" readonly property color saturdayBorder: isDark ? "#334155" : "#fda4af" - readonly property color holidayBorder: isDark ? "#334155" : "#fda4af" + readonly property color holidayBorder: isDark ? "#C58F69" : "#FF9101" // === Highlighted Days === readonly property color todayBg: isDark ? "#082f49" : "#f0f9ff" From e66c42b38c20c231086171be0e121389838feaea Mon Sep 17 00:00:00 2001 From: khumnath Date: Mon, 18 Aug 2025 09:56:26 +0545 Subject: [PATCH 8/8] debug day difference fix between data driven and computed --- resources/PanchangaCalculator.js | 129 ++++++++++++++++--------------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/resources/PanchangaCalculator.js b/resources/PanchangaCalculator.js index c005bb8..3b0d631 100644 --- a/resources/PanchangaCalculator.js +++ b/resources/PanchangaCalculator.js @@ -632,7 +632,6 @@ function generateDebugInfo(date, lat, lon, tz) { date.getUTCDate() ); var ahar = jd - KaliEpoch + 0.25 + ((lon / 15 - tz) / 24); - var sunLong = trueLongitudeSun(ahar); var moonLong = trueLongitudeMoon(ahar); var tithiVal = getTithi(sunLong, moonLong); @@ -642,101 +641,109 @@ function generateDebugInfo(date, lat, lon, tz) { var tithiName = resolveTithiName(tithiDay, paksha); var karanaIdx = Math.floor(2 * tithiVal); - var karanaName = karanaIdx > 0 - ? (karanaIdx < 57 ? karanas[karanaIdx % 7 || 7] : karanas[karanaIdx - 57 + 8]) - : karanas[0]; + var karanaName = karanaIdx > 0 ? (karanaIdx < 57 ? karanas[(karanaIdx - 1) % 7 + 1] : karanas[karanaIdx - 57 + 8]) : karanas[0]; var bsInfoCalc = fromGregorianAstronomical( date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate() ); - var dayDifference = 0; - var gregFromAstronomical = fromBikramSambat( + var gregFromAstronomical_Today = fromBikramSambat( bsInfoCalc.year, bsInfoCalc.monthIndex, bsInfoCalc.day - ); + ); - if (gregFromAstronomical) { - var timeDiff = date.getTime() - gregFromAstronomical.getTime(); + if (gregFromAstronomical_Today) { + var timeDiff = date.getTime() - gregFromAstronomical_Today.getTime(); dayDifference = Math.round(timeDiff / (1000 * 60 * 60 * 24)); } + if (dayDifference === 0 && !bsInfoData.isComputed) { + var isMismatch = (bsInfoData.day !== bsInfoCalc.day || bsInfoData.monthIndex !== bsInfoCalc.monthIndex); + if (isMismatch) { + var tomorrow = new Date(date.getTime()); + tomorrow.setUTCDate(date.getUTCDate() + 1); + var bsInfoCalc_Tomorrow = fromGregorianAstronomical( + tomorrow.getUTCFullYear(), + tomorrow.getUTCMonth() + 1, + tomorrow.getUTCDate() + ); + + var gregFromAstronomical_Tomorrow = fromBikramSambat( + bsInfoCalc_Tomorrow.year, + bsInfoCalc_Tomorrow.monthIndex, + bsInfoCalc_Tomorrow.day + ); + + if (gregFromAstronomical_Tomorrow) { + var timeDiff_Tomorrow = tomorrow.getTime() - gregFromAstronomical_Tomorrow.getTime(); + var dayDifference_Tomorrow = Math.round(timeDiff_Tomorrow / (1000 * 60 * 60 * 24)); + + if (dayDifference_Tomorrow !== 0) { + dayDifference = dayDifference_Tomorrow; + } + } + } + } + var dayDifferenceDisplay = dayDifference; - if (Math.abs(dayDifference) > 2) {  // Show in red if difference is more than 2 days + if (Math.abs(dayDifference) > 2) { dayDifferenceDisplay = '' + dayDifference + ''; } else if (Math.abs(dayDifference) > 0) { dayDifferenceDisplay = '' + dayDifference + ''; } + var sunriseSunset = getSunriseSunset(date, lat, lon, tz); var isComputed = bsInfoData.isComputed; var computedbsdate = toDevanagari(bsInfoCalc.year) + " " + bsInfoCalc.monthName + " " + toDevanagari(bsInfoCalc.day); - var dataDrivenBsDateString = "N/A"; - var acceptedBsDate = computedbsdate; // fallback by default + var acceptedBsDate = computedbsdate; var dataDrivenInfo = ""; if (bsInfoData && !isComputed) { dataDrivenBsDateString = toDevanagari(bsInfoData.year) + " " + bsInfoData.monthName + " " + toDevanagari(bsInfoData.day); acceptedBsDate = dataDrivenBsDateString; - dataDrivenInfo = - `Debug Information\n` + - `(Data-Driven for date conversion):\n` + - "Gregorian Date: " + date + "\n" + - "accepted BS Date: " + acceptedBsDate + "\n" + - "(panchanga is based on data-driven conversion)\n"; + dataDrivenInfo = `Debug Information\n(Data-Driven for date conversion):\n` + "Gregorian Date: " + date + "\n" + "accepted BS Date: " + acceptedBsDate + "\n" + "(panchanga is based on data-driven conversion)\n"; } else { - dataDrivenInfo = - `Debug Information\n` + - `(Astronomical Calculation - outside data range):\n` + - "Gregorian Date: " + date + "\n" + - "accepted BS Date: " + acceptedBsDate + "\n" + - "(panchanga is based on astronomical computation)\n"; + dataDrivenInfo = `Debug Information\n(Astronomical Calculation - outside data range):\n` + "Gregorian Date: " + date + "\n" + "accepted BS Date: " + acceptedBsDate + "\n" + "(panchanga is based on astronomical computation)\n"; } - - var lunarMonthInfo = getLunarMonthNameWithAdhik(ahar); var lunarMonthDisplay = lunarMonthInfo.isAdhika ? "अधिक " + lunarMonthInfo.monthName + " " + paksha : lunarMonthInfo.monthName + " " + paksha; var debugOutput = - '
' +
-            dataDrivenInfo +
-            `Consistency Check:\n` +
-            "Data-Driven BS Date: " + dataDrivenBsDateString + "\n" +
-            "Astronomical BS Date (Computed): " + computedbsdate + "\n" +
-            "Day Difference: " + dayDifferenceDisplay + " " + (Math.abs(dayDifference) === 1 ? 'day' : 'days') + "\n" +
-            `Note: Positive = Astronomical date is behind;\n` +
-            `Negative = Astronomical date is ahead\n` +
-
-            " " +`Lunar Month (Purnimanta): ` + lunarMonthDisplay + "\n" +
-
-            `--- Solar Outputs ---\n` +
-            "gregorianDate: " + Qt.formatDateTime(date, "dddd, MMMM d, yyyy") + "\n" +
-            "sunrise: " + sunriseSunset.sunrise + "\n" +
-            "sunset: " + sunriseSunset.sunset + "\n" +
-            "sunRashi: " + rashis[Math.floor(sunLong / 30) % 12] + " | index: " + (Math.floor(sunLong / 30) % 12 + 1) + "\n" +
-
-            " " +`--- Lunar Outputs ---\n` +
-            "tithi: " + tithiName + " | index: " + tithiDay + "\n" +
-            "tithiAngle: " + (tithiVal * 12).toFixed(4) + "°\n" +
-            "paksha: " + paksha + "\n" +
-            "nakshatra: " + nakshatras[Math.floor(moonLong * 27 / 360) % 27] + " | index: " + (Math.floor(moonLong * 27 / 360) % 27 + 1) + "\n" +
-            "yoga: " + yogas[Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27] + " | index: " + (Math.floor(zero360(sunLong + moonLong) * 27 / 360) % 27 + 1) + "\n" +
-            "yogaAngle: " + zero360(sunLong + moonLong).toFixed(4) + "°\n" +
-            "karana: " + karanaName + " | index: " + karanaIdx + "\n" +
-            "karanaAngle: " + (2 * tithiVal).toFixed(4) + "\n" +
-            "moonRashi: " + rashis[Math.floor(moonLong / 30) % 12] + " | index: " + (Math.floor(moonLong / 30) % 12 + 1) + "\n" +
-            "adhikaMasa: " + calculateAdhikaMasa(ahar) + " (computed)\n" +
-
-            " " + `--- Metadata ---\n` +
-            "bsMonthIndex (0-based): " + bsInfoCalc.monthIndex + "\n" +
-            "weekday (UTC): " + weekdays[date.getUTCDay()] + "\n" +
-            "isComputed: " + isComputed +
-            '
'; - + '
' +
+        dataDrivenInfo +
+        `Consistency Check:\n` +
+        "Data-Driven BS Date: " + dataDrivenBsDateString + "\n" +
+        "Astronomical BS Date (Computed): " + computedbsdate + "\n" +
+        "Day Difference: " + dayDifferenceDisplay + " " + (Math.abs(dayDifference) === 1 ? 'day' : 'days') + "\n" +
+        `Note: Positive = Astronomical date is behind;\n` +
+        `Negative = Astronomical date is ahead\n` +
+        " " + `Lunar Month (Purnimanta): ` + lunarMonthDisplay + "\n" +
+        `--- Solar Outputs ---\n` +
+        "gregorianDate: " + Qt.formatDateTime(date, "dddd, MMMM d, yyyy") + "\n" +
+        "sunrise: " + sunriseSunset.sunrise + "\n" + "sunset: " + sunriseSunset.sunset + "\n" +
+        "sunRashi: " + rashis[Math.floor(sunLong / 30) % 12] + " | index: " + (Math.floor(sunLong / 30) % 12 + 1) + "\n" +
+        " " + `--- Lunar Outputs ---\n` +
+        "tithi: " + tithiName + " | index: " + tithiDay + "\n" +
+        "tithiAngle: " + (tithiVal * 12).toFixed(4) + "°\n" + "paksha: " + paksha + "\n" +
+        "nakshatra: " + nakshatras[Math.floor(moonLong / (360 / 27))] + " | index: " + (Math.floor(moonLong / (360 / 27)) + 1) + "\n" +
+        "yoga: " + yogas[Math.floor(zero360(sunLong + moonLong) / (360 / 27))] + " | index: " + (Math.floor(zero360(sunLong + moonLong) / (360 / 27)) + 1) + "\n" +
+        "yogaAngle: " + zero360(sunLong + moonLong).toFixed(4) + "°\n" +
+        "karana: " + karanaName + " | index: " + karanaIdx + "\n" +
+        "karanaAngle: " + (2 * tithiVal).toFixed(4) + "\n" +
+        "moonRashi: " + rashis[Math.floor(moonLong / 30) % 12] + " | index: " + (Math.floor(moonLong / 30) % 12 + 1) + "\n" +
+        "adhikaMasa: " + calculateAdhikaMasa(ahar) + " (computed)\n" +
+
+        " " + `--- Metadata ---\n` +
+        "Julian Day: " + jd.toFixed(4) + "\n" +
+        "Ahar: " + ahar.toFixed(4) + "\n" +
+        "weekday (UTC): " + weekdays[date.getUTCDay()] + "\n" +
+        "isComputed: " + isComputed +
+        '
'; var result = { debug: debugOutput.trim().replace(/^\s*[\r\n]/gm, "") }; calculationCache[cacheKey] = result;