views:

464

answers:

6

What is a good Perl module (or good approach) that returns all the valid calendar dates between a start date and an end date?

For example, if I have 1/29/2009 as a start date and 2/3/2009 as an end date then I would like it to return an array of 1/30/2009, 1/31/2009, 2/1/2009, and 2/2/2009. There must be a good Perl module that already does this and accounts for leap years, months, but I can't find it.

Thanks for your suggestions!

+3  A: 

Package Date::DateCalc

Chris Ballance
+7  A: 

DateTime, I've used it many times and it can do pretty much anything you can think of with dates. It handles leap years, leap seconds, invalid dates/times, it can output dates in any format, it can compare, add, subtract, etc...

The only issue is that it might be overkill.

Ben S
Yes DateTime is the "canonical" date module. See datetime.perl.org
draegtun
+2  A: 

Date::Manip seems to be the canonical date module in Perl. It has a weird API, but it works. Here's an example of using the ParseRecur function to do what you want:

#!/usr/bin/perl
use warnings;
use strict;

use Date::Manip;
use Data::Dumper;

my ($start, $end) = qw(2009-01-29 2009-02-03);

# Exclude start date
$start = DateCalc($start, "+1 day");

# y:m:w:d:h:m:s
my @dates = ParseRecur('0:0:0:1:0:0:0', $start, $start, $end);

for my $date (@dates) {
    print UnixDate($date, "%Y-%m-%d\n");
}
vasi
Thanks! This works. This might be required depending on your environment.
NoahD
+3  A: 

Here's a stab. It requires Date::Simple and Date::Range:

#!/usr/bin/env perl
use strict;
use warnings;
use Date::Simple;
use Date::Range;

my $d1 = Date::Simple->new('2009-03-02');
my $d2 = Date::Simple->new('2009-03-07');

my $range = Date::Range->new( $d1, $d2 );

for my $date ($range->dates) {
  print $date->format("%m/%d/%Y"), "\n" # Fixed format
}
Telemachus
Nice! These modules have a much saner API than Date::Manip.
vasi
It's also significantly lighter than Date::Manip (or DateTime). It can't do everything that DateTime can do, but sometimes simple is better than complete.
Telemachus
A: 

Because of the neat power of POSIX::mktime, you could do the following:

use POSIX qw<mktime strftime>;

my ( $month, $day, $year )  = ( 8, 16, 2008 );
my $end_date   = mktime( 0, 0, 0, 1, 2 - 1, 2009 - 1900 );
while ( 1 ) { 
    my $date = mktime( 0, 0, 0, $day++, $month - 1, $year - 1900 );
    push @date_range, strftime( '%x', localtime $date );
    last if $date >= $end_date;
}

With mktime( 0, 0, 0, 500, 0, 108 ) has meaning. But then so does this mktime( 0, 0, 0, 0, 2, x ) for the last date of February for any year.

Axeman
+5  A: 

Here's an example using DateTime:

use strict;
use warnings;

use DateTime;

my $d1 = DateTime->new( month => 1, day => 29, year => 2009);
my $d2 = DateTime->new( month => 2, day => 3,  year => 2009);

while ($d1 <= $d2) {
  print $d1->strftime("%m/%d/%Y"),"\n";
  $d1->add(days => 1);
}
runrig