Try Astrologer API

Subscribe to support and grow the project.

Moon Phase Details #

The MoonPhaseDetailsFactory generates a rich lunar context from any astrological subject. This page shows practical examples covering common use cases.

Basic Usage #

from kerykeion import AstrologicalSubjectFactory, MoonPhaseDetailsFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "Example", 2025, 4, 1, 7, 51,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London",
    online=False,
)

overview = MoonPhaseDetailsFactory.from_subject(subject)

print(f"Phase:        {overview.moon.phase_name} {overview.moon.emoji}")
print(f"Illumination: {overview.moon.illumination}")
print(f"Stage:        {overview.moon.stage}")
print(f"Major Phase:  {overview.moon.major_phase}")
print(f"Age:          {overview.moon.age_days} days")
print(f"Cycle:        {overview.moon.lunar_cycle}")

Output:

Phase:        Waxing Crescent 🌒
Illumination: 5%
Stage:        waxing
Major Phase:  New Moon
Age:          2 days
Cycle:        6.836%

Upcoming Phases #

Find the last and next occurrence of each major phase:

if overview.moon.detailed and overview.moon.detailed.upcoming_phases:
    phases = overview.moon.detailed.upcoming_phases

    for label, window in [
        ("New Moon",      phases.new_moon),
        ("First Quarter", phases.first_quarter),
        ("Full Moon",     phases.full_moon),
        ("Last Quarter",  phases.last_quarter),
    ]:
        if window is None:
            continue
        last = window.last.datestamp if window.last else "N/A"
        nxt  = window.next.datestamp if window.next else "N/A"
        print(f"{label:15s}  Last: {last}")
        print(f"{'':15s}  Next: {nxt}")
        print()

Output:

New Moon          Last: Sun, 30 Mar 2025 ...
                  Next: Mon, 28 Apr 2025 ...

First Quarter     Last: ...
                  Next: ...
...

Eclipse Information #

# Next Lunar Eclipse
if overview.moon.next_lunar_eclipse:
    ecl = overview.moon.next_lunar_eclipse
    print(f"Next Lunar Eclipse: {ecl.datestamp}")
    print(f"Type: {ecl.type}")

# Next Solar Eclipse
if overview.sun and overview.sun.next_solar_eclipse:
    ecl = overview.sun.next_solar_eclipse
    print(f"Next Solar Eclipse: {ecl.datestamp}")
    print(f"Type: {ecl.type}")

Sun Times and Position #

if overview.sun:
    sun = overview.sun

    print(f"Sunrise:    {sun.sunrise_timestamp}")
    print(f"Sunset:     {sun.sunset_timestamp}")
    print(f"Solar Noon: {sun.solar_noon}")
    print(f"Day Length: {sun.day_length}")

    if sun.position:
        print(f"Altitude:   {sun.position.altitude:.2f}°")
        print(f"Azimuth:    {sun.position.azimuth:.2f}°")

Generating a Text Report #

Pass the overview directly to ReportGenerator for a formatted ASCII report:

from kerykeion import ReportGenerator

ReportGenerator(overview).print_report()

Output:

=====================================================
Moon Phase Overview — Tue, 01 Apr 2025 06:51:00 +0000
=====================================================

+Moon Summary--+-------------------+
| Field        | Value             |
+--------------+-------------------+
| Phase Name   | Waxing Crescent 🌒|
| Major Phase  | New Moon          |
| Stage        | Waxing            |
| Illumination | 5%                |
| Age (days)   | 2                 |
| ...          | ...               |
+--------------+-------------------+

+Illumination Details--------+
| Field            | Value   |
+------------------+---------+
| Percentage       | 5.0%    |
| Visible Fraction | 0.0476  |
| Phase Angle      | 24.61°  |
+------------------+---------+

...

JSON Serialization #

import json

# Compact JSON (no None fields)
json_str = overview.model_dump_json(exclude_none=True, indent=2)
print(json_str)

# Or as a Python dict
data = overview.model_dump(exclude_none=True)

Zodiac Signs #

if overview.moon.zodiac:
    print(f"Sun Sign:  {overview.moon.zodiac.sun_sign}")
    print(f"Moon Sign: {overview.moon.zodiac.moon_sign}")

Location Metadata #

The factory can annotate whether a default location was used (useful for API consumers):

overview = MoonPhaseDetailsFactory.from_subject(
    subject,
    using_default_location=True,
    location_precision=2,
)

loc = overview.location
print(f"Lat: {loc.latitude}, Lng: {loc.longitude}")
print(f"Default location: {loc.using_default_location}")

Need this in production? Use the Astrologer API for hosted calculations, charts, and AI interpretations - no server setup required. Learn more →