Date Math in Perl

Man, I hate doing date math in any language…

Anyway, I need to take today’s date and add 45 days to it. If that 45th day is after the 25th of any given month, I need to “round up” to the 1st of the next month.

I’m just starting to write some code now, so I don’t have something for you to look at. Mostly, I’m hoping I don’t have to re-invent the wheel here.

This is for an insurance quoting app, btw. Not homework. :slight_smile:

Thanks!

Here’s what I have so far. So, when the $day is greater than 25, I could increment the $month and set $day to 1, but then I’d have to be careful of December. So, if after adding 1 to $month, if it is greater than 12, set it to 1 and increment the year.

Am I making this harder than it needs to be or am I on the right track?

Thanks!


my $time = time();

my $future_time = $time + (45 * 24 * 60 *60);

my ($second, $minute, $hour, $day, $month, $year, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime($time);
my ($fsecond, $fminute, $fhour, $fday, $fmonth, $fyear, $fdayOfWeek, $fdayOfYear, $fdaylightSavings) = localtime($future_time);

$year += 1900;
$fyear += 1900;

print "$month/$day/$year\
";
print "$fmonth/$fday/$year\
";

Here’s my completed script:


my $time = time();

my $future_time = $time + (45 * 24 * 60 *60);

my ($second, $minute, $hour, $day, $month, $year, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime($time);
my ($fsecond, $fminute, $fhour, $fday, $fmonth, $fyear, $fdayOfWeek, $fdayOfYear, $fdaylightSavings) = localtime($future_time);

$month += 1;
$fmonth += 1;

$year += 1900;
$fyear += 1900;

print "$month/$day/$year\
";
print "$fmonth/$fday/$fyear\
";

if($fday > 25){
  $fmonth += 1;
  $fday = 1;
  
  if($fmonth > 12){
    $fmonth = 1;
    $fyear += 1;
  }
}

if($fmonth < 10){
  $fmonth = "0" . $fmonth;
}

if($fday < 10){
  $fday = "0" . $fday;
}

print "$fmonth/$fday/$fyear\
";

Is it working OK?

Yeah, actually it works pretty slick. I made some minor updates. I changed the += 1 to a ++ for a few variables.

I liked doing the math on the results of the time() function. That was actually easier than I expected.

I’m glad that you got it working. Do you have any aversion to me using it? :shifty:
I would modify it for dates in the past.
You noted some minor changes . Do you have the completed (and final) code?

Use it!

Here’s the final code, but its not significantly different then what I posted. I removed my print statements. Those were just for testing. At the end, I assign the date to variable that used later in the full script.


my $time = time();
my $future_time = $time + (45 * 24 * 60 *60);
my ($second, $minute, $hour, $day, $month, $year, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime($time);
my ($fsecond, $fminute, $fhour, $fday, $fmonth, $fyear, $fdayOfWeek, $fdayOfYear, $fdaylightSavings) = localtime($future_time);
	
$month++;
$fmonth++;
	
$year += 1900;
$fyear += 1900;
	
if($fday > 25){
  $fmonth++;
  $fday = 1;
		
  if($fmonth > 12){
    $fmonth = 1;
    $fyear++;
  }
}
	
if($fmonth < 10){
  $fmonth = "0" . $fmonth;
}
	
if($fday < 10){
  $fday = "0" . $fday;
}
	
my $effective_date = "$fmonth$fday$fyear";

same thing using other methods:

my ($day, $month, $year) = (localtime(time + (45 * 24 * 60 *60)))[3,4,5];

my &#37;months = (
   '0'  => '02',
    1  => '03',
    2  => '04',
    3  => '05',
    4  => '06',
    5  => '07',
    6  => '08',
    7  => '09',
    8  => '10',
    9  => '11',
   10  => '12',
   11  => '01'
);

my $effective_date = ($day > 25) ?
                     sprintf('%02d%02d',$months{$month},1) . ($year+=1900) :
                     sprintf('%02d%02d',$month,$day) . ($year+=1900);

print $effective_date;

I wonder if anyone on this forum actually knows Perl?

Add 45 days to the current date, and if the result is the 25th or later of a month, skip to the 1st of the next month:


use DateTime;    # include the DateTime module in our script

my $dt = DateTime->now( time_zone => 'floating' );    # create a DateTime object set to the current date and time, with no particular timezone

$dt->add( days => 45 );    # add 45 days

if ($dt->day >= 25)    # see if the date is the 25th or later
{
    $dt->set_month( $dt->month + 1 );    # set the month to it's current value plus 1
    $dt->set_day( 1 );    # set the day to the 1st
}

Ta! Simple.

Personally I don’t like to post suggestions that require a non-core module unless there is clear benefit, which your code does not provide, it is just a different way to do the same thing.

The clear benefit is that it provides a single point of entry to the data and insures correct calculation of complex date arithmetic, and takes advantage of the expressive power of Perl. The other examples listed here are error prone, unobvious, and make the sleek Ferrari that is Perl look like a jalopy.

if you say so. :lol:

Actually I would use excellent Date::Manip module for this…

use Date::Manip;
my $date = “2007-08-20”;
my $date2 = UnixDate(DateCalc($date,“+ 45 days”,\$err),“%Y-%m-%d”);

if (UnixDate($date2,“%d)> 25) {
$enddate = UnixDate(DateCalc($date2,”+ 10 days",\$err),“%Y-%m-”).“01”;
} else {
$enddate = $date2;
}
print "The date you are looking for is “.$enddate.”
";