Skip to main content

Moon Module

The Moon module provides calculations for lunar position, phases, rise/set times, and related phenomena. Essential for planning observations and understanding our celestial companion.

Overview

The Moon's motion is complex—more so than any other celestial body we observe regularly. This module implements algorithms suitable for:

  • Lunar position (RA/Dec, ecliptic coordinates)
  • Moon phase (illumination, age, phase name)
  • Moonrise and moonset times
  • Next occurrence of major phases
  • Angular diameter and parallax

Accuracy: Position ~0.5° (sufficient for rise/set and phase calculations).

Quick Start

CLI Usage

# Current lunar position
starward moon position

# Current phase information
starward moon phase

# Moonrise and moonset
starward moon rise --lat 51.5 --lon -0.1
starward moon set --lat 51.5 --lon -0.1

# Next full moon
starward moon next full

# Next new moon
starward moon next new

Python API

from starward.core.moon import (
moon_position, moon_phase, moon_altitude,
moonrise, moonset, next_phase, MoonPhase
)
from starward.core.observer import Observer
from starward.core.time import jd_now

# Create an observer
greenwich = Observer.from_degrees("Greenwich", 51.4772, -0.0005)

# Get current lunar position
jd = jd_now()
pos = moon_position(jd)
print(f"Moon RA: {pos.ra.hours:.2f}h, Dec: {pos.dec.degrees:.1f}°")
print(f"Distance: {pos.distance_km:.0f} km")

# Current phase
phase = moon_phase(jd)
print(f"Phase: {phase.name}")
print(f"Illumination: {phase.percent_illuminated:.0f}%")
print(f"Age: {phase.age_days:.1f} days")

# Moonrise and moonset
rise = moonrise(greenwich, jd)
if rise:
print(f"Moonrise: {rise.to_datetime()}")

# Next full moon
next_full = next_phase(jd, MoonPhase.FULL_MOON)
print(f"Next full moon: {next_full.to_datetime()}")

Lunar Position

The moon_position() function returns a MoonPosition object containing:

FieldDescription
longitudeEcliptic longitude (Angle)
latitudeEcliptic latitude (Angle, ±5.3°)
raRight Ascension (Angle)
decDeclination (Angle)
distance_kmDistance in kilometers
angular_diameterApparent size (Angle)
parallaxHorizontal parallax (Angle)

Distance and Size

The Moon's distance varies from ~356,500 km (perigee) to ~406,700 km (apogee), causing its apparent size to vary:

pos = moon_position(jd)
print(f"Distance: {pos.distance_km:.0f} km")
print(f"Angular diameter: {pos.angular_diameter.arcminutes:.1f} arcmin")
print(f"Parallax: {pos.parallax.degrees:.2f}°")

When the Moon is closer, it appears larger—a "supermoon" occurs when a full moon coincides with perigee.

Moon Phase

The moon_phase() function returns a MoonPhaseInfo object:

FieldDescription
phase_anglePhase angle (0° = new, 180° = full)
illuminationIlluminated fraction (0-1)
percent_illuminatedPercentage (0-100)
age_daysDays since new moon (0-29.5)
namePhase name (string)

Phase Names

The lunar cycle is divided into eight phases:

PhaseAge (days)Illumination
New Moon00%
Waxing Crescent1-70-50%
First Quarter~7.450%
Waxing Gibbous7-1550-100%
Full Moon~14.8100%
Waning Gibbous15-22100-50%
Last Quarter~22.150%
Waning Crescent22-29.550-0%
phase = moon_phase(jd)
print(f"Phase: {phase.name}")
print(f"Age: {phase.age_days:.1f} days")
print(f"Illumination: {phase.percent_illuminated:.0f}%")

Finding Next Phases

Find the next occurrence of a major phase:

from starward.core.moon import next_phase, MoonPhase

jd = jd_now()

# Major phases
next_new = next_phase(jd, MoonPhase.NEW_MOON)
next_first = next_phase(jd, MoonPhase.FIRST_QUARTER)
next_full = next_phase(jd, MoonPhase.FULL_MOON)
next_last = next_phase(jd, MoonPhase.LAST_QUARTER)

print(f"Next new moon: {next_new.to_datetime()}")
print(f"Next full moon: {next_full.to_datetime()}")

Moonrise and Moonset

Unlike the Sun, the Moon rises and sets at very different times each day (about 50 minutes later each day on average):

rise = moonrise(observer, jd)
set_t = moonset(observer, jd)

if rise and set_t:
print(f"Moonrise: {rise.to_datetime()}")
print(f"Moonset: {set_t.to_datetime()}")

Edge Cases

  • The Moon may not rise or set on a given day
  • Near full moon, moonrise occurs around sunset
  • Near new moon, moonrise occurs around sunrise

Moon Altitude

Calculate the Moon's altitude at any time:

alt = moon_altitude(observer, jd)
print(f"Moon altitude: {alt.degrees:.1f}°")

if alt.degrees > 0:
print("Moon is up")

The Synodic Month

The synodic month (new moon to new moon) averages 29.53 days but varies due to the elliptical orbit:

# Find two consecutive new moons
new1 = next_phase(jd, MoonPhase.NEW_MOON)
new2 = next_phase(JulianDate(new1.jd + 1), MoonPhase.NEW_MOON)

synodic_month = new2.jd - new1.jd
print(f"This synodic month: {synodic_month:.2f} days")

Observation Planning

Moon-Target Separation

For deep-sky observations, moonlight can be problematic. Use the visibility module:

from starward.core.visibility import moon_target_separation
from starward.core.coords import ICRSCoord

target = ICRSCoord.from_degrees(83.63, 22.01) # M1 Crab Nebula
sep = moon_target_separation(target, jd)
print(f"Moon separation: {sep.degrees:.1f}°")

if sep.degrees < 30:
print("Moon may affect observations")

Best Observation Windows

For faint objects, plan observations when:

  1. Moon is below the horizon
  2. Moon is far from target (>60°)
  3. Moon is near new phase

Lunar Libration

Although not directly computed by this module, the Moon's apparent "wobble" (libration) means we can see about 59% of its surface over time, not just 50%.

Algorithm Details

This module uses the simplified lunar theory from Jean Meeus' Astronomical Algorithms, incorporating:

  • Mean orbital elements
  • Major perturbations from the Sun
  • Variation in orbital speed
  • Parallax correction

For higher precision (sub-arcminute), consider ELP/MPP02 (not yet implemented).

CLI Reference

# Position
starward moon position [--jd JD] [--json] [--verbose]

# Phase
starward moon phase [--jd JD] [--json]

# Rise/Set
starward moon rise --lat LAT --lon LON [--jd JD]
starward moon set --lat LAT --lon LON [--jd JD]

# Altitude
starward moon altitude --lat LAT --lon LON [--jd JD]

# Next phase (full|new|first|last)
starward moon next PHASE [--jd JD]

See Also