Working with a smaller, bounded subset might help: # reduce the working set size by intersecting with a smaller span $total_span_set = $total_span_set->intersection( DateTime::Span->new( start => DateTime->new( year => 2003, month => 1, day => 1 ), before => DateTime->new( year => 2003, month => 3, day => 1 ) ) );
Also changing the set time zone inside a loop can be expensive. It would be better to move the call to $dt_set->set_time_zone() to outside of the loops. Flávio S. Glock 2010/12/1 Per-Olof Jensen <per.jen...@bolderthinking.com>: > I've been running into the issue of having a SpanSet being incredibly slow > when doing a ->contains on a DateTime->now object. I've tried spreading the > spanset into an array of spans. That becomes much faster, but only if there > is no time zone set on those spans. The moment I put time zones on those > 'not unioned' spans I get a massive slowdown in computation time. This is > going into a large scale project, and I was hoping that this feature would > be able to be used since it does exactly what I need it to do! > > Our goal is to take a group of spans and check if the time right now is > within each span (basically a daily schedule across the globe). > > Here's a test program illustrating the problem I'm having. I'm just > wondering if there is any way to make the ->contains faster. > > > #!/usr/bin/perl > > use DateTime::Event::Recurrence; > use DateTime::SpanSet; > use DateTime::Infinite; > use DateTime::Set; > use DateTime; > > my ($total_span_set, $start, $end, $spanset); > my @array; > my %tzhash = ( > '1' => 'America/Halifax', > '2' => 'America/New_York', > '3' => 'America/Chicago', > '4' => 'America/Denver', > '5' => 'America/Los_Angeles', > '6' => 'America/Nome', > '7' => 'Pacific/Honolulu', > '8' => 'Asia/Tokyo', > ); > > $x = 7; > > while ($x > 0 ){ > > # Make the set representing the work start times: M-F 9:00 and 13:00 > $start = DateTime::Event::Recurrence->weekly > ( days => $x%6+1, hours => 00 , minutes => 00); > # Make the set representing the work end times: M-F 12:00 and 17:00 > $end = DateTime::Event::Recurrence->weekly > ( days => $x%6+1, hours => 23, minutes => 59); > > # Build a spanset from the set of starting points and ending points > $spanset = DateTime::SpanSet->from_sets > ( start_set => $start, > end_set => $end ); > > if ($total_span_set){$total_span_set = $total_span_set->union($spanset)} > else {$total_span_set = $spanset} > push(@array, $spanset); > $x--; > } > # Iterate from Thursday the 3rd to Monday the 6th > my $it = $spanset->iterator > (start => > DateTime->new(year => 2003, month => 1, day => 3), > before => > DateTime->new(year => 2003, month => 1, day => 7)); > > while (my $span = $it->next) { > my ($st, $end) = ($span->start(), $span->end()); > print $st->day_abbr, " ", $st->hour, " to ", $end->hour, "\n"; > } > > my $dt = DateTime->new(year => 2003, month => 2, day => 11, hour => 11); > > > my $timer = DateTime->now; > > #Here I'm using the first way. Using a spanet seems very slow on 'contains' > regardless of having a timezone set or not for the span > my $x = 3; > while( $x ){ > $dt->set_time_zone($tzhash{$x%6 + 1}); > #Setting a time zone to the SpanSet doesn't seem to affect search time > $total_span_set->set_time_zone($tzhash{2}); > if ($total_span_set->contains( $dt )){ > print "Found time! \n"; > } > } > $result = $timer - DateTime->now; > print "Total time : ".$result->seconds."\n"; > > > #An array of spans, this seems to be very fast without timezones set > $timer = DateTime->now; > $x = 3; > while( $x ){ > > foreach(@array){ > #Setting a time zone to the SpanSet/Spans really hoses search time > $_->set_time_zone($tzhash{2}); > if ($_->contains( $dt )){ > print "Found time\n"; > } > } > $x--; > } > > $result = $timer - DateTime->now; > print "Total time : ".$result->seconds."\n"; > > > > -- > Per Jensen > Bolder Thinking - Software Developer >