Work the Shell

Planetary Age

Dave Taylor

Issue #261, January 2016

For his 120th column, Dave looks at time around the universe—programmatically, that is!

This marks my 120th column for Linux Journal. 120 times I've delved into the retro world of shell script programming. You've gotten ten years of my puns and wry asides—all available on the www.linuxjournal.com site for your reading pleasure!

At approximately 1,200 words/column that represents 144,000 words total. By comparison, Harry Potter and the Philosopher's Stone is 76,944 words. The Hobbit is 95,356 words, and Pride and Prejudice is 122,685. So there you have it. In those 144k words, I could have created a magical universe with an endearing young hero, or a different magical world with a plucky Hobbit adventurer (albeit reluctant adventurer), or I could have written about five daughters of marrying age, the charming Mr. Bingley and the haughty Mr. Darcy.

I have, of course, done none of those things. But on the bright side, I'm hoping you've been entertained while learning about shell script programming, programming techniques and how divide and conquer can help you solve even the most thorny of challenges. I'm sure Harry would approve!

This leaves me with the question: what should I do with the next ten years? That question's only slightly intimidating, of course, but given that UNIX is 45 years old (I'm using 1970 as the first launch date, back on an old PDP-7), and Linux is 24 years old (using 1991 as the date Torvalds begin developing his alternative to UNIX), there's still some time to go.

For this article, I thought it'd be fun to talk about space. Specifically, to write a script that would tell you what your age would be if you lived on one of the other planets in our solar system. So let's jump in!

Calculating Universe Age

Different planets revolve around the sun at different rates. Earth is easy. It takes the planet just a bit more than 365 days (a day being a full day/night cycle and based on the rotation of the planet) to circle the sun—an Earth year.

But what about the other planets? We could calculate day-length and then number of days for each planet's “native” orbit, but it's more fun to have this be based on Earth days, although when we get to Pluto (yeah, I still consider it a planet), it's rather a long time.

Here's the data, in 24-hour Earth days:

Mercury	87.96
Venus	224.68
Earth	365.26
Mars	686.98
Jupiter	11.862 years
Saturn	29.456 years
Uranus	84.07 years
Neptune	164.81 years
Pluto	247.7 years

We will need to convert the last five into Earth days, but that's easy: just multiply by 365.26 (to be accurate), which gives us this better reference chart, presented as variables ready for a script:

mercury=87.96
venus=224.68
earth=365.26
mars=686.98
jupiter=4332.71412
saturn=10759.09856
uranus=30707.4082
neptune=60198.5006
pluto=90474.902

It sure takes a while for Pluto to circle our solar system, doesn't it? It's 90,474 days.

For this script, we'll want users to enter their birthdays, calculate how many days it's been since they were born, then simply divide that number by the “year” on each planet to calculate their universe ages.

I've actually written about how to calculate days between a specific date in the past and the current day, but rather than show the exhaustive calculation, let's just lean on the date function—more specifically GNU date. It's quite likely what you have on your computer already, and you can find out simply by typing:

>
$ date --version
date (GNU coreutils) 8.23
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and 
redistribute it. There is NO WARRANTY, to the 
extent permitted by law.

This is on the latest version of Ubuntu. Sadly, I'm going to be leaving you Mac users who have become accustomed to working with my scripts in the dust this time. Unfortunately, Mac OS X still ships with the older POSIX version of date and therefore has no date math available. With GNU date, however, it's super easy to calculate the number of days you've been alive. Let's assume you, like me, were born on August 3, 1965 (my birthday, plus or minus a year or three). How many days have I been alive?

The one-liner:

daysalive=$(( ( $(date -ud 'aug 3 1965' +'%s') - 
 ↪$(date -u +'%s') )/60/60/24 ))

This has my birthday hard-coded, probably not what we want, so instead it could be modified to work with user input, as a first step toward actually creating a script:

$ cat planetaryage.sh 
#!/bin/sh
daysalive="$(( ( $(date -ud "$*" +'%s') - 
 ↪$(date -u +'%s') )/60/60/24 ))"
echo "Born on $* means you've been alive $daysalive days."
exit 0
$ sh planetaryage.sh aug 3 1965
Born on aug 3 1965 means you've been alive -18354 days.

Negative days. It seems like something you'd get out of an old Night Gallery show or perhaps Black Mirror, to be a bit more contemporary. But why? Because we're subtracting the current date from the day in the past, not vice versa.

Flipping the math around in the equation solves the problem and gets the desired result:

Born on aug 3 1965 means you've been alive 18354 days.

Now the rest of the script is quite easy, particularly since we've already translated each and every planet's orbital duration into Earth days. To demonstrate, 18,354 Earth days would make me 26.71 (18354 / 686.98) Martian years old.

Here's the full script:

$ cat planetaryage.sh 
#!/bin/sh

mercury=87.96; venus=224.68; earth=365.26
mars=686.98; jupiter=4332.71412; saturn=10759.09856
uranus=30707.4082; neptune=60198.5006; pluto=90474.902

planetaryAge()
{
  orbit=$1
  planetname=$2
  planetarydays=$( echo "scale=5;$daysalive / $orbit"|bc )
  echo "You are $planetarydays $planetname years old."
}

daysalive="$(( ( $(date -u +'%s') - 
 ↪$(date -ud "$*" +'%s') )/60/60/24 ))"

planetaryAge $mercury "Mercury"
planetaryAge $venus   "Venus"
planetaryAge $earth   "Earth"
planetaryAge $mars    "Mars"
planetaryAge $jupiter "Jupiter"
planetaryAge $saturn  "Saturn"
planetaryAge $uranus  "Uranus"
planetaryAge $neptune "Neptune"
planetaryAge $pluto   "Pluto"

exit 0

It's actually not too complicated. When I run it for my own birthday, I find out I'm quite a spring chicken on Neptune:

$ sh planetaryage.sh aug 3 1965
You are 208.66302 Mercury years old.
You are 81.68951 Venus years old.
You are 50.24913 Earth years old.
You are 26.71693 Mars years old.
You are 4.23614 Jupiter years old.
You are 1.70590 Saturn years old.
You are .59770 Uranus years old.
You are .30489 Neptune years old.
You are .20286 Pluto years old.

What about duration since the signing of the Declaration of Independence? Those numbers are a bit more interesting:

$ sh planetaryage.sh july 4 1776
You are 993.79263 Mercury years old.
You are 389.05999 Venus years old.
You are 239.31993 Earth years old.
You are 127.24387 Mars years old.
You are 20.17534 Jupiter years old.
You are 8.12465 Saturn years old.
You are 2.84667 Uranus years old.
You are 1.45209 Neptune years old.
You are .96616 Pluto years old.

Ah, it was almost one Plutonian year ago. It's simple enough once you know the mathematical capabilities of GNU date, for sure. Without it, you definitely can cobble together a script that can calculate the number of days since a specified date in the past, but we've done that before!

Next Month

Now is a golden opportunity, as we head into our next decade of this column, for you to send in some puzzles, ideas or topics you'd like me to cover here (send e-mail to info@linuxjournal.com). Don't be shy!

Dave Taylor has been hacking shell scripts since the dawn of the computer era. Well, not really, but still, 30 years is a long time! He's the author of the popular Wicked Cool Shell Scripts and Teach Yourself Unix in 24 Hours (new edition just released!). He can be found on Twitter as @DaveTaylor and more generally at his tech site: www.AskDaveTaylor.com.