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

Hello All, I am getting lots of rows from a database where the time stamp has to be evaluated. I set an off set of 12:00am, so every entry before 12:00 is stays, every date which is after 12:00 is beeing put forward by 24hours. That way I report from 12:00am to 12:00am rather that 0:00 to 0:00. Iam using Date::Manip but is is just a bit slow and I was wondering if there a faster / simpler way.
while (@row = $sth->fetchrow_array ){ ($host,$pol,$sched,$date,$target,$error)=@row[0,1,2,3,4,5]; $cutover=(split /:/,$time)[0]; if ($date=~/\s(\d{2})/){ $hour=$1; } #print "========= CUTOVER: $cutover DATE: $date HOUR: $hour == +======\n"; if ($hour > $cutover){ ## 12 hours are added to push the backup into the new repo +rting window (next day) $date=DateCalc("$date","+24 hours"); ###Takes 2min out of +2:30min. $date=&UnixDate($date,"%Y-%m-%d"); #print" This backup has moved to the next day: $date\n"; }else{ $date=(split /\s/,$date)[0]; #print" This backup has stayed: $date\n"; } if (defined ${$report{$host}{$pol}{$sched}{$date}}){ ${$report{$host}{$pol}{$sched}{$date}}=${$report{$host}{$p +ol}{$sched}{$date}}+$error; }else{ ${$report{$host}{$pol}{$sched}{$date}}=$error; } } }

Replies are listed 'Best First'.
Re: Changing dates
by jZed (Prior) on May 01, 2007 at 04:21 UTC
    Most databases have time and date functions, maybe you can let the SQL do the math.
Re: Changing dates
by GrandFather (Saint) on May 01, 2007 at 05:02 UTC

    Date::Calc and a little hand rolled code may help:

    use strict; use warnings; use Date::Manip; use Date::Calc qw(Add_Delta_DHMS); use Benchmark qw(cmpthese); Date_Init ("TZ=UT"); my @dates = ("2007-04-30 12:50:00", "2007-04-30 11:50:00"); print "Manip result: \n", join "\n", manip (), "\n"; print "Calc result: \n", join "\n", calc (), "\n"; cmpthese (-1, { manip => \&manip, calc => \&calc, }); sub manip { my @results; for (@dates) { my $date = $_; my $hour = (split /:/, $date)[0]; die "Can't find hour" unless $hour =~ /\s(\d{2})$/; if ($1 >= 12){ $date=DateCalc("$date","+24 hours"); ###Takes 2min out of +2:30min. $date=&UnixDate($date,"%Y-%m-%d"); } push @results, $date; } return @results; } sub calc { my @results; for (@dates) { my $date = $_; my $hour = (split /:/, $date)[0]; die "Can't find hour" unless $hour =~ /\s(\d{2})$/; if ($1 >= 12){ my ($year,$month,$day, $hour,$min,$sec) = $date =~ /(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/; ($year,$month,$day, $hour,$min,$sec) = Add_Delta_DHMS ( $year,$month,$day, $hour,$min,$sec, 1, 0, 0, 0 ); $date = "$year-$month-$day $hour:$min:$sec"; } push @results, $date; } return @results; }

    Prints:

    Manip result: 2007-05-01 2007-04-30 11:50:00 Calc result: 2007-5-1 12:50:0 2007-04-30 11:50:00 Rate manip calc manip 662/s -- -99% calc 59112/s 8825% --

    A little tidying up to generate consistent output formating may be required, but that's likely not a big price to pay.


    DWIM is Perl's answer to Gödel
Re: Changing dates
by parv (Parson) on May 01, 2007 at 06:21 UTC

    This reply does not deal with The Original Question.

    It seems you are having some shortage of whitespace, and clearly are not running your code under warnings pragma.

    $cutover=(split /:/,$time)[0]; if ($date=~/\s(\d{2})/){ $hour=$1; } ... if ($hour > $cutover){

    In case $date is not formatted correctly or is undefined, $hour would be undefined in the if condition. That would cause the backup not to be moved.

    If warnings pragma were in effect, above would have generated an "uninitialized value" error message (assuming variables had been properly declared) when $date =~ /\s(\d{2})/ fails, indicating problem in expected date format or value.

    $date=DateCalc("$date","+24 hours"); ###Takes 2min out of +2:30min.

    Why is there a need to quote $date above? By the associated comment, do you mean adding 24 hours to a date string causes half hour times to be shifted back by 2 minutes?

    $date=&UnixDate($date,"%Y-%m-%d");

    Why is UnixDate sub being called as &UnixDate() not just UnixDate() -- note the lack of '&'? At least be consistent.

    if (defined ${$report{$host}{$pol}{$sched}{$date}}){ ${$report{$host}{$pol}{$sched}{$date}}=${$report{$host}{$p +ol}{$sched}{$date}}+$error; }else{ ${$report{$host}{$pol}{$sched}{$date}}=$error; }

    (Damn!) Are you sure that the date field referenced in above hash is really a scalar reference, not just a plain scalar? In the if branch, what is it that you want to achieve by using + operator? Besides, won't you agree that accessing the date field as above is rather a pain?

    Without warnings pragma in effect, in the first branch, the date field would be the value of arithmetic addition of the date field & $error. + is only a arithmetic operator (barring any intentional overloading and outside of regular expressions) which causes any string to be added (as above) to evaluate to zero. . is the concatenation operator.

    Now, if warnings were in effect, you would have gotten an error message indicating that the operands of + are not numeric (as appropriate).

    Above can be rewritten in many ways. Here is one version assuming (a) the date field in %report is really a scalar reference, and (b) in the if branch, you want to concatenate $error with the date field ...

    my $rep_date = $report{$host}{$pol}{$sched}{$date}; if ( defined ${ $rep_date } ) { ${ $rep_date } .= $error; } else { ${ $rep_date } = $error; } # # ... or ... #${ $rep_date } = # defined ${ $rep_date } ? ${ $rep_date } . $error # : $error # ;

    Please study some introductory material -- including but not limited to, in not much of an order -- Learning Perl and Intermediate Perl books, perlintro, perldsc, perlsub, perlreftut, perlop.