Skip to content

Instantly share code, notes, and snippets.

@miklb
Created July 1, 2015 07:12
Show Gist options
  • Save miklb/ed145757971096565723 to your computer and use it in GitHub Desktop.
Save miklb/ed145757971096565723 to your computer and use it in GitHub Desktop.
Calculate Lunar Phase
#!/usr/bin/env python
"""
moonphase.py - Calculate Lunar Phase
Author: Sean B. Palmer, inamidst.com
Cf. http://en.wikipedia.org/wiki/Lunar_phase#Lunar_phase_calculation
"""
import math, decimal, datetime
dec = decimal.Decimal
def position(now=None):
if now is None:
now = datetime.datetime.now()
diff = now - datetime.datetime(2001, 1, 1)
days = dec(diff.days) + (dec(diff.seconds) / dec(86400))
lunations = dec("0.20439731") + (days * dec("0.03386319269"))
return lunations % dec(1)
def phase(pos):
index = (pos * dec(8)) + dec("0.5")
index = math.floor(index)
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"
}[int(index) & 7]
def main():
pos = position()
phasename = phase(pos)
roundedpos = round(float(pos), 3)
print "%s (%s)" % (phasename, roundedpos)
if __name__=="__main__":
main()
@aceisace
Copy link

aceisace commented Nov 5, 2019

Simple, yet awesome piece of code! 👍 Thanks for sharing :)
If you don't mind, may I use this snippet in one of my repos?

@miklb
Copy link
Author

miklb commented Nov 12, 2019

Not my code, so I’m assuming as long as leave credit in the script, you would be Ok.

@aceisace
Copy link

@miklb
Thanks for getting back. OK, I'll do that then.

@DamienAllonsius
Copy link

Hey! Thanks for the script 👍
I understood that 0.20439731 = 1 / synodic lunar month.
But could you explain what 0.20439731 represents ? Is it the lunation at 00:00 on the 1st of January 2001 ? If yes, where did you get this figure ?
Thanks a lot

@cbronner35
Copy link

Amazing script! Would it be possible to the show percentage of the moon instead of what phase its in?

@miklb
Copy link
Author

miklb commented Sep 8, 2021

Swap out the percentages for the names in the return starting on line 24. You could add them instead of swapping for that matter.

@cbronner35
Copy link

I actually did that at first until I realized that some phases of the moon are between 0% to 50%. I need a more exact percentage. We use night vision googles that amplify light by 6000 times. The moon is the primary source of light for amplification. So when were flying the percent tells how well we are going to see. Hope that makes sense lol

@miklb
Copy link
Author

miklb commented Sep 9, 2021

It does and while this wasn’t my script it’s a challenge worthy figuring out. My 1st instinct is the print lunations and see what that value is.

@miklb
Copy link
Author

miklb commented Sep 9, 2021

Actually I believe roundedpos is your lunation %. I get .09 for today which seems ~.01 accurate

I added print(f"{pos: .2%}" + " illuminated") after the current print

6F986A32-0066-467E-967E-616821A24B22

@cbronner35
Copy link

Perfect!!! Thanks so much that's exactly what I needed! Your amazing! I appreciate it :)

@cbronner35
Copy link

You know actually I'm not super sure its very accurate. I just printed around 12.4 % but according to this site https://www.timeanddate.com/astronomy/@4313572 for our area its 16.1 percent. Any idea why I have such a disconnect between these two?

@miklb
Copy link
Author

miklb commented Sep 10, 2021

My tide app tells me it’s 28% waxing. I believe there are a few different formulas for calculating lunation. All use some fixed time from the past to calculate from. I suppose if you need accuracy to the 1°, a different formula may be required. If you find one I’d be happy to help implement in this script.

@miklb
Copy link
Author

miklb commented Sep 11, 2021

You could always go a different route & make an api call to get the reported lunation. That could also get you visibility for closest weather station and any other details you might need. If worried about connectivity, store it in LocalStorage in the browser. I’m not sure how you are using the script though.

@sbp
Copy link

sbp commented Jun 17, 2024

Hi, original author here. The equation that I used was originally posted to Wikipedia by an author named "Monsieur le docteur Ralph" in March 2005. The magic values that I used were from that equation. Later, on the talk page for that article where they discuss removing the equation, they also discussed some potentially more accurate alternatives.

I posted the above code to my own website as moonphase.py, which has a Last-Modified date of 30 November 2005. I've been hosting it for nearly two decades on that site! I'm glad that people are finding the script useful. I and my friends use it in an IRC bot called saxo which I wrote about a decade ago to replace another one which I'd written a decade previously, roughly contemporaneous with moonphase.py.

If anybody comes up with an improved version of this script, with greater accuracy or ported to another language such a Go or Rust, please post the code or link to the code on this thread, and please send me a message. You can contact me on GitHub at @sbp, leave a message on my Wikipedia user talk page, or use whatever email address du jour I've got listed on my homepage.

@miklb
Copy link
Author

miklb commented Jun 18, 2024

@sbp howdy! I did leave credit in the script and I honestly don't remember where I came across it or why I originally shared it. I posted this gist 9 years ago! Thanks for pointing folks to the original source and offering support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment