astronoby
astronoby copied to clipboard
Moon "phase" and "phase name"
Problem this feature will solve
With the moon's current attributes, we get illuminated_fraction
but not the name of the current moon_phase
. I believe we discussed this a while back, and we realized that it's a bit of a tricky problem because essentially a "phase" is more of a "phase event" that occurs at a specific time, as opposed to being something that lasts for an entire day / calendar date.
However, I believe it's common for people to discuss the moon's illumination in terms of a day / calendar date (i.e. there's a full moon tomorrow) and having a shortcut to obtain this human-readable moon phase name would be useful.
Desired solution
We might consider converting illuminated_fraction
to phase_name
or such according to a formula. (I'll discuss this a bit more below...) We could also consider first checking against monthly_phase_events
, which, if rounded to the day, could take precedence over the formula.
A few years ago, I discussed this with the creators of the Dark Sky API, and this is a summary of the conversation and the resulting code that I've been using in my application for some time. Note that their JSON names are a bit confusing -- in their case moon_phase
is equivalent to illuminated_fraction
in Astronoby. Still, I think this could serve as the basis for a formula:
I have a question about the moon phase data point. I have Ruby code that looks like so:
if moon_phase == 0.5 "full" elsif moon_phase.between?(0.5, 0.75) "waning-gibbous-3" etc...
My concern is that the exact comparison of 0.5 might not be ideal if the 0.5 value doesn't last for a full day. The other conditions use ranges and would "win" more often than I'd like. (I'm thinking I'd like a "full moon" day to last for the entire day.) Can you tell me if I should be using a range for the "new" and "full" moons (0.0 and 0.5 respectively) or do those values last for a full day?
Good question! The answer depends on your use case, of course, but if you want to display the full moon only on the day it occurs, you should use a range of +/- half a day. A lunar month is 29.530587981 days long, which means you want a range of 0.5-0.5/29.530587981 to 0.5+0.5/29.530587981, or 0.4831 to 0.5169. You can do similarly for a new moon, which would then be less than 0.0169 or greater than 0.9831.
Taking this advice, I created a Ruby converter method that looks like this:
if moon_phase.between?(0.0169, 0.2415)
"Waxing crescent"
elsif moon_phase.between?(0.2415, 0.2584)
"First quarter"
elsif moon_phase.between?(0.2584, 0.4830)
"Waxing gibbous"
elsif moon_phase.between?(0.4830, 0.5169)
"Full"
elsif moon_phase.between?(0.5169, 0.7246)
"Waning gibbous"
elsif moon_phase.between?(0.7246, 0.7753)
"Last quarter"
elsif moon_phase.between?(0.7753, 0.9831)
"Waning crescent"
else
"New"
end
This has been working reasonably well for my application (an iOS weather app) and I think it seems reasonably generic and useful for potential inclusion into this gem, so I figured I'd chime in here. I'm working up a wrapper to integrate Astronoby into my application, so I'll report back if I get something working to my liking.
Thanks for your consideration!
[Update] I think I spoke too soon, and illuminated_fraction
is not what I'm looking for.
For example in other Rubygems:
SunCalc.moon_illumination(Time.zone.now)
=> {:fraction=>0.9617255644495569, :phase=>0.5626779295167722, :angle=>1.1389579376885706}
Astro::Moon.phase(Time.zone.now.to_datetime).phase
=> 0.5660597883082039
...I think you referred to this as the elongation
but it's a bit complicated how to calculate the "phase" to match these other libraries!
FWIW here's the Dark Sky documentation about their "moonPhase" attribute:
moonPhase: The fractional part of the lunation number during the given day: a value of 0 corresponds to a new moon, 0.25 to a first quarter moon, 0.5 to a full moon, and 0.75 to a last quarter moon. (The ranges in between these represent waxing crescent, waxing gibbous, waning gibbous, and waning crescent moons, respectively.)
The "lunation number" links to https://en.wikipedia.org/wiki/New_moon#Lunation_number
[Update 2] I came across this Swift library which seems to handle things how I was thinking of them -- might be worth having a closer look! https://github.com/mannylopez/TinyMoon?tab=readme-ov-file#moon-vs-exactmoon