Is the Moon Waxing or Waning?
That site provides the current moon illumination level, which lets you break it down into the phases of new moon, crescent, quarter, gibbous and full. Amateur astronomers know that the fun part of tracking the moon's phase is to understand whether it's "waxing" (growing more illuminated) or "waning" (growing less illuminated).
Although at any given moment the moon is illuminated based on its location, and your location, relative to the sun, the full cycle of a moon phase starts and ends with a new (0% illuminated) moon, and the full moon (100% illuminated) is the mid-point of the journey.
Therefore, to ascertain waxing or waning, all you need to do is know the moon's illumination level today and either yesterday or tomorrow. Fortunately, the Moon Giant website obligingly has the ability for you to ascertain the illumination level for a specific date.
A quick visit to the site with a regular web browser reveals that it works using a date-based URL format like this: http://www.moongiant.com/phase/11/6/2016.
So, you can build the date URL for the day before today with a call to
date program. If you've got the GNU version of
date, it's easy
to back up a day:
$ date Mon Nov 7 11:40:31 MST 2016 $ date -v -1d Sun Nov 6 11:40:15 MST 2016
It turns out that you also can specify that you want to back up 24 hours, although, of course, the net result is the same:
$ date -v -24H Sun Nov 6 11:40:24 MST 2016
More important, you can pass
date a format string that you then
can evaluate with the
eval function, so you can set month, day and year for
yesterday in one easy step:
$ eval $( date -v -1d +"mon=%m day=%d year=%Y" ) $ echo month = $mon, day = $day and year $year month = 11, day = 06 and year 2016
It's quite a handy trick when you need to work with extracting specific elements from date and 10x that when it also involves date math.Older Date Programs Are More Complicated
But, what if your version of
date doesn't include the
-v flag and
doesn't have all these fancy features? Then, my friend, you are facing
a definite challenge. Date math is pretty easy, except for the edge
That is, it's easy to extract the current month, day and year from even
the most rudimentary Linux version of
date, and it's obviously easy to
subtract one from the day, but what if it's the first of the month? Or
the first of the year?
That's doable too, but it's just a bit more work. Notably, you'll also want to know about leap years, because one day prior to March 1, 2016, might be February 28, or it might be February 29, depending on whether 2016 was a leap year.
Now a sneaky way to do it simply would be to sidestep the issue. If the day number of the month is greater than 1, subtract one to get yesterday's date. If it is the first, however, add one and reverse the logic of the waxing/waning test.
Fortunately, I do have the more sophisticated
program, so I'm going to do
that most frustrating of things and leave this particular facet as the
proverbial exercise for the reader.
Knowing the format of the Moon Giant URL when you specify a date, and
knowing how to use
date to get the numeric month, day and year
values for yesterday, here's some code to put that all together:
url_ago="http://www.moongiant.com/phase" eval $( date -v -1d +"mon=%m day=%d year=%Y" ) ydayurl="$url_ago/$mon/$day/$year"
The good news is that the resultant web page has the same format as the
page for today's illumination level too, so the same
explored in my last article can be reused for this task:
yillumlevel="$( curl -s "$ydayurl" | grep "$pattern" | tr ',' '\ ' | grep "$pattern" | sed 's/[^0-9]//g')"
In fact, let's add a debugging statement that displays both today's lunar illumination level and yesterday's level:
echo today\'s illumination level = $illumlevel and \ yesterday was $yillumlevel
Running it on November 7, 2016, here's what the script and the Moon Giant website report:
today's illumination level = 47 and yesterday was 37
Now it's a simple test: is today's level greater or less than yesterday's level?
But wait, "waxing" and "waning" applies only to crescent and gibbous moon phases. If the moon is new, quarter or full, neither word applies in common astronomical parlance.
Seriously, who came up with these rules? Talk about complicated!
Here's how this all fits together:
if [ $illumlevel -gt $yillumlevel ] ; then # we're waxing if it's getting brighter waxwane="waxing" else waxwane="waning" fi if [ $illumlevel -lt 5 ] ; then phasename="new" elif [ $illumlevel -lt 45 ] ; then phasename="$waxwane crescent" elif [ $illumlevel -lt 55 ] ; then phasename="quarter" elif [ $illumlevel -lt 95 ] ; then phasename="$waxwane gibbous" else phasename="full" fi echo "The moon is currently $phasename with \ $illumlevel% illuminated."
That's just about the entire script. If I run it on November 7, 2016, the moon is 47% illuminated, which makes it a quarter moon (45%–55%), so the output is:
The moon is currently quarter with 47% illuminated.
A few days later, on November 10, the output is what you would hope:
The moon is currently waxing gibbous with 78% illuminated.
Done. Nice and easy.Creeping Featurism
You could do plenty of things with this script to improve it and make it more powerful and flexible. The easiest would be simply to rewrite that output line so it's less grammatically awkward:
echo "It's a $phasename moon that's $illumlevel% illuminated."
Now the output will make a bit more sense as the script reports that "It's a waning gibbous moon that's 72% illuminated."
The bigger task is to allow users to specify a date and calculate the
values for that particular date (including the day prior to the date
specified). I would do this using the same basic
-v approach, but
first parse users' input and break it down into month, day and
year. For simplicity's sake, constrain their input to a MM/DD/YYYY
format, and there's surprisingly little involved in the task.
For huge bonus points, of course, a graphical display would be nice. But that's hard to do with a shell script, right?Next Article
That's it for space. Next article, I'm planning to turn back to games and explore how to write a rock, paper, scissors game. You might want to study the game first so you're ready!