Time-Related Things I Never Want to See In A Perl Script Again

Time-Related Things I Never Want to See In A Perl Script Again

I got stuck debugging someone else’s Perl code today, and it was chock-full of the sorts of things that annoy the piss out of those of us who know better.

$date = `date +%Y-%m-%d`;

Perl isn’t the Bourne shell, you know. It’s a pretty complete programming language. It can tell time. Look up localtime, which returns the time either as a human-readable string, or as a conveniently parsed array with year, month, day, hour, minute, second, and everythng, depending on whether you call it as

$date = localtime;

or

@time_elements = localtime;

Or try gmtime if you want universal time.

If you want the time and/or date in a particular format, e.g., if you want a file with a date in the filename, like “logfile-2006-03-15”, there’s the POSIX module:

use POSIX;

$log_file_name = strftime("logfile-%Y-%m-%d", localtime);

(Notice how conveniently strftime takes the same arguments that localtime returns.)

Okay, but what if you had just collected statistics about yesterday’s events (e.g., web server statistics), and wanted to put them in a log file with yesterday’s date? You might think the easiest thing to do is to call localtime and subtract one from the day number.

And subtract one from the month number if today is the first of the month. And subtract one from the year number if today is January 1st. And figure out how many days were in the last month, and whether it was February on a leap year.

There’s a simpler way: time returns the number of seconds since the Unix Epoch, Jan. 1, 1970 at midnight. There are 60 * 60 * 24 = 86400 seconds in a day. So 86400 seconds ago was yesterday. The time-related functions in the POSIX module were written by clever people who took the time to figure out the best way to convert a Unix time to year, month, day, etc. So you can just create your filename with:

use POSIX;
$log_file_name = strftime("logfile-%Y-%m-%d", localtime(time - 86400));