Monday, September 1, 2008

Date manipulation in perl.

Hello~

I ran across, a small problem while coding in Perl the other day.
I wanted yesterdays, date to do some calculations. The way I went about it was as follows:



use Time::localtime;
$tm=localtime;
$yesterdaysDate=sprintf("%04d-%02d-%02d",$tm->year+1900, ($tm->mon)+1, ($tm->mday)-1);



This is what I am trying to accomplish here, I create a reference to an object that holds date related data like year, month, day etc.
The above code, gets yesterdays date by: ($tm->mday)-1, which basically negates 1 day from todays date. So if it is say 30th August today, the variable will hold the date component as 29th.

All looks hunky and dory here, but looking a bit more carefully we realize there is a big bug; What happens at the start of every month, also the start of every year.

Say, today is 1st January 2009.
The variable $yesterdaysDate after negation, will hold the following info, 2007-1-0, which is meaningless, what we wanted was, 2006-12-31.

So what is the solution, there are basically 2 solutions:

One the really hard one involving tons of if else loop, checking for all boundary condition, I will not discuss this solution. In my opinion everyone can figure it out.
The second solution uses a concept called epoch time. It is the time in seconds that have passed since some reference day in the year 1970.
This is how we modify the above program to make it function correctly.


use Time::localtime;
$yesterday = time() - (24 * 60 * 60 );
$tm=localtime($yesterday);
$yesterdaysDate=sprintf("%04d-%02d-%02d",$tm->year+1900, ($tm->mon)+1, ($tm->mday));



As you can see, that has been done here is that we use a function time(), from perl base lib, which return to us the number of epoch seconds that have passed till now. Once we get that, all we do to get yesterdays date is to negate (24*60*60) seconds from it and pass this as the in parameter to the localtime() function. This fixes all the issues that I put forth in the start of the post.

No comments: