I've run into an odd issue with DateTime and Memoization (often necessary to
get decent performance for processing 10-20k records with repeat dates). I've
processed a lot of data this way but I recently ran into a few records that
caused an infinite loop, below is some simplified sample code that reproduces
the behavior. It goes away if I don't memoize DT::from_object, but I still
find it odd and thought somebody might be interested in looking into it further
(or documenting the potential for trouble?)

I'm using:

  $DateTime::VERSION = '0.2901';
  $DateTime::Set::VERSION = '0.25';
  $DateTime::Event::Recurrence::VERSION = '0.16';

with ActiveState under Win32.

=cut

use Memoize;
use DateTime::Format::Strptime;
use DateTime::Event::Recurrence;

#DateTime::from_object doesn't Memoize well here.
#Granted, there maybe ought to be a normalizer for the locale parameter?
memoize($_) foreach qw/DateTime::from_object DateTime::new/;

my $strp = new DateTime::Format::Strptime(pattern => '%m/%d/%Y %H:%M');

#Behavior seems to be tied to this data, several records preceeding it are OK
@F{qw(ETYP TYPE     DESCRP SDate    EDate    M T W R F S U STime ETime ROOM)}=
   qw(CLSS ACADEMIC 6.27   2/1/2001 2/1/2001 0 0 0 R 0 0 0 900   2300  26-100);

$F{Start} =$strp->parse_datetime("$F{SDate} ".
                                 substr($F{STime}, 0,-2) .':'.
                                 substr($F{STime}, -2, 2));
$F{End}   =$strp->parse_datetime("$F{SDate} ".
                                 substr($F{ETime}, 0,-2) .':'.
                                 substr($F{ETime}, -2, 2));

$hours = DateTime::Set->from_recurrence(
                                        start      => $F{Start},
                                        before     => $F{End},
                                        recurrence => sub {
                                          $_[0]->truncate( to => 'hour' )
                                            ->add( hours => 1 )
                                          },
                                       );

$iter = $hours->iterator;

#Possibly related: while debugging I somehow, sometimes, managed to get output
#below, but the # of hours were off? I'd get back the even hours only...
printf "There ought to be %i hours\n", scalar $hours->as_list;


#Infinite loop here:
#_callback_previous: iterator can't find a previous value, got 2001-02-01
#  after 2001-02-01 at DateTime/Set.pm line 338.
while ( my $dt = $iter->next ) {
  my $hour = $dt->hour() || 24; #0..23,24 hours
  
  if( $hour >= 7 && $hour <= 24 ){
    doMath($F{ROOM}, $F{Start}->dow, 1, $hour, 1);
  }
};

sub doMath{
  print "\$stash{ $_[0] }->{usage}->[ $_[1] ]->[ $_[3] ] += $_[2] * $_[4];\n";
  $stash{ $_[0] }->{usage}->[ $_[1] ]->[ $_[3] ] += $_[2] * $_[4];
}
__END__
-- 
H4sICNoBwDoAA3NpZwA9jbsNwDAIRHumuC4NklvXTOD0KSJEnwU8fHz4Q8M9i3sGzkS7BBrm
OkCTwsycb4S3DloZuMIYeXpLFqw5LaMhXC2ymhreVXNWMw9YGuAYdfmAbwomoPSyFJuFn2x8
Opr8bBBidccAAAA=
--
MOTD on Pungenday, the 65th of Discord, in the YOLD 3172:
I've lost all sensation in my shirt

Reply via email to