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 { JDate } from './jdate';
|
||||||
import { Paschalion } from './paschalion';
|
import { Paschalion } from './paschalion';
|
||||||
|
import { FOUNDATION } from './paschalion';
|
||||||
|
|
||||||
/** Result of sunrise/sunset calculation for a given day. */
|
/** Result of sunrise/sunset calculation for a given day. */
|
||||||
export interface SolarTimes {
|
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. */
|
/** Moon phase info for a given Julian date. */
|
||||||
export function getMoonInfo(jdate: JDate): LunarInfo {
|
export function getMoonInfo(jdate: JDate): LunarInfo {
|
||||||
const phase = Paschalion.getLunarPhase(jdate);
|
const phase = Paschalion.getLunarPhase(jdate);
|
||||||
const trend = phase < 0.5 ? 'waxing' : 'waning';
|
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)
|
// Map phase (0-1) to emoji (0=new, 0.5=full)
|
||||||
let emoji: string;
|
let emoji: string;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import { JDate } from './jdate';
|
|||||||
|
|
||||||
const LUNAR_MONTH = 29.52916667;
|
const LUNAR_MONTH = 29.52916667;
|
||||||
|
|
||||||
/** Age of the moon on March 1 for each year in the 19-year Metonic cycle (hours since midnight). */
|
/** Age of the moon on March 1 for each year in the 19-year Metonic cycle (days). */
|
||||||
const FOUNDATION = [
|
export const FOUNDATION = [
|
||||||
14.042016807, 25.462184874, 6.084033613, 17.966386555, 28.336134454,
|
14.042016807, 25.462184874, 6.084033613, 17.966386555, 28.336134454,
|
||||||
9.210084034, 20.504201681, 1.420168067, 12.294117647, 23.168067227,
|
9.210084034, 20.504201681, 1.420168067, 12.294117647, 23.168067227,
|
||||||
4.546218487, 15.042016807, 26.294117647, 7.630252101, 18.546218487,
|
4.546218487, 15.042016807, 26.294117647, 7.630252101, 18.546218487,
|
||||||
|
|||||||
Reference in new issue
Block a user