Moon’s Lunar Phase in JavaScript

Jason Sturges
3 min readJan 31, 2021
Photo by Mathew Schwartz on Unsplash

Using Julian date, you can calculate the current phase of the moon by finding the lunar age as a percentage through the lunar month.

In lunar calendars, a lunar month is the time between two identical syzygies. This is the equivalent of 29.53059 Earth days.

Start by obtaining Julian date:

const getJulianDate = (date = new Date()) => {
const time = date.getTime();
const tzoffset = date.getTimezoneOffset()

return (time / 86400000) - (tzoffset / 1440) + 2440587.5;
}

With Julian date, calculate days or percentage through the lunar month:

const LUNAR_MONTH = 29.530588853;const getLunarAge = (date = new Date()) => {
const percent = getLunarAgePercent(date);
const age = percent * LUNAR_MONTH;
return age;
}
const getLunarAgePercent = (date = new Date()) => {
return normalize((getJulianDate(date) - 2451550.1) / LUNAR_MONTH);
}
const normalize = value => {
value = value - Math.floor(value);
if (value < 0)
value = value + 1
return value;
}

Using the percentage through the lunar month, you can determine the current phase and precise position of shadow.

Lunar phases in order are as follows (Emojis represent moon as seen in the Northern Hemisphere.

  • 🌑 New
  • 🌒 Waxing Crescent
  • 🌓 First Quarter
  • 🌔 Waxing Gibbous
  • 🌕 Full
  • 🌖 Waning Gibbous
  • 🌗 Last Quarter
  • 🌘 Waning Crescent

Apply these to percentage ranges to get the phase:

const getLunarPhase = (date = new Date()) => {
const age = getLunarAge(date);
if (age < 1.84566)
return "New";
else if (age < 5.53699)
return "Waxing Crescent";
else if (age < 9.22831)
return "First Quarter";
else if (age < 12.91963)
return "Waxing Gibbous";
else if (age < 16.61096)
return "Full";
else if (age < 20.30228)
return "Waning Gibbous";
else if (age < 23.99361)
return "Last Quarter";
else if (age < 27.68493)
return "Waning Crescent";
return "New";
}

Or, use lunar age to determine whether the moon is waning or waxing:

const isWaxing = (date = new Date()) => {
const age = getLunarAge(date);
return age <= 14.765;
}
const isWaning = (date = new Date()) => {
const age = getLunarAge(date);
return age > 14.765;
}

This code has been assembled into a library in my lunarphase-js GitHub project, or install via npm:

npm i lunarphase-js

Then, import and use as:

import * as Moon from 'lunarphase-js';// For a specific date, pass a date object to a function:
const date = new Date();
const phase = Moon.getLunarPhase(date);
// Otherwise, current date will be used:
const phase = Moon.getLunarPhase();

API is as follows:

  • getLunarPhase() — Get the current lunar phase from the LunarPhase enum (ex: "Full")
  • getLunarPhaseEmoji() —Get the current lunar phase emoji from the LunarPhaseEmoji enum (ex: "🌕")
  • getLunarAge() — Get the lunar age (ex: 16.54412413414952)
  • getLunarAgePercent() — Get the percentage through the lunar cycle (ex: 0.5602368519132597)
  • isWaxing() — Whether the moon is waxing (ex: false)
  • isWaning() — Whether the moon is waning (ex: true)
  • getJulianDate()— Get the current Julian date (ex: 2459244.5972259142)

--

--

Jason Sturges

Avant-garde experimental artist — creative professional leveraging technology for immersive experiences