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

Hi guys I'm weaning myself back on the Perl trail after a long illness though I've already hit a problem that's baffling me! I need to write a script that is supplied with 2 dates that must be consecutive ( date1 is read from a file & date2 is a parameter. Date2 must be 1 day later than date1. If you look at the attached rough version of this script - it looks like it should do the job (Okay maybe only to my naive eye!) but.... It looked like it was working if the dates were mid month but as soon as the dates were the 31st October & 1st Nov the results were unexpected - to this novice at least! Anyone shed any light on this or am I being very foolish? (It is amazing how much you forget in just 6 months!!)
#!/usr/bin/perl -w # use Time::Local ; # my $sec1 = '01' ; my $min1 = '00' ; my $hour1 = '00' ; my $day1 = '24' ; my $mon1 = '02' ; my $year1 = '2005' ; my $TIME1 = undef ; my $date1 = undef ; # my $tm = undef ; my $now = time ; # my $sec2 = '01' ; my $min2 = '00' ; my $hour2 = '00' ; my $day2 = '25' ; my $mon2 = '02' ; my $year2 = '2005' ; my $TIME2 = undef ; my $date2 = undef ; # print "\n\tTimestamp test begins\n" ; # $TIME1 = timegm($sec1,$min1,$hour1,$day1,$mon1,$year1) ; # print "\n\tTimestamp1 :: $TIME1\n" ; # ($sec1,$min1,$hour1,$day1,$mon1,$year1) = gmtime($TIME1) ; print "\n\tDay :: $day1" ; print "\n\tMon :: $mon1" ; $year1 += 1900 ; print "\n\tYear :: $year1\n" ; # print "\n\tDATE1 :: $year1\/$mon1\/$day1\n" ; # $TIME2 = timegm($sec2,$min2,$hour2,$day2,$mon2,$year2) ; # print "\n\tTimestamp2 :: $TIME2\n" ; # ($sec2,$min2,$hour2,$day2,$mon2,$year2) = gmtime($TIME2) ; print "\n\tDay :: $day2" ; print "\n\tMon :: $mon2" ; $year2 += 1900 ; print "\n\tYear :: $year2\n" ; # print "\n\tDATE2 :: $year2\/$mon2\/$day2\n" ; # my $dif = $TIME2 - $TIME1 ; my $days = ($dif / (60 * 60 * 24)) ; # print "\n\tThe difference is :: $days\n" ; # print "\n\tTimestamp test ends\n" ;
br Running with the above params results in -
$ xxrctimestamp.pl Timestamp test begins Timestamp1 :: 1111622401 Day :: 24 Mon :: 2 Year :: 2005 DATE1 :: 2005/2/24 Timestamp2 :: 1111708801 Day :: 25 Mon :: 2 Year :: 2005 DATE2 :: 2005/2/25 The difference is :: 1 Timestamp test ends $
Using the following parameters however -
my $sec1 = '01' ; my $min1 = '00' ; my $hour1 = '00' ; my $day1 = '31' ; my $mon1 = '10' ; my $year1 = '2005' ; my $TIME1 = undef ; my $date1 = undef ; # my $tm = undef ; my $now = time ; # my $sec2 = '01' ; my $min2 = '00' ; my $hour2 = '00' ; my $day2 = '01' ; my $mon2 = '11' ; my $year2 = '2005' ; my $TIME2 = undef ; my $date2 = undef ;
br Results in the less than successful -
$ xxrctimestamp.pl Timestamp test begins Timestamp1 :: 1133395201 Day :: 1 Mon :: 11 Year :: 2005 DATE1 :: 2005/11/1 Timestamp2 :: 1133395201 Day :: 1 Mon :: 11 Year :: 2005 DATE2 :: 2005/11/1 The difference is :: 0 Timestamp test ends
If there is something mind bogglingly stupid/dumb about this please feel free to say because I can't see my error! Cheers, Ronnie

Replies are listed 'Best First'.
Re: Date/Timestamp Puzzle
by saintmike (Vicar) on Jun 20, 2005 at 17:08 UTC
    Date and time calculations are tough to get right, especially the nitty-gritty like leap years and daylight savings times. That's why there's a bunch of modules on CPAN, dealing with these problems: Check out DateTime, or for simpler calculations, use Date::Calc and Date::Manip. Example:
    use DateTime; my $dt1 = DateTime->new( year => 2005, month => 10, day => 31, hour => 0, minute => 0, second => 01, ); my $dt2 = DateTime->new( year => 2005, month => 11, day => 01, hour => 0, minute => 0, second => 01, ); my $duration = $dt2 - $dt1; print $duration->in_units('days'), "\n";
Re: Date/Timestamp Puzzle
by Ido (Hermit) on Jun 20, 2005 at 17:28 UTC
    The "bug" you see is simply because months of gmtime and timegm are 0..11, and 31/11 is an invalid date (or rather, the same day as the 1/12??). You could simple you Date::Calc :

    use Date::Calc 'Delta_Days'; print Delta_Days(2005,10,31,2005,11,1);

      I agree with you about Date::Calc but I think Date::Calc 'Add_Delta_Days' may be closer to what the OP is looking for. He has a date and wants to get the date of the following day.

      use warnings; use strict; use Date::Calc qw/Add_Delta_Days Today_and_Now/; my $delta = 1; my ($year, $month, $day) = Today_and_Now; print "$year $month $day\n"; my @nextdate = Add_Delta_Days($year, $month, $day, $delta); print "@nextdate\n";