Perl Quiz-of-the-Week #15

Mark Jason Dominus <[email protected]> Wed, 18 Jun 2003 22:25:41 -0400
Newsgroups gmane.comp.lang.perl.qotw.quiz-of-the-week
Organization Plover Systems
Message-ID <[email protected]>
IMPORTANT: Please do not post solutions, hints, or other spoilers
        until at least 60 hours after the date of this message.
        Thanks.

IMPORTANTE: Por favor, no enviéis soluciones, pistas, o cualquier otra
        cosa que pueda echar a perder la resolución del problema hasta
        que hayan pasado por lo menos 60 horas desde el envío de este
        mensaje. Gracias.

IMPORTANT: S'il vous plaît, attendez au minimum 60 heures après la
        date de ce message avant de poster solutions, indices ou autres
        révélations. Merci.

WICHTIG: Bitte schicken Sie keine Lösungen, Tipps oder Hinweise für
        diese Aufgabe vor Ablauf von 60 Stunden nach dem Datum dieser
        Mail. Danke.

BELANGRIJK: Stuur aub geen oplossingen, hints of andere tips in de
        eerste 60 uur na het verzendingstijdstip van dit
        bericht. Waarvoor dank.

VNIMANIE: Pozhalujsta ne shlite reshenija, nameki na reshenija, i
        voobshe lyubye podskazki v techenie po krajnej mere 60 chasov
        ot daty etogo soobshenija.  Spasibo.

Qing3 Zhu4Yi4: Qing3 Ning2 Deng3Dao4 Jie1Dao4 Ben3 Xin4Xi2 Zhi1Hou4 60
        Xiao3Shi2, Zai4 Fa1Biao3 Jie3Da2, Ti2Shi4, Huo4 Qi2Ta1 Hui4
        Xie4Lou4 Da2An4 De5 Jian4Yi4.  Xie4Xie4.

----------------------------------------------------------------

About six months ago, Pr. Kevin Pfeiffer suggested:

        I need to send you more details (when I have the book in hand)
        but there was a method of timekeeping once that divided the
        day and night each into 12 equal "hours". So at the equinoxes
        each hour was 60 minutes long (as we know them), but in winter
        for example, a "day hour" might last thirty of our minutes and
        a "night hour" might last two of our hours.

        I like this idea (it seems to fit the reality better - esp. at
        the time of the winter solstice) and think it would be nice to
        be able to experience this way of telling time.

        Hence a program that emulates this time clock and tells me at
        16:00 that it's already "midnight" (or close to it). To do
        this I suppose you would have to know high noon and midnight
        for each day; then it should be easy to take these two periods
        and divide them into 12 equal periods each (and then 60 minute
        periods, etc.).

I thought that was a great idea.  So that's what we'll do.  We'll
introduce a new daily calendar with the following labels:


     Midnight        Sunrise         Noon            Sunset          Midnight
     |               |               |               |               |
     0000            0600            1200            1800            2400


and write a program to print out the normal civil time of day and also
the time of day in this new calendar.  0100 in this new calendar will
no longer mean "exactly 3600 seconds after midnight."  Instead, it'll
mean "exactly 7/12 of the way between sunset and sunrise."  This will
be more time in the winter, and less in the summer.  

I liked this suggestion, but it seemed difficult.  I said to Kevin
that the problem with that is that it's very tricky to calculate when
sunrise and sunset occur.  But then I realized that it doesn't have to
be so tricky, if you're willing to cut a few corners.  Here's how.

First, we'll assume that noon is at exactly 1200 and midnight is
exactly at 0000 every day.  (By "noon" I obviously mean the time when
the sun is exactly overhead, not when the clock shows 1200.)  This
isn't too far off the truth anyway.

The equinoxes are the two days of the year when the daytime and
nighttime are almost exactly 12 hours each; this is why they're called
'equinoxes'.  So on the equinoxes, the sun will rise at about 0600 and
will set at about 1800.  This also isn't too far off the truth.

With these assumptions, it turns out to be easy to calculate the
approximate time of sunrise on any day of the year.  You only need to
know two magic numbers, and then do this:

        sunrise = 0600 + A * sin(2*pi * d/365.2522)

pi, of course, is 3.1416 or so.  d is the number of days that have
elapsed since the vernal (spring) equinox.  The vernal equinox is
around 19 March in the northern hemisphere, and around 19 september in
the southern hemisphere, and if you care you can look it up a more
accurate value on the web.  A is a magic number that depends on your
latitude.

The sticking point is the 'magic number' A.  How do we calculate A?
There's probably some way to calculate it directly from the latitude,
but I don't know what that is.  (I failed observational astronomy
twice in college.)  But there's another trick we can use.  If you
happen to know the time of sunset on the summer solstice (the longest
day of the year) you can calculate A easily:

        A = (time of sunset on summer solstice) - 1800

Or, if your local civil calendar includes a one-hour "daylight
savings" or "summer time" adjustment, 

        A = (time of sunset on summer solstice) - 1900

Great.  Does this really help?  After all, nobody except astronomy
freaks will "happen to know the time of sunset on the summer
solstice".

But wait!  The summer solstice is this week, so if you just look out
the window as the sun is going down, and then look at the clock, you
will know the time of sunset on the summer solstice.  Even if you
don't have a window, you can look in the weather section of your local
daily newspaper, which will tell you what time the sun will set that
day, and that is the time of sunset on the summer solstice.

(People in the southern hemisphere should replace 'summer' with
'winter' in the foregoing, and let A = 1800 - (time of sunset on
winter solstice), since everything there is upside down.)

Now here's this week's quiz:

Write a program, "greektime", which prints out the current time in the
usual format and in the 'Greek' format.  

The 'Greek' format divides the daytime into twelve equal "Greek
hours", each of which is divided into 60 equal "Greek minutes";
similarly the nighttime is divided into 12 hours of 60 minutes each.

In 'Greek' time, sunrise always occurs at exactly "0600" and sunset is
always at exactly "1800". 

So, for example, right now the clock says it is 2115 local civil time.
In Philadelphia at this time of year, the nighttime runs from about
2030 (sunset) to about 0530 (sunrise).  (Notice that the middle of
this period is 0100, not 0000 as it should be; that's because of the
DST adjustment.)  The entire nighttime is about 9 hours = 540 minutes
long, so each "Greek hour" is 540 / 12 = 45 minutes long.  At 2115,
we've therefore just finished the first of the 12 nighttime hours, so
the "Greek" time is 1900, one hour past sunset.  The program should
print out

           Civil time: 21:15
           Greek time: 19:00

If it's a little later, the display will be:

           Civil time: 21:55
           Greek time: 19:54

It's after sunset in the summertime, so the 'Greek' time advances
faster than the civil time, because at night the Greek hours are
shorter than the civil hours.  Each Greek hour is divided into 60
Greek minutes, of course.  If it were exactly the time of sunset, the
output would be

           Civil time: 20:30
           Greek time: 18:00

Your program should also support command-line arguments and options as
you think useful and appropriate.

If you live north of the Arctic Circle or south of the Antarctic
Circle, none of this will make sense for you.  You then have at least
two options:

        a) Pretend you live somewhere less awful, or
        b) Ignore the quiz and spend this week huddling in your igloo.

My thanks to Pr. Pfeiffer for this excellent suggestion.