← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/share/koha/opac/cgi-bin/opac/opac-search.pl
  Run on Tue Oct 15 11:58:52 2013
Reported on Tue Oct 15 12:01:36 2013

Filename/usr/share/koha/lib/Koha/Calendar.pm
StatementsExecuted 31 statements in 2.30ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1114.06ms31.9msKoha::Calendar::::BEGIN@7Koha::Calendar::BEGIN@7
1112.75ms4.25msKoha::Calendar::::BEGIN@11Koha::Calendar::BEGIN@11
11147µs116µsKoha::Calendar::::BEGIN@4Koha::Calendar::BEGIN@4
11119µs138µsKoha::Calendar::::BEGIN@10Koha::Calendar::BEGIN@10
11116µs20µsKoha::Calendar::::BEGIN@2Koha::Calendar::BEGIN@2
11115µs20µsKoha::Calendar::::BEGIN@9Koha::Calendar::BEGIN@9
11112µs12µsKoha::Calendar::::BEGIN@8Koha::Calendar::BEGIN@8
11112µs69µsKoha::Calendar::::BEGIN@4.8Koha::Calendar::BEGIN@4.8
11111µs24µsKoha::Calendar::::BEGIN@3Koha::Calendar::BEGIN@3
1119µs9µsKoha::Calendar::::BEGIN@6Koha::Calendar::BEGIN@6
0000s0sKoha::Calendar::::_initKoha::Calendar::_init
0000s0sKoha::Calendar::::_mockinitKoha::Calendar::_mockinit
0000s0sKoha::Calendar::::addDateKoha::Calendar::addDate
0000s0sKoha::Calendar::::addDaysKoha::Calendar::addDays
0000s0sKoha::Calendar::::addHoursKoha::Calendar::addHours
0000s0sKoha::Calendar::::add_holidayKoha::Calendar::add_holiday
0000s0sKoha::Calendar::::clear_weekly_closed_daysKoha::Calendar::clear_weekly_closed_days
0000s0sKoha::Calendar::::days_betweenKoha::Calendar::days_between
0000s0sKoha::Calendar::::hours_betweenKoha::Calendar::hours_between
0000s0sKoha::Calendar::::is_holidayKoha::Calendar::is_holiday
0000s0sKoha::Calendar::::newKoha::Calendar::new
0000s0sKoha::Calendar::::next_open_dayKoha::Calendar::next_open_day
0000s0sKoha::Calendar::::prev_open_dayKoha::Calendar::prev_open_day
0000s0sKoha::Calendar::::set_daysmodeKoha::Calendar::set_daysmode
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package Koha::Calendar;
2333µs224µs
# spent 20µs (16+4) within Koha::Calendar::BEGIN@2 which was called: # once (16µs+4µs) by C4::Circulation::BEGIN@49 at line 2
use strict;
# spent 20µs making 1 call to Koha::Calendar::BEGIN@2 # spent 4µs making 1 call to strict::import
3326µs236µs
# spent 24µs (11+13) within Koha::Calendar::BEGIN@3 which was called: # once (11µs+13µs) by C4::Circulation::BEGIN@49 at line 3
use warnings;
# spent 24µs making 1 call to Koha::Calendar::BEGIN@3 # spent 13µs making 1 call to warnings::import
4682µs3242µs
# spent 69µs (12+57) within Koha::Calendar::BEGIN@4.8 which was called: # once (12µs+57µs) by Koha::Calendar::BEGIN@4 at line 4 # spent 116µs (47+69) within Koha::Calendar::BEGIN@4 which was called: # once (47µs+69µs) by C4::Circulation::BEGIN@49 at line 4
use 5.010;
# spent 116µs making 1 call to Koha::Calendar::BEGIN@4 # spent 69µs making 1 call to Koha::Calendar::BEGIN@4.8 # spent 57µs making 1 call to feature::import
5
6326µs19µs
# spent 9µs within Koha::Calendar::BEGIN@6 which was called: # once (9µs+0s) by C4::Circulation::BEGIN@49 at line 6
use DateTime;
# spent 9µs making 1 call to Koha::Calendar::BEGIN@6
73142µs131.9ms
# spent 31.9ms (4.06+27.9) within Koha::Calendar::BEGIN@7 which was called: # once (4.06ms+27.9ms) by C4::Circulation::BEGIN@49 at line 7
use DateTime::Set;
# spent 31.9ms making 1 call to Koha::Calendar::BEGIN@7
8330µs112µs
# spent 12µs within Koha::Calendar::BEGIN@8 which was called: # once (12µs+0s) by C4::Circulation::BEGIN@49 at line 8
use DateTime::Duration;
# spent 12µs making 1 call to Koha::Calendar::BEGIN@8
9363µs226µs
# spent 20µs (15+5) within Koha::Calendar::BEGIN@9 which was called: # once (15µs+5µs) by C4::Circulation::BEGIN@49 at line 9
use C4::Context;
# spent 20µs making 1 call to Koha::Calendar::BEGIN@9 # spent 5µs making 1 call to C4::Context::import
10356µs2256µs
# spent 138µs (19+118) within Koha::Calendar::BEGIN@10 which was called: # once (19µs+118µs) by C4::Circulation::BEGIN@49 at line 10
use Carp;
# spent 138µs making 1 call to Koha::Calendar::BEGIN@10 # spent 118µs making 1 call to Exporter::import
1131.84ms24.29ms
# spent 4.25ms (2.75+1.50) within Koha::Calendar::BEGIN@11 which was called: # once (2.75ms+1.50ms) by C4::Circulation::BEGIN@49 at line 11
use Readonly;
# spent 4.25ms making 1 call to Koha::Calendar::BEGIN@11 # spent 43µs making 1 call to Exporter::import
12
13sub new {
14 my ( $classname, %options ) = @_;
15 my $self = {};
16 bless $self, $classname;
17 for my $o_name ( keys %options ) {
18 my $o = lc $o_name;
19 $self->{$o} = $options{$o_name};
20 }
21 if ( exists $options{TEST_MODE} ) {
22 $self->_mockinit();
23 return $self;
24 }
25 if ( !defined $self->{branchcode} ) {
26 croak 'No branchcode argument passed to Koha::Calendar->new';
27 }
28 $self->_init();
29 return $self;
30}
31
32sub _init {
33 my $self = shift;
34 my $branch = $self->{branchcode};
35 my $dbh = C4::Context->dbh();
36 my $weekly_closed_days_sth = $dbh->prepare(
37'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL'
38 );
39 $weekly_closed_days_sth->execute( $branch );
40 $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ];
41 Readonly::Scalar my $sunday => 7;
42 while ( my $tuple = $weekly_closed_days_sth->fetchrow_hashref ) {
43 $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1;
44 }
45 my $day_month_closed_days_sth = $dbh->prepare(
46'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL'
47 );
48 $day_month_closed_days_sth->execute( $branch );
49 $self->{day_month_closed_days} = {};
50 while ( my $tuple = $day_month_closed_days_sth->fetchrow_hashref ) {
51 $self->{day_month_closed_days}->{ $tuple->{month} }->{ $tuple->{day} } =
52 1;
53 }
54
55 my $exception_holidays_sth = $dbh->prepare(
56'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1'
57 );
58 $exception_holidays_sth->execute( $branch );
59 my $dates = [];
60 while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) {
61 push @{$dates},
62 DateTime->new(
63 day => $day,
64 month => $month,
65 year => $year,
66 time_zone => C4::Context->tz()
67 )->truncate( to => 'day' );
68 }
69 $self->{exception_holidays} =
70 DateTime::Set->from_datetimes( dates => $dates );
71
72 my $single_holidays_sth = $dbh->prepare(
73'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0'
74 );
75 $single_holidays_sth->execute( $branch );
76 $dates = [];
77 while ( my ( $day, $month, $year ) = $single_holidays_sth->fetchrow ) {
78 push @{$dates},
79 DateTime->new(
80 day => $day,
81 month => $month,
82 year => $year,
83 time_zone => C4::Context->tz()
84 )->truncate( to => 'day' );
85 }
86 $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates );
87 $self->{days_mode} = C4::Context->preference('useDaysMode');
88 $self->{test} = 0;
89 return;
90}
91
92sub addDate {
93 my ( $self, $startdate, $add_duration, $unit ) = @_;
94
95 # Default to days duration (legacy support I guess)
96 if ( ref $add_duration ne 'DateTime::Duration' ) {
97 $add_duration = DateTime::Duration->new( days => $add_duration );
98 }
99
100 $unit ||= 'days'; # default days ?
101 my $dt;
102
103 if ( $unit eq 'hours' ) {
104 # Fixed for legacy support. Should be set as a branch parameter
105 Readonly::Scalar my $return_by_hour => 10;
106
107 $dt = $self->addHours($startdate, $add_duration, $return_by_hour);
108 } else {
109 # days
110 $dt = $self->addDays($startdate, $add_duration);
111 }
112
113 return $dt;
114}
115
116sub addHours {
117 my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_;
118 my $base_date = $startdate->clone();
119
120 $base_date->add_duration($hours_duration);
121
122 # If we are using the calendar behave for now as if Datedue
123 # was the chosen option (current intended behaviour)
124
125 if ( $self->{days_mode} ne 'Days' &&
126 $self->is_holiday($base_date) ) {
127
128 if ( $hours_duration->is_negative() ) {
129 $base_date = $self->prev_open_day($base_date);
130 } else {
131 $base_date = $self->next_open_day($base_date);
132 }
133
134 $base_date->set_hour($return_by_hour);
135
136 }
137
138 return $base_date;
139}
140
141sub addDays {
142 my ( $self, $startdate, $days_duration ) = @_;
143 my $base_date = $startdate->clone();
144
145 if ( $self->{days_mode} eq 'Calendar' ) {
146 # use the calendar to skip all days the library is closed
147 # when adding
148 my $days = abs $days_duration->in_units('days');
149
150 if ( $days_duration->is_negative() ) {
151 while ($days) {
152 $base_date = $self->prev_open_day($base_date);
153 --$days;
154 }
155 } else {
156 while ($days) {
157 $base_date = $self->next_open_day($base_date);
158 --$days;
159 }
160 }
161
162 } else { # Days or Datedue
163 # use straight days, then use calendar to push
164 # the date to the next open day if Datedue
165 $base_date->add_duration($days_duration);
166
167 if ( $self->{days_mode} eq 'Datedue' ) {
168 # Datedue, then use the calendar to push
169 # the date to the next open day if holiday
170 if ( $self->is_holiday($base_date) ) {
171 if ( $days_duration->is_negative() ) {
172 $base_date = $self->prev_open_day($base_date);
173 } else {
174 $base_date = $self->next_open_day($base_date);
175 }
176 }
177 }
178 }
179
180 return $base_date;
181}
182
183sub is_holiday {
184 my ( $self, $dt ) = @_;
185 my $localdt = $dt->clone();
186 my $day = $localdt->day;
187 my $month = $localdt->month;
188
189 $localdt->truncate( to => 'day' );
190
191 if ( $self->{exception_holidays}->contains($localdt) ) {
192 # exceptions are not holidays
193 return 0;
194 }
195
196 my $dow = $localdt->day_of_week;
197 # Representation fix
198 # TODO: Shouldn't we shift the rest of the $dow also?
199 if ( $dow == 7 ) {
200 $dow = 0;
201 }
202
203 if ( $self->{weekly_closed_days}->[$dow] == 1 ) {
204 return 1;
205 }
206
207 if ( exists $self->{day_month_closed_days}->{$month}->{$day} ) {
208 return 1;
209 }
210
211 if ( $self->{single_holidays}->contains($localdt) ) {
212 return 1;
213 }
214
215 # damn have to go to work after all
216 return 0;
217}
218
219sub next_open_day {
220 my ( $self, $dt ) = @_;
221 my $base_date = $dt->clone();
222
223 $base_date->add(days => 1);
224
225 while ($self->is_holiday($base_date)) {
226 $base_date->add(days => 1);
227 }
228
229 return $base_date;
230}
231
232sub prev_open_day {
233 my ( $self, $dt ) = @_;
234 my $base_date = $dt->clone();
235
236 $base_date->add(days => -1);
237
238 while ($self->is_holiday($base_date)) {
239 $base_date->add(days => -1);
240 }
241
242 return $base_date;
243}
244
245sub days_between {
246 my $self = shift;
247 my $start_dt = shift;
248 my $end_dt = shift;
249
250 if ( $start_dt->compare($end_dt) > 0 ) {
251 # swap dates
252 my $int_dt = $end_dt;
253 $end_dt = $start_dt;
254 $start_dt = $int_dt;
255 }
256
257
258 # start and end should not be closed days
259 my $days = $start_dt->delta_days($end_dt)->delta_days;
260 for (my $dt = $start_dt->clone();
261 $dt <= $end_dt;
262 $dt->add(days => 1)
263 ) {
264 if ($self->is_holiday($dt)) {
265 $days--;
266 }
267 }
268 return DateTime::Duration->new( days => $days );
269
270}
271
272sub hours_between {
273 my ($self, $start_date, $end_date) = @_;
274 my $start_dt = $start_date->clone();
275 my $end_dt = $end_date->clone();
276 my $duration = $end_dt->delta_ms($start_dt);
277 $start_dt->truncate( to => 'day' );
278 $end_dt->truncate( to => 'day' );
279 # NB this is a kludge in that it assumes all days are 24 hours
280 # However for hourly loans the logic should be expanded to
281 # take into account open/close times then it would be a duration
282 # of library open hours
283 my $skipped_days = 0;
284 for (my $dt = $start_dt->clone();
285 $dt <= $end_dt;
286 $dt->add(days => 1)
287 ) {
288 if ($self->is_holiday($dt)) {
289 ++$skipped_days;
290 }
291 }
292 if ($skipped_days) {
293 $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days));
294 }
295
296 return $duration;
297
298}
299
300sub _mockinit {
301 my $self = shift;
302 $self->{weekly_closed_days} = [ 1, 0, 0, 0, 0, 0, 0 ]; # Sunday only
303 $self->{day_month_closed_days} = { 6 => { 16 => 1, } };
304 my $dates = [];
305 $self->{exception_holidays} =
306 DateTime::Set->from_datetimes( dates => $dates );
307 my $special = DateTime->new(
308 year => 2011,
309 month => 6,
310 day => 1,
311 time_zone => 'Europe/London',
312 );
313 push @{$dates}, $special;
314 $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates );
315
316 # if not defined, days_mode defaults to 'Calendar'
317 if ( !defined($self->{days_mode}) ) {
318 $self->{days_mode} = 'Calendar';
319 }
320
321 $self->{test} = 1;
322 return;
323}
324
325sub set_daysmode {
326 my ( $self, $mode ) = @_;
327
328 # if not testing this is a no op
329 if ( $self->{test} ) {
330 $self->{days_mode} = $mode;
331 }
332
333 return;
334}
335
336sub clear_weekly_closed_days {
337 my $self = shift;
338 $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ]; # Sunday only
339 return;
340}
341
342sub add_holiday {
343 my $self = shift;
344 my $new_dt = shift;
345 my @dt = $self->{single_holidays}->as_list;
346 push @dt, $new_dt;
347 $self->{single_holidays} =
348 DateTime::Set->from_datetimes( dates => \@dt );
349
350 return;
351}
352
35314µs1;
354__END__