Created
December 2, 2017 16:05
-
-
Save mrrrk/e100225508ad8b6882844de99d264ca7 to your computer and use it in GitHub Desktop.
Calculate lunar (moon) phase
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math, datetime | |
class Moon: | |
# average length of a lunar cycle (Wikipedia) | |
@staticmethod | |
def lunar_month_days(): return 29.530588853 | |
@staticmethod | |
def day_of_cycle(test_date=None): | |
if test_date is None: | |
test_date = datetime.datetime.now() | |
# the closer the base date (a known new-moon) is to the dates we're interested with, the better | |
base_new_moon = datetime.datetime(2017, 8, 21, 18, 30, 0) | |
days = (test_date - base_new_moon).total_seconds() / (24.0 * 60.0 * 60.0) | |
return days % Moon.lunar_month_days() | |
@staticmethod | |
def illumination(day_of_cycle): | |
# translate daily position as an angle between 0 and 360° | |
angle = 2 * math.pi * day_of_cycle / Moon.lunar_month_days() | |
# move and resize cosine curve so it represents waxing and waning as value from 0 to 1 | |
return (1 + (-math.cos(angle))) / 2.0 | |
# This isn't strictly accurate because new moon and full moon do not actually last for 1/8th of a cycle | |
@staticmethod | |
def phase(day_of_cycle): | |
proportion = float(day_of_cycle) / Moon.lunar_month_days() | |
# add 0.5 to put value in 'middle' of phase | |
# - which might put it past end of array, so use bitwise AND to lop it off | |
index = int(proportion * 8.0 + 0.5) & 7 | |
return { | |
0: "New Moon", | |
1: "Waxing Crescent", | |
2: "First Quarter", | |
3: "Waxing Gibbous", | |
4: "Full Moon", | |
5: "Waning Gibbous", | |
6: "Last Quarter", | |
7: "Waning Crescent" | |
}[index] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This uses the average synodic cycle time (time between new moons) along with the time of a recent new moon and assumes you're happy with the approximate result being out by a few hours.