Incrementing a Date in Perl

Album Cover: Abbey Road

"She's killer-diller when she's dressed to the hilt."
The Beatles / Polythene Pam

Posted on October 10, 2006 11:45 PM in Programming
Warning: This blog entry was written two or more years ago. Therefore, it may contain broken links, out-dated or misleading content, or information that is just plain wrong. Please read on with caution.

Anyone who's done anything with dates in Perl knows it involves a lot more elbow grease than doing the same thing in a language like PHP. The main reason for this is that in Perl you get to deal with all the various components of a date/time separately...so you end up populating a bunch of variables like so:

($s, $m, $h, $day, $mon, $year, $dow, $doy, $dst) = localtime();

You've then gotta deal with all the geeky date concepts like days of the week ranging from 0-6 or the year actually being the year minus 1900. So, to avoid getting into any other superfluous details, it involves a lot of work and almost always requires a bit of a refresher when you've stepped away from the code for a few months.

So let's say you want to go beyond just the normal date/time manipulation and actually increment on a date until you find a date in the future (or the past) and then work with that date. How do you do it?

Well, as with any good programming/scripting language, there are multiple ways, and each way has its pros and cons. I usually go with the first way because I like to just get things done, but it just so happens that this time around I was forced into learning two separate ways, so I'll describe them here.

One option is to use the Date::Simple module. To get a handle on today's date with Date::Simple, you can do something like the following:

use Date::Simple ('date', 'today');

$day = today();

print "Today's date is $day.";

Pretty simple, right? If you want to then increment on that date and stop when you've reached next Tuesday (in Perl, Tuesday is represented numerically as 2), you add the following:

$counter = 1;

while ($day->day_of_week != 2)
{
  $day = today() + $counter;
  $counter++;
}

print "Next Tuesday's date will be $day.";

Now let's say the Date::Simple approach works fine-and-dandy on your local machine, but for some reason you can't get the module to compile or run on the remote server you wish to execute your script on. What do you do? Well, luckily, there is another option: Date::Calc.

In Date::Calc, the approach is similar, but the code and function calls are different enough to warrant more code samples:

use Date::Calc qw(Today Day_of_Week Add_Delta_Days);

($year, $month, $day) = Today();

while (Day_of_Week($year, $month, $day) != 2)
{
  ($year, $month, $day) = Add_Delta_Days($year, $month, $day, 1);
}

At this point, you've got yourself values for $year, $month and $day that match up with the expected values for next Tuesday. However, if you wish to print them in a format like 2006-10-10, you need to do some of the usual number padding you've grown accustomed to when working with dates in Perl:

$start = $year."-";
$start .= (length($month) < 2) ? "0".$month : $month;
$start .= "-";
$start .= (length($day) < 2) ? "0".$day : $day;

print "Next Tuesday's date will be $start.";

So there you have it. Two options for incrementing dates in Perl. And before you ask, no, I didn't just do this for the heck of it. This is an actual problem I ran into and had to solve in order for me to get my New Releases Web Feed up-and-running again after Amazon made some changes to their site and URI structure.

Just for fun, we can look at the PHP equivalent to these for a quick lesson on how to choose the right programming language for the job:

print("Next Tuesday's date will be ".date("Y-m-d", strtotime("next Tuesday")));

This whole incrementing dates concept seems pretty obscure, but I have a feeling there are people out there doing or attempting to do the same thing. If you're one of those people and manage to stumble upon this post, please leave a comment and let me know what exactly you're working on.

Comments

Peter on March 25, 2008 at 6:13 AM:

What if Date::Calc is not on remote server either?

Permalink

Sravanth on August 03, 2009 at 11:30 AM:

Hi sir,
here my requriment is to find the next month and assigne that to a variable so that i can use it in a shall script.
and the most important thing is that the value of the next month should be in both "numedrical and verbal"

Sravanth

Permalink

Sivarama Raju on October 22, 2009 at 7:35 AM:

Hi,

I work on HP Data Protector. I have a script which I run once every week which automates Backup Tape ejects.

Before doing ejects, it will provide me with a list of tapes and the data protection date.

The data Protection date will tell me when I need to re-insert the tape as a scratch tape, back into the tape Library.

Now, I am want to increment/decrement this protection date to the nearest Tuesday or Friday.

The examples you provided above are good. But the problem is I dont have the module on the remote server.

I wanted to know if there is any other way by which I can accomplish this. Any other module which is present everywhere?

Please help me.

Thanks and regards,
Sivarama Raju

Permalink

peter_retep on August 25, 2011 at 9:04 AM:

use DateTime module:

use DateTime;
print DateTime->now()->add(days=>((9-DateTime->now()->day_of_week())%7))->ymd()."n"';

Permalink

Post Comments

If you feel like commenting on the above item, use the form below. Your email address will be used for personal contact reasons only, and will not be shown on this website.

Name:

Email Address:

Website:

Comments:

Check this box if you hate spam.