Skip to content

Instantly share code, notes, and snippets.

@gnacu
Created October 18, 2025 00:45
Show Gist options
  • Select an option

  • Save gnacu/aba7584a5490b0d20921bbe44d67a9fb to your computer and use it in GitHub Desktop.

Select an option

Save gnacu/aba7584a5490b0d20921bbe44d67a9fb to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
function readStdin(callback) {
let data = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => (data += chunk));
process.stdin.on("end", () => callback(data.trim()));
}
function getMoonInfo(date = new Date()) {
// --- Julian Day ---
const y = date.getUTCFullYear();
const m = date.getUTCMonth() + 1;
const d = date.getUTCDate();
let yy = y, mm = m;
if (m < 3) { yy--; mm += 12; }
const a = Math.floor(yy / 100);
const b = Math.floor(a / 4);
const c = 2 - a + b;
const e = Math.floor(365.25 * (yy + 4716));
const f = Math.floor(30.6001 * (mm + 1));
const jd = c + d + e + f - 1524.5;
// --- Phase and age ---
const daysSinceNew = jd - 2451550.1;
const newMoons = daysSinceNew / 29.53058867;
const phase = newMoons - Math.floor(newMoons);
const age = phase * 29.53058867;
let phaseName = "";
if (age < 1.0) phaseName = "New Moon";
else if (age < 7.4) phaseName = "Waxing Crescent";
else if (age < 8.6) phaseName = "First Quarter";
else if (age < 14.8) phaseName = "Waxing Gibbous";
else if (age < 15.8) phaseName = "Full Moon";
else if (age < 22.1) phaseName = "Waning Gibbous";
else if (age < 23.8) phaseName = "Last Quarter";
else phaseName = "Waning Crescent";
// --- Illumination ---
const illum = (1 - Math.cos((age / 29.53058867) * 2 * Math.PI)) / 2;
const percentLit = Math.round(illum * 100);
// --- Days until full/new ---
let daysToFull = 14.77 - age;
if (daysToFull < 0) daysToFull += 29.53;
let daysToNew = 29.53 - age;
if (daysToNew < 0) daysToNew += 29.53;
// --- Zodiac sign (approximate) ---
const T = (jd - 2451545.0) / 36525.0;
let Lm = (218.3164477 + 481267.88123421 * T) % 360;
if (Lm < 0) Lm += 360;
const zodiacNames = [
"Aries","Taurus","Gemini","Cancer","Leo","Virgo",
"Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"
];
const sign = zodiacNames[Math.floor(Lm / 30)];
// --- Distance (rough, km) ---
const a_km = 384400;
const ecc = 0.0549; // renamed from e → ecc
const M = (age / 29.53058867) * 2 * Math.PI;
let E = M;
for (let i = 0; i < 5; i++) E -= (E - ecc * Math.sin(E) - M) / (1 - ecc * Math.cos(E));
const v = 2 * Math.atan(Math.sqrt((1 + ecc) / (1 - ecc)) * Math.tan(E / 2));
const dist = a_km * (1 - ecc * ecc) / (1 + ecc * Math.cos(v));
const distK = Math.round(dist / 1000);
return {
phaseName,
percentLit,
daysToFull: daysToFull.toFixed(1),
daysToNew: daysToNew.toFixed(1),
sign,
distK
};
}
readStdin((input) => {
let date = new Date();
if (input && /^\d{4}-\d{2}-\d{2}$/.test(input))
date = new Date(input + "T00:00:00Z");
const { phaseName, percentLit, daysToFull, daysToNew, sign, distK } = getMoonInfo(date);
const output = `${phaseName}, ${percentLit}% lit, Full in ${daysToFull}d, New in ${daysToNew}d, in ${sign}, Dist ${distK}k km`;
process.stdout.write(output);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment