fix: ecclesiastical moon day with alternating 29/30-day months
This commit is contained in:
1 parent
ec366f5681
commit
f4db817d13
2 files changed
+45
-3
No files matched your search
+43
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
import { JDate } from './jdate';
|
||||
import { Paschalion } from './paschalion';
|
||||
import { FOUNDATION } from './paschalion';
|
||||
|
||||
/** Result of sunrise/sunset calculation for a given day. */
|
||||
export interface SolarTimes {
|
||||
@@ -120,11 +121,52 @@ export function calcSolarTimes(jdate: JDate, lat: number, lon: number, tz: numbe
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate ecclesiastical moon day using the foundation (age on March 1)
|
||||
* and alternating 29/30-day months.
|
||||
* Returns 1-based day of the current lunar cycle (1-30).
|
||||
*/
|
||||
function calcMoonDay(jdate: JDate): number {
|
||||
const year = jdate.getYear();
|
||||
const cycle = Paschalion.getLunarCycle(year);
|
||||
const foundation = FOUNDATION[cycle - 1];
|
||||
|
||||
// Days from March 1 to the target date
|
||||
const march1 = new JDate(3, 1, year);
|
||||
let diff = jdate.difference(march1);
|
||||
if (diff < 0) {
|
||||
// Date is before March 1 — use previous year's foundation
|
||||
const prevCycle = cycle === 1 ? 19 : cycle - 1;
|
||||
const prevFoundation = FOUNDATION[prevCycle - 1];
|
||||
const prevMarch1 = new JDate(3, 1, year - 1);
|
||||
const diffFromPrevMarch = jdate.difference(prevMarch1);
|
||||
const adjusted = 29.53 * 12 + diffFromPrevMarch; // ~354 days for 12 lunar months
|
||||
let total = prevFoundation + adjusted;
|
||||
// Subtract full lunar cycles (alternating 29/30, starting with 29)
|
||||
const ml = (idx: number) => (idx % 2 === 0) ? 29 : 30;
|
||||
let monthIdx = 0;
|
||||
while (total >= ml(monthIdx)) { total -= ml(monthIdx); monthIdx++; }
|
||||
return Math.floor(total) + 1;
|
||||
}
|
||||
|
||||
let total = foundation + diff;
|
||||
|
||||
// Subtract alternating 29/30-day months (starting with 29)
|
||||
const monthLen = (idx: number) => (idx % 2 === 0) ? 29 : 30;
|
||||
let monthIdx = 0;
|
||||
while (total >= monthLen(monthIdx)) {
|
||||
total -= monthLen(monthIdx);
|
||||
monthIdx++;
|
||||
}
|
||||
|
||||
return Math.floor(total) + 1;
|
||||
}
|
||||
|
||||
/** Moon phase info for a given Julian date. */
|
||||
export function getMoonInfo(jdate: JDate): LunarInfo {
|
||||
const phase = Paschalion.getLunarPhase(jdate);
|
||||
const trend = phase < 0.5 ? 'waxing' : 'waning';
|
||||
const moonDay = Math.floor(phase * 29.53) + 1;
|
||||
const moonDay = calcMoonDay(jdate);
|
||||
|
||||
// Map phase (0-1) to emoji (0=new, 0.5=full)
|
||||
let emoji: string;
|
||||
|
||||
@@ -11,8 +11,8 @@ import { JDate } from './jdate';
|
||||
|
||||
const LUNAR_MONTH = 29.52916667;
|
||||
|
||||
/** Age of the moon on March 1 for each year in the 19-year Metonic cycle (hours since midnight). */
|
||||
const FOUNDATION = [
|
||||
/** Age of the moon on March 1 for each year in the 19-year Metonic cycle (days). */
|
||||
export const FOUNDATION = [
|
||||
14.042016807, 25.462184874, 6.084033613, 17.966386555, 28.336134454,
|
||||
9.210084034, 20.504201681, 1.420168067, 12.294117647, 23.168067227,
|
||||
4.546218487, 15.042016807, 26.294117647, 7.630252101, 18.546218487,
|
||||
|
||||
Reference in new issue
Block a user