thunders has asked for the wisdom of the Perl Monks concerning the following question:

I wrote a program to find out how many years old a person would be were they born and raised on another planet with a different rotational period. Anyway, as implemneted here It chokes on any date before 1970, because it uses timelocal from the Time::Local module. Am I using that function wrong, or should I do this with a different module?
#!/usr/bin/perl -w #mercury.pl-how old am I in Mercury Years. use Time::localtime(); #for ctime use Time::Local; #for timelocal use POSIX; #for floor #length of Mercury year in earth days $mercuryRevolution = 87.97; #get birthday stats for Oct 1, 1977 $birthDay = 1;$birthMonth=9;$birthYear=77; $birthTime = timelocal(0,0,0,$birthDay,$birthMonth,$birthYear); $currentTime = time(); $timeAlive = $currentTime - $birthTime; $daysAlive = POSIX::floor($timeAlive / (24 * 60 * 60)); $mercuryYears = POSIX::floor($daysAlive / $mercuryRevolution); $nextMercuryBday = $daysAlive % $mercuryRevolution; $nextBirthDate = ctime(time()+ ($nextMercuryBday *24*60*60)); #strip hours,minutes,seconds from ctime string $nextBirthDate =~ s/(\w+\s\w+\s\d+)(\s\S+\s)(\w*)/$1,$3/; print "\nYou are ".$mercuryYears." Mercurian Years old", "\nYour next Mercurian Birthday is in " . $nextMercuryBday . " days\n", "on ". $nextBirthDate

Replies are listed 'Best First'.
Re: Older people should know their age on Mercury
by lhoward (Vicar) on Oct 03, 2001 at 00:37 UTC
    Time::Local and many of the "unix based" time functions base their time as "number of seconds since Jan 1, 1970". If you want a greater range, use Date::Calc which is good back to the year 1 AD.
      Thanks a lot. That module was what I was looking for.
      I'll post my solution on this node.
Re: Older people should know their age on Mercury
by thunders (Priest) on Oct 03, 2001 at 02:27 UTC
    I was able to make this work with Date::Calc. Like so:
    #!/usr/bin/perl -w #mercury.pl-how old am I in Mercury Years. use Time::localtime qw(localtime);#also for ctime use POSIX; #for floor use Date::Calc qw(Delta_Days); #length of Mercury year in earth days $mercuryRevolution = 87.97; #get birthday stats for Oct 1, 1977 $birthDay = 1;$birthMonth=9;$birthYear=1977; $daysAlive = Delta_Days($birthYear,$birthMonth,$birthDay, localtime->year()+1900,localtime->mon(), localtime->mday()); $mercuryYears = POSIX::floor($daysAlive / $mercuryRevolution); $nextMercuryBday = $daysAlive % $mercuryRevolution; $nextBirthDate = ctime(time()+ ($nextMercuryBday *24*60*60)); #strip hours,minutes,seconds from ctime string $nextBirthDate =~ s/(\w+\s\w+\s\d+)(\s\S+\s)(\w*)/$1,$3/; print "\nYou are ".$mercuryYears." Mercurian Years old", "\nYour next Mercurian Birthday is in " . $nextMercuryBday . " days\n", "on ". $nextBirthDate;
    It's a shorter program and it would even work for Dracula, now.
      Yes, that is a better way of doing it, except that Date::Calc is 1-based in it's months instead of 0-based, So if you wanted to find out for a person born in October, you would need to set $birthMonth to 10.

      I find that to be an annoying feature of Date::Calc. That and the way it sets up the days of the week as (1..7) = (Monday .. Sunday). The pod sites all sorts of ISO specs that say this is the way it should be. Unfortunately, localtime and timelocal don't agree. This means an enormous opportunity for off-by-one errors if you need to switch back and forth.
        This 0..11 rang for months is a wart inherited from C. I am amazed it is still there in Perl 5. Same thing for year 101 instead of 2001. Fortunately, most modules have correct ideas about date elements. Fortunately too, there is RFC 48 for Perl 6, that will fix the warts.
        You are correct. It seemed to work until I put in 0 for a January date. That's an invalid argument for the Delta_Days function. which means I also have to add one to localtime->mon() as well. Cause the Time::localtime module starts it's indices at zero. Quite Inconsistent. Thanks.