nejcPirc has asked for the wisdom of the Perl Monks concerning the following question:

Hello!

How can I increase date in a loop if i have a starting date for example: $start_date="2005-07-12" and my $end_date="2005-08-03"

Output should be:
2005-07-12
2005-07-13
2005-07-14
2005-07-15
2005-07-16
...
2005-08-03

Thanks!

Replies are listed 'Best First'.
Re: How to increase date in a loop
by holli (Abbot) on Jul 28, 2005 at 09:47 UTC
    use a Date module.


    holli, /regexed monk/
Re: How to increase date in a loop
by davorg (Chancellor) on Jul 28, 2005 at 11:29 UTC

    If you want to use a module then look at DateTime or one of its friends (see http://datetime.perl.org/). Please don't use Date::Manip as it's rather old and slow.

    However, it's quite possible to do simple data manipulation like this without using CPAN modules.

    #!/usr/bin/perl use strict; use warnings; use Time::Local; use POSIX 'strftime'; my $start = date2epoch('2005-07-12'); my $end = date2epoch('2005-08-03'); my $curr = $start; while ($curr <= $end) { print strftime "%Y-%m-%d\n", localtime($curr); $curr += 24 * 60 * 60; } sub date2epoch { my ($y, $m, $d) = split /-/, shift; return timelocal(0, 0, 12, $d, $m - 1, $y - 1900); }
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: How to increase date in a loop
by anonymized user 468275 (Curate) on Jul 28, 2005 at 10:02 UTC
    Date::Manip has all you need. Here is an untested sketch of why:
    use Date::Manip; my $err; for ( my $mydate = '2005-07-12', my $theirdate = ParseDate($mydate); $mydate le '2005-08-03'; $theirdate = DateCalc( $theirdate, '+ 1days', \$err ) or die $err ) { $mydate = &UnixDate( $theirdate,"%y%-%m%-%d"); # now $mydate is ready for use in this loop }

    One world, one people

Re: How to increase date in a loop
by davidrw (Prior) on Jul 28, 2005 at 12:15 UTC
    Here's an example solution (including error checking) using the Date::Calc module:
    my $start_date = "2005-07-12"; my $end_date = "2005-08-03"; use Date::Calc qw/Delta_Days Add_Delta_Days check_date/; my @start_date = split /-/, $start_date; my @end_date = split /-/, $end_date; die "Bad start date" unless check_date(@start_date); die "Bad end date" unless check_date(@end_date); die "bad order" unless Delta_Days(@start_date, @end_date) >= 0; my @d = @start_date; while( Delta_Days(@d, @end_date) >= 0 ){ printf "%04d-%02d-%02d\n", @d; @d = Add_Delta_Days(@d, 1); }
Re: How to increase date in a loop
by Zucan (Beadle) on Jul 28, 2005 at 19:24 UTC
    I don't use any of the Data modules, and do not know how good they are... but I hope they would be fine to use for what you are doing.

    However, I am a little concerned about some of the other suggestions, such as adding 86400 seconds to the current day, etc. The problem is with how our calendar works. Do you properly take into account leap-years with Feb 29th? Do you properly take into account that a time change may actually make a day last 23 hour or 25 hours (in which case, adding 86400 isn't enough to give you the next day)?

    I have fought with these issues myself, and being a minimalist (as in, it is easier to run my code on any machine if I didn't have to install a bunch of perl modules prior to running the program), I settled on converting my dates to Julian dates and back again. The advantage of Julian dates is that your date is converted to an integer, and can then be operated on using normal math. When you need a real date, just convert the julian date back...

    ### ## Convert a YYYY-MM-DD date to a Julian date ### sub date_to_julian ( $ ) { my $date = shift @_; my $y = substr($date, 0, 4); my $m = substr($date, 5, 2); my $d = substr($date, 8, 2); my $j = int((1461 * ($y + 4800 + int(($m - 14) / 12))) / 4) + int((367 * ($m - 2 - 12 * int((($m - 14) / 12)))) / 12) - int((3 * int((($y + 4900 + int(($m - 14) / 12)) / 100))) / 4) + $d - 32075; return $j; } ### ## Convert a Julian date to YYYY-MM-DD date ### sub julian_to_date ( $ ) { my $j = shift @_; my ($l, $n, $i, $d, $m, $y); $l = $j + 68569; $n = int((4 * $l) / 146097); $l = $l - int((146097 * $n + 3) / 4); $i = int((4000 * ($l + 1)) / 1461001); $l = $l - int((1461 * $i) / 4) + 31; $j = int((80 * $l) / 2447); $d = $l - int((2447 * $j) / 80); $l = int($j / 11); $m = $j + 2 - (12 * $l); $y = 100 * ($n - 49) + $i + $l; return sprintf("%04d-%02d-%02d", $y, $m, $d); } ### ## Print all the dates between a start and end date ### my $start_date = date_to_julian("2005-07-12"); my $end_date = date_to_julian("2005-08-03"); for (my $i = $start_date; $i <= $end_date; $i++) { print julian_to_date($i), "\n"; }

    The information on Julian calendars was found by doing an ordinary Google search. The formulas were gleaned from one of the sites I found. There are two types of formulas, one that operates on just dates, and another that includes the hours/minutes/seconds. I am using the simpler date-only version of the formulas.

    Hope that helps!
    Zucan

      Thanks to all of you.....
Re: How to increase date in a loop
by Anonymous Monk on Jul 28, 2005 at 13:36 UTC
    You need the magical constant '86400':
    #!perl -l use strict; use warnings; use constant NEXT_DAY => 86400; for (1 .. 10) { print sleep NEXT_DAY ? scalar localtime : (); }
Re: How to increase date in a loop
by umbra (Acolyte) on Jul 28, 2005 at 14:54 UTC
    I not view existing answers because I know there is a lot of
    smart (at least) guys around. My answer uses only
    standart modules but is a few clumsy.
    use strict; use Time::Local; my $start_date = '2005-07-12'; my $end_day = '2005-08-03'; my @start_date_list = split /-/, $start_date; my @end_day_list = split /-/, $end_day; my $start_day_num = timelocal(0, 0, 0, int($start_date_list[2]), int($ +start_date_list[1]), int($start_date_list[0])); my $end_day_num = timelocal(0, 0, 0, int($end_day_list[2]), int($end_d +ay_list[1]), int($end_day_list[0])); my $count = ($end_day_num - $start_day_num)/86400; for my $day (0..$count){ my (undef, undef, undef, $day, $month, $year, undef, undef, undef) = localtime($start_day_num + 86400*$day); my $str = ($year+1900)."-".(length($month)==1?"0".$month:$month)."- +".(length($day)==1?"0".$day:$day)."\n"; print "$str"; }