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

I have a paltry, date string conundrum upon which I beseech the wisdom of those who frequent this site. I am doing basic date/string manipulation with the constraint of not using Date::Calc; I am just using Perl "out of the box". The below code snippet demonstrates the core issue. I take an input date and generate a date 6 days later. It works for every date except November 1st and I am not sure why.
#!/usr/bin/perl -w use warnings; use strict; use Getopt::Long; use Time::Local; use POSIX qw(strftime); # The idea is to take an input date and add 6 days to it. # It seems to work except when the start date is November 1! # # Below is an example: # my $input_date; GetOptions("start_date=s" => \$input_date); print "\nWe expect a start day and a day 6 days later than that!\n"; my @date_pieces = split('/',$input_date); my $start_day = timelocal(0, 0, 0, $date_pieces[1], $date_pieces[0]-1, + $date_pieces[2]); my $end_day = $start_day + 6*24*60*60; my $new_start_day = strftime "%m/%d/%Y", (localtime($start_day)); my $new_end_day = strftime "%m/%d/%Y", (localtime($end_day)); print "The start day is $new_start_day and the end day is $new_end_day +\n";
Below is a run of various inputs and you see that the only failure seen is Nov 1st:
$ LIST="09/20/2008 1/1/2009 11/3/2008 06/06/2006 11/1/2008 11/1/2008 1 +0/1/2008" $ for i in $LIST > do > booger -start_date $i > done We expect a start day and a day 6 days later than that! The start day is 09/20/2008 and the end day is 09/26/2008 We expect a start day and a day 6 days later than that! The start day is 01/01/2009 and the end day is 01/07/2009 We expect a start day and a day 6 days later than that! The start day is 11/03/2008 and the end day is 11/09/2008 We expect a start day and a day 6 days later than that! The start day is 06/06/2006 and the end day is 06/12/2006 We expect a start day and a day 6 days later than that! The start day is 11/01/2008 and the end day is 11/06/2008 We expect a start day and a day 6 days later than that! The start day is 11/01/2008 and the end day is 11/06/2008 We expect a start day and a day 6 days later than that! The start day is 10/01/2008 and the end day is 10/07/2008
Note how both November dates are 5 days apart as opposed to 6. Any help would be greatly appreciated.

Replies are listed 'Best First'.
Re: date string conundrum
by Fletch (Bishop) on Dec 01, 2008 at 20:04 UTC

    Hrmmm, one wonders if there's any time related events that occur near the beginning of November that might be germane . . .

    Update: And personally I'd just use DateTime as it does the right thing easily.

    use strict; use DateTime; my $start = DateTime->new( month => 11, day => 1, year => 2008 ); my $end = $start->clone->add( days => 6 ); print "Start: ", $start->ymd, "\tend: ", $end->ymd, "\n"; __END__ Start: 2008-11-01 end: 2008-11-07

    Granted that's not "out of the box" either, but I'd be more worried about correctness than an additional install.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: date string conundrum
by Corion (Patriarch) on Dec 01, 2008 at 20:08 UTC

    When you want to add days, it is dangerous to add multiples of 24 hours. There are days that have only 23 hours and others that have 25 hours - the days when daylight savings time gets switched on or off.

    I'd use DateTime for the date calculations, but if you insist of doing it yourself, I also use the approach of adding 22 hours until the date part of a timestamp changes and then renormalize the timestamp to 00:00:00 of the days. That way, I'm always safe from DST changes.

Re: date string conundrum
by toolic (Bishop) on Dec 01, 2008 at 20:13 UTC
    with the constraint of not using Date::Calc; I am just using Perl "out of the box"
    You could always leverage off of CPAN modules by looking at their source code. See Yes, even you can use CPAN.
Re: date string conundrum
by almut (Canon) on Dec 01, 2008 at 20:39 UTC

    FYI, I can't replicate the problem. I always get 6 days apart, even with 11/1/2008 (and even when pretending to be in another time zone, e.g. via TZ=PST).  Not really sure if it might have to do with the timezone, but maybe you could just try by switching to timegm()/gmtime() (and $ENV{TZ}="GMT", as strftime is TZ-aware).  Or maybe your system's POSIX library (strftime) is just broken...

    Update: actually, I can reproduce the issue when using a time zone for which my system does handle daylight savings time1 (plus using a different start date, as in (most parts of) Europe the DST switch is done on the last Sunday in October — as opposed to the first Sunday in November).  Similarly, using TZ=GMT 'fixes' the issue:

    $ TZ=CET ./727202.pl -s 10/25/2008 The start day is 10/25/2008 and the end day is 10/30/2008 23:00 $ TZ=GMT ./727202.pl -s 10/25/2008 The start day is 10/25/2008 and the end day is 10/31/2008 00:00

    (to show the hour, I changed the end_day format to "%m/%d/%Y %H:%M")

    Anyhow, as others have said, it's probably better to use a module that has already solved this, and other date/time issues...

    ___

    1 For reasons I haven't investigated further, it isn't sufficient to set my TZ to a time zone in the US — when doing so, I do get the respective local time, but without the local daylight savings time being handled correctly... (which is why I initially couldn't replicate the problem)

Re: date string conundrum
by ww (Archbishop) on Dec 01, 2008 at 22:08 UTC
    Likewise, I cannot replicate on W2k re 11/1/2008 with Perl 5.8.8 BUT the problem is reproduced on Ubuntu 6.0.6 with Perl 5.8.7.

    But using 10/24/2008 as the start day under W2k:

    We expect a start day and a day 6 days later than that! The start day is 10/24/2008 and the end day is 10/29/2008

    while running under Ubuntu, the end day is returned as 10/30/2008.

    Note that I took some minor liberties with your code: I hardcoded each $start_date and commented out the use of GetOpt::Long).

      Microsoft didn't issue a public patch for Win2k when North America switched the duration of DST recently, only WinXP and up.

      The patch my office used.

Re: date string conundrum
by pileofrogs (Priest) on Dec 01, 2008 at 21:49 UTC

    Dates being the arbitrary and complex things that they are, I'd abandon trying to be elegant and just go with the big ugly obvious approach.

    You have the days already submitted, so just add more days, check for month overlap etc.. Don't convert to seconds past epoch at all. This might miss weird leapyear stuff, but it will work %99.99 of the time and it will be easy to maintain because it will be really obvious what it's doing.

    --Pileofrogs