views:

2230

answers:

5

Heylo,

I want to calculate (using the default Perl installation only) the number of days between two dates. The format of both the dates are like so 04-MAY-09. (DD-MMM-YY)

I couldn't find any tutorials that discussed that date format. Should I be building a custom date checker for this format? Further reading of the Date::Calc on CPAN it looks unlikely that this format is supported.

Thanks.

+1  A: 

You could convert the dates into the long integer format, which is the number of seconds since the epoch (some date in 1970 I think). You then have two variables that are the dates in seconds; subtract the smaller from the larger. Now you have a time span in seconds; divide it by the number of seconds in 24 hours.

lumpynose
The UNIX/C epoch is January 1, 1970 00:00:00 UTC.
R. Bemrose
This will give you the number of 86400-seconds blocks of time between two dates, which is not the same thing as the number of (calendar) days between two dates. (Okay, it's actually not even the same thing as 86400-second blocks either, due to leap seconds...)
John Siracusa
+2  A: 

Time::ParseDate will handle that format just fine:

use Time::ParseDate qw(parsedate);

$d1="04-MAR-09";
$d2="06-MAR-09";

printf "%d days difference\n", (parsedate($d2) - parsedate($d1)) / (60 * 60 * 24);
Michael Cramer
Time::ParseDate is not part of Core Perl
Chas. Owens
Obviously the mention of Date::Calc in the question implies CPAN's fair game.
Michael Cramer
The question also says "using default perl installation only"
Chas. Owens
+1  A: 

Date::Calc has Decode_Date_EU (and US etc)

#!/usr/bin/perl
use Date::Calc qw(Delta_Days Decode_Date_EU);

($year1,$month1,$day1) = Decode_Date_EU('02-MAY-09');
($year2,$month2,$day2) = Decode_Date_EU('04-MAY-09');

print "Diff = " . Delta_Days($year1,$month1,$day1, $year2,$month2,$day2);
Maupie
Date::Calc is not part of Core Perl
Chas. Owens
A: 

Convert the two dates to seconds and then do the math:

#!/usr/bin/perl

use strict;
use warnings;
use POSIX qw/mktime/;

{

    my %mon = (
     JAN => 0,
     FEB => 1,
     MAR => 2,
     APR => 3,
     MAY => 4,
     JUN => 5,
     JUL => 6,
     AUG => 7,
     SEP => 8,
     OCT => 9,
     NOV => 10,
     DEC => 11,
    );

    sub date_to_seconds {
     my $date = shift;
     my ($day, $month, $year) = split /-/, $date;

     $month = $mon{$month};
     if ($year < 50) { #or whatever your cutoff is
      $year += 100; #make it 20??
     }

     #return midnight on the day in question in 
     #seconds since the epoch
     return mktime 0, 0, 0, $day, $month, $year;
    }
}

my $d1 = "04-MAY-99";
my $d2 = "04-MAY-00";

my $s1 = date_to_seconds $d1;
my $s2 = date_to_seconds $d2;

my $days = int(($s2 - $s1)/(24*60*60));

print "there are $days days between $d1 and $d2\n";
Chas. Owens
+5  A: 

If you care about accuracy, keep in mind that not all days have 86400 seconds. Any solution based on that assumption will not be correct for some cases.

Here's a snippet I keep around to calculate and display date/time differences a few different ways using the DateTime library. The last answer printed is the one you want, I think.

#!/usr/bin/perl -w

use strict;

use DateTime;
use DateTime::Format::Duration;

# XXX: Create your two dates here
my $d1 = DateTime->new(...);
my $d2 = DateTime->new(...);

my $dur = $d1 > $d2 ? ($d1 - $d2) : ($d2 - $d1);

my $dur_abs = $d1 > $d2 ? 
  $d1->subtract_datetime_absolute($d2) :
  $d2->subtract_datetime_absolute($d1);

my $fmt = DateTime::Format::Duration->new(pattern => 
  '%Y years, %m months, %e days, %H hours, %M minutes, %S seconds');

print $fmt->format_duration($dur), "\n";

$dur = $d1->delta_md($d2);

my $dy = int($dur->delta_months / 12);
my $dm = $dur->delta_months % 12;
print "$dy years $dm months ", $dur->delta_days, " days\n";
print $dur->delta_months, " months ", $dur->delta_days, " days\n";
print $d1->delta_days($d2)->delta_days, " days\n";
John Siracusa