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!
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!
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!