From 196cf7557f5bd92c50919ed63141c929e249501a Mon Sep 17 00:00:00 2001 From: Seth Date: Mon, 9 Mar 2026 02:36:56 +0000 Subject: [PATCH] Show Seth/Gregorian astronomy columns and dual-date lunar event list --- astro.html | 51 ++++++++++++++++++++++++++--------- astro.js | 79 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 109 insertions(+), 21 deletions(-) diff --git a/astro.html b/astro.html index aa2fbd7..ff8e2d6 100644 --- a/astro.html +++ b/astro.html @@ -35,16 +35,28 @@ color: var(--muted); margin-top: 0.2rem; } + .astro-head { + display: grid; + grid-template-columns: 130px 1fr 1fr; + gap: 0.35rem 0.9rem; + font-size: 0.72rem; + color: #808892; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-top: 0.35rem; + } .astro-grid { display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 0.4rem 1rem; - font-size: 0.92rem; + grid-template-columns: 130px 1fr 1fr; + gap: 0.35rem 0.9rem; + font-size: 0.9rem; color: var(--muted); - margin: 1.2rem 0; + margin: 0.45rem 0 1.1rem; + } + .astro-label { + color: var(--text); + font-weight: 600; } - .astro-grid p { margin: 0; } - .astro-grid strong { color: var(--text); } .date-nav { display: flex; align-items: center; @@ -92,10 +104,19 @@ border-bottom: 1px solid #2a2a2a; display: flex; justify-content: space-between; + align-items: flex-start; gap: 0.5rem; } .event-list li:last-child { border-bottom: none; } .event-name { color: var(--text); } + .event-dual { + display: flex; + flex-direction: column; + text-align: right; + gap: 0.04rem; + font-size: 0.77rem; + } + .event-dual span:first-child { color: var(--text); } @@ -117,19 +138,23 @@
+
+
Seth
Gregorian
+
+
Sun
-

Sunrise:

-

Sunset:

-

Day length:

-

Solar noon:

+
Sunrise
+
Sunset
+
Day length
+
Solar noon
Moon
-

Age:

-

Next new moon:

-

Next full moon:

+
Age
+
Next new moon
+
Next full moon
diff --git a/astro.js b/astro.js index 8d20c36..470394c 100644 --- a/astro.js +++ b/astro.js @@ -143,6 +143,54 @@ function dayLengthStr(riseJD, setJD) { return `${h}h ${String(m).padStart(2,"0")}m`; } +function jdToDecimalTime(jd) { + const frac = ((jd + 0.5) % 1 + 1) % 1; + const dec = frac * 10; + const h = Math.floor(dec); + const m = Math.floor((dec - h) * 100); + return `${h}:${String(m).padStart(2, "0")}`; +} + +function dayLengthDecimalStr(riseJD, setJD) { + const decHours = (setJD - riseJD) * 10; + const h = Math.floor(decHours); + const m = Math.floor((decHours - h) * 100); + return `${h}:${String(m).padStart(2, "0")}`; +} + +// ── Seth date helpers ─────────────────────────────────────────────────────── +function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; +} + +function getDayOfYearUTC(date) { + const y = date.getUTCFullYear(); + const m = date.getUTCMonth() + 1; + const d = date.getUTCDate(); + const cum = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; + let doy = cum[m - 1] + d; + if (isLeapYear(y) && m > 2) doy++; + return { year: y, doy }; +} + +function toSethDate(year, dayOfYear) { + const leap = isLeapYear(year); + if (leap && dayOfYear === 60) return { type: "leapday", year }; + const idx = (leap && dayOfYear > 60 ? dayOfYear - 1 : dayOfYear) - 1; + if (idx < 360) { + const month = Math.floor(idx / 36); + const dayInM = idx % 36; + return { type: "month", year, month, day: dayInM }; + } + return { type: "holiday", year, holiday: idx - 360 }; +} + +function sethLog(sd) { + if (sd.type === "leapday") return `Leap Day ${sd.year}`; + if (sd.type === "holiday") return `H${sd.holiday}.${sd.year}`; + return `${String(sd.day).padStart(2, "0")}.${sd.month}.${sd.year}`; +} + // ── Solstice / Equinox (Meeus Table 27.a + correction) ─────────────────────── // Returns approximate JD for each event in a given year // season: 0=March equinox, 1=June solstice, 2=September equinox, 3=December solstice @@ -246,15 +294,27 @@ function render() { const jd = jdFromDate(date); const nextNewJD = nextMoonPhaseJD(jd, 0); const nextFullJD = nextMoonPhaseJD(jd, 2); - document.getElementById("nextNew").textContent = dateFromJD(nextNewJD).toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC" }); - document.getElementById("nextFull").textContent = dateFromJD(nextFullJD).toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC" }); + const nextNewDate = dateFromJD(nextNewJD); + const nextFullDate = dateFromJD(nextFullJD); + const nextNewSeth = toSethDate(getDayOfYearUTC(nextNewDate).year, getDayOfYearUTC(nextNewDate).doy); + const nextFullSeth = toSethDate(getDayOfYearUTC(nextFullDate).year, getDayOfYearUTC(nextFullDate).doy); + document.getElementById("nextNewSeth").textContent = sethLog(nextNewSeth); + document.getElementById("nextNewGreg").textContent = nextNewDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" }); + document.getElementById("nextFullSeth").textContent = sethLog(nextFullSeth); + document.getElementById("nextFullGreg").textContent = nextFullDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" }); // Sun const sun = sunriseSunset(date, LAT, LON); - document.getElementById("sunrise").textContent = sun.rise || (sun.alwaysUp ? "Midnight sun" : "Below horizon"); - document.getElementById("sunset").textContent = sun.set || (sun.alwaysUp ? "Midnight sun" : "Below horizon"); - document.getElementById("solarNoon").textContent = sun.noon; - document.getElementById("dayLen").textContent = sun.rise && sun.set ? dayLengthStr(sun.riseJD, sun.setJD) : "—"; + document.getElementById("sunriseSeth").textContent = sun.riseJD ? jdToDecimalTime(sun.riseJD) : "—"; + document.getElementById("sunriseGreg").textContent = sun.rise || (sun.alwaysUp ? "Midnight sun" : "Below horizon"); + document.getElementById("sunsetSeth").textContent = sun.setJD ? jdToDecimalTime(sun.setJD) : "—"; + document.getElementById("sunsetGreg").textContent = sun.set || (sun.alwaysUp ? "Midnight sun" : "Below horizon"); + document.getElementById("solarNoonSeth").textContent = sun.noonJD ? jdToDecimalTime(sun.noonJD) : "—"; + document.getElementById("solarNoonGreg").textContent = sun.noon; + document.getElementById("dayLenSeth").textContent = sun.rise && sun.set ? dayLengthDecimalStr(sun.riseJD, sun.setJD) : "—"; + document.getElementById("dayLenGreg").textContent = sun.rise && sun.set ? dayLengthStr(sun.riseJD, sun.setJD) : "—"; + document.getElementById("moonAgeSeth").textContent = `${(age * (10 / 29.53058867)).toFixed(2)} days`; + document.getElementById("moonAgeGreg").textContent = `${age.toFixed(1)} days`; @@ -290,9 +350,12 @@ function render() { ul.innerHTML = ""; allEvents.forEach(ev => { const li = document.createElement("li"); - const ds = ev.date.toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC" }); + const ds = ev.date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" }); + const sy = getDayOfYearUTC(ev.date); + const sseth = toSethDate(sy.year, sy.doy); + const sds = sethLog(sseth); const isToday = dateToParam(ev.date) === dateToParam(date); - li.innerHTML = `${ev.name}${ds}`; + li.innerHTML = `${ev.name}${sds}${ds}`; ul.appendChild(li); }); }