File Coverage

File:C4/Calendar.pm
Coverage:9.4%

linestmtbrancondsubtimecode
1package C4::Calendar;
2
3# This file is part of Koha.
4#
5# Koha is free software; you can redistribute it and/or modify it under the
6# terms of the GNU General Public License as published by the Free Software
7# Foundation; either version 2 of the License, or (at your option) any later
8# version.
9#
10# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along with
15# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16# Suite 330, Boston, MA 02111-1307 USA
17
18
14
14
14
20361
90
740
use strict;
19
14
14
14
143
407
771
use warnings;
20
14
14
14
130
80
761
use vars qw($VERSION @EXPORT);
21
22
14
14
14
132
64
1130
use Carp;
23
14
14
14
433
3115
1297
use Date::Calc qw( Date_to_Days );
24
25
14
14
14
346
57
187
use C4::Context;
26
27BEGIN {
28    # set the version for version checking
29
14
78
    $VERSION = 3.01;
30
14
139
    require Exporter;
31
14
47893
    @EXPORT = qw(
32        &get_week_days_holidays
33        &get_day_month_holidays
34        &get_exception_holidays
35        &get_single_holidays
36        &insert_week_day_holiday
37        &insert_day_month_holiday
38        &insert_single_holiday
39        &insert_exception_holiday
40        &ModWeekdayholiday
41        &ModDaymonthholiday
42        &ModSingleholiday
43        &ModExceptionholiday
44        &delete_holiday
45        &isHoliday
46        &addDate
47        &daysBetween
48    );
49}
50
51 - 73
=head1 NAME

C4::Calendar::Calendar - Koha module dealing with holidays.

=head1 SYNOPSIS

    use C4::Calendar::Calendar;

=head1 DESCRIPTION

This package is used to deal with holidays. Through this package, you can set 
all kind of holidays for the library.

=head1 FUNCTIONS

=head2 new

  $calendar = C4::Calendar->new(branchcode => $branchcode);

Each library branch has its own Calendar.  
C<$branchcode> specifies which Calendar you want.

=cut
74
75sub new {
76
0
    my $classname = shift @_;
77
0
    my %options = @_;
78
0
    my $self = bless({}, $classname);
79
0
    foreach my $optionName (keys %options) {
80
0
        $self->{lc($optionName)} = $options{$optionName};
81    }
82
0
    defined($self->{branchcode}) or croak "No branchcode argument to new. Should be C4::Calendar->new(branchcode => \$branchcode)";
83
0
    $self->_init($self->{branchcode});
84
0
    return $self;
85}
86
87sub _init {
88
0
    my $self = shift @_;
89
0
    my $branch = shift;
90
0
    defined($branch) or die "No branchcode sent to _init"; # must test for defined here and above to allow ""
91
0
    my $dbh = C4::Context->dbh();
92
0
    my $repeatable = $dbh->prepare( 'SELECT *
93                                       FROM repeatable_holidays
94                                      WHERE ( branchcode = ? )
95                                        AND (ISNULL(weekday) = ?)' );
96
0
    $repeatable->execute($branch,0);
97
0
    my %week_days_holidays;
98
0
    while (my $row = $repeatable->fetchrow_hashref) {
99
0
        my $key = $row->{weekday};
100
0
        $week_days_holidays{$key}{title} = $row->{title};
101
0
        $week_days_holidays{$key}{description} = $row->{description};
102    }
103
0
    $self->{'week_days_holidays'} = \%week_days_holidays;
104
105
0
    $repeatable->execute($branch,1);
106
0
    my %day_month_holidays;
107
0
    while (my $row = $repeatable->fetchrow_hashref) {
108
0
        my $key = $row->{month} . "/" . $row->{day};
109
0
        $day_month_holidays{$key}{title} = $row->{title};
110
0
        $day_month_holidays{$key}{description} = $row->{description};
111
0
        $day_month_holidays{$key}{day} = sprintf("%02d", $row->{day});
112
0
        $day_month_holidays{$key}{month} = sprintf("%02d", $row->{month});
113    }
114
0
    $self->{'day_month_holidays'} = \%day_month_holidays;
115
116
0
    my $special = $dbh->prepare( 'SELECT day, month, year, title, description
117                                    FROM special_holidays
118                                   WHERE ( branchcode = ? )
119                                     AND (isexception = ?)' );
120
0
    $special->execute($branch,1);
121
0
    my %exception_holidays;
122
0
    while (my ($day, $month, $year, $title, $description) = $special->fetchrow) {
123
0
        $exception_holidays{"$year/$month/$day"}{title} = $title;
124
0
        $exception_holidays{"$year/$month/$day"}{description} = $description;
125
0
        $exception_holidays{"$year/$month/$day"}{date} =
126                sprintf("%04d-%02d-%02d", $year, $month, $day);
127    }
128
0
    $self->{'exception_holidays'} = \%exception_holidays;
129
130
0
    $special->execute($branch,0);
131
0
    my %single_holidays;
132
0
    while (my ($day, $month, $year, $title, $description) = $special->fetchrow) {
133
0
        $single_holidays{"$year/$month/$day"}{title} = $title;
134
0
        $single_holidays{"$year/$month/$day"}{description} = $description;
135
0
        $single_holidays{"$year/$month/$day"}{date} =
136                sprintf("%04d-%02d-%02d", $year, $month, $day);
137    }
138
0
    $self->{'single_holidays'} = \%single_holidays;
139
0
    return $self;
140}
141
142 - 148
=head2 get_week_days_holidays

   $week_days_holidays = $calendar->get_week_days_holidays();

Returns a hash reference to week days holidays.

=cut
149
150sub get_week_days_holidays {
151
0
    my $self = shift @_;
152
0
    my $week_days_holidays = $self->{'week_days_holidays'};
153
0
    return $week_days_holidays;
154}
155
156 - 162
=head2 get_day_month_holidays

   $day_month_holidays = $calendar->get_day_month_holidays();

Returns a hash reference to day month holidays.

=cut
163
164sub get_day_month_holidays {
165
0
    my $self = shift @_;
166
0
    my $day_month_holidays = $self->{'day_month_holidays'};
167
0
    return $day_month_holidays;
168}
169
170 - 178
=head2 get_exception_holidays

    $exception_holidays = $calendar->exception_holidays();

Returns a hash reference to exception holidays. This kind of days are those
which stands for a holiday, but you wanted to make an exception for this particular
date.

=cut
179
180sub get_exception_holidays {
181
0
    my $self = shift @_;
182
0
    my $exception_holidays = $self->{'exception_holidays'};
183
0
    return $exception_holidays;
184}
185
186 - 193
=head2 get_single_holidays

    $single_holidays = $calendar->get_single_holidays();

Returns a hash reference to single holidays. This kind of holidays are those which
happend just one time.

=cut
194
195sub get_single_holidays {
196
0
    my $self = shift @_;
197
0
    my $single_holidays = $self->{'single_holidays'};
198
0
    return $single_holidays;
199}
200
201 - 215
=head2 insert_week_day_holiday

    insert_week_day_holiday(weekday => $weekday,
                            title => $title,
                            description => $description);

Inserts a new week day for $self->{branchcode}.

C<$day> Is the week day to make holiday.

C<$title> Is the title to store for the holiday formed by $year/$month/$day.

C<$description> Is the description to store for the holiday formed by $year/$month/$day.

=cut
216
217sub insert_week_day_holiday {
218
0
    my $self = shift @_;
219
0
    my %options = @_;
220
221
0
    my $dbh = C4::Context->dbh();
222
0
    my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ( '',?,?,NULL,NULL,?,? )");
223
0
        $insertHoliday->execute( $self->{branchcode}, $options{weekday},$options{title}, $options{description});
224
0
    $self->{'week_days_holidays'}->{$options{weekday}}{title} = $options{title};
225
0
    $self->{'week_days_holidays'}->{$options{weekday}}{description} = $options{description};
226
0
    return $self;
227}
228
229 - 246
=head2 insert_day_month_holiday

    insert_day_month_holiday(day => $day,
                             month => $month,
                             title => $title,
                             description => $description);

Inserts a new day month holiday for $self->{branchcode}.

C<$day> Is the day month to make the date to insert.

C<$month> Is month to make the date to insert.

C<$title> Is the title to store for the holiday formed by $year/$month/$day.

C<$description> Is the description to store for the holiday formed by $year/$month/$day.

=cut
247
248sub insert_day_month_holiday {
249
0
    my $self = shift @_;
250
0
    my %options = @_;
251
252
0
    my $dbh = C4::Context->dbh();
253
0
    my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ('', ?, NULL, ?, ?, ?,? )");
254
0
        $insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{title}, $options{description});
255
0
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title};
256
0
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description};
257
0
    return $self;
258}
259
260 - 280
=head2 insert_single_holiday

    insert_single_holiday(day => $day,
                          month => $month,
                          year => $year,
                          title => $title,
                          description => $description);

Inserts a new single holiday for $self->{branchcode}.

C<$day> Is the day month to make the date to insert.

C<$month> Is month to make the date to insert.

C<$year> Is year to make the date to insert.

C<$title> Is the title to store for the holiday formed by $year/$month/$day.

C<$description> Is the description to store for the holiday formed by $year/$month/$day.

=cut
281
282sub insert_single_holiday {
283
0
    my $self = shift @_;
284
0
    my %options = @_;
285
286
0
        my $dbh = C4::Context->dbh();
287
0
    my $isexception = 0;
288
0
    my $insertHoliday = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)");
289
0
        $insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description});
290
0
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
291
0
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
292
0
    return $self;
293}
294
295 - 315
=head2 insert_exception_holiday

    insert_exception_holiday(day => $day,
                             month => $month,
                             year => $year,
                             title => $title,
                             description => $description);

Inserts a new exception holiday for $self->{branchcode}.

C<$day> Is the day month to make the date to insert.

C<$month> Is month to make the date to insert.

C<$year> Is year to make the date to insert.

C<$title> Is the title to store for the holiday formed by $year/$month/$day.

C<$description> Is the description to store for the holiday formed by $year/$month/$day.

=cut
316
317sub insert_exception_holiday {
318
0
    my $self = shift @_;
319
0
    my %options = @_;
320
321
0
    my $dbh = C4::Context->dbh();
322
0
    my $isexception = 1;
323
0
    my $insertException = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)");
324
0
        $insertException->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description});
325
0
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
326
0
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
327
0
    return $self;
328}
329
330 - 342
=head2 ModWeekdayholiday

    ModWeekdayholiday(weekday =>$weekday,
                      title => $title,
                      description => $description)

Modifies the title and description of a weekday for $self->{branchcode}.

C<$weekday> Is the title to update for the holiday.

C<$description> Is the description to update for the holiday.

=cut
343
344sub ModWeekdayholiday {
345
0
    my $self = shift @_;
346
0
    my %options = @_;
347
348
0
    my $dbh = C4::Context->dbh();
349
0
    my $updateHoliday = $dbh->prepare("UPDATE repeatable_holidays SET title = ?, description = ? WHERE branchcode = ? AND weekday = ?");
350
0
    $updateHoliday->execute( $options{title},$options{description},$self->{branchcode},$options{weekday});
351
0
    $self->{'week_days_holidays'}->{$options{weekday}}{title} = $options{title};
352
0
    $self->{'week_days_holidays'}->{$options{weekday}}{description} = $options{description};
353
0
    return $self;
354}
355
356 - 373
=head2 ModDaymonthholiday

    ModDaymonthholiday(day => $day,
                       month => $month,
                       title => $title,
                       description => $description);

Modifies the title and description for a day/month holiday for $self->{branchcode}.

C<$day> The day of the month for the update.

C<$month> The month to be used for the update.

C<$title> The title to be updated for the holiday.

C<$description> The description to be update for the holiday.

=cut
374
375sub ModDaymonthholiday {
376
0
    my $self = shift @_;
377
0
    my %options = @_;
378
379
0
    my $dbh = C4::Context->dbh();
380
0
    my $updateHoliday = $dbh->prepare("UPDATE repeatable_holidays SET title = ?, description = ? WHERE month = ? AND day = ? AND branchcode = ?");
381
0
       $updateHoliday->execute( $options{title},$options{description},$options{month},$options{day},$self->{branchcode});
382
0
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title};
383
0
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description};
384
0
    return $self;
385}
386
387 - 407
=head2 ModSingleholiday

    ModSingleholiday(day => $day,
                     month => $month,
                     year => $year,
                     title => $title,
                     description => $description);

Modifies the title and description for a single holiday for $self->{branchcode}.

C<$day> Is the day of the month to make the update.

C<$month> Is the month to make the update.

C<$year> Is the year to make the update.

C<$title> Is the title to update for the holiday formed by $year/$month/$day.

C<$description> Is the description to update for the holiday formed by $year/$month/$day.

=cut
408
409sub ModSingleholiday {
410
0
    my $self = shift @_;
411
0
    my %options = @_;
412
413
0
    my $dbh = C4::Context->dbh();
414
0
    my $isexception = 0;
415
0
    my $updateHoliday = $dbh->prepare("UPDATE special_holidays SET title = ?, description = ? WHERE day = ? AND month = ? AND year = ? AND branchcode = ? AND isexception = ?");
416
0
      $updateHoliday->execute($options{title},$options{description},$options{day},$options{month},$options{year},$self->{branchcode},$isexception);
417
0
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
418
0
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
419
0
    return $self;
420}
421
422 - 442
=head2 ModExceptionholiday

    ModExceptionholiday(day => $day,
                        month => $month,
                        year => $year,
                        title => $title,
                        description => $description);

Modifies the title and description for an exception holiday for $self->{branchcode}.

C<$day> Is the day of the month for the holiday.

C<$month> Is the month for the holiday.

C<$year> Is the year for the holiday.

C<$title> Is the title to be modified for the holiday formed by $year/$month/$day.

C<$description> Is the description to be modified for the holiday formed by $year/$month/$day.

=cut
443
444sub ModExceptionholiday {
445
0
    my $self = shift @_;
446
0
    my %options = @_;
447
448
0
    my $dbh = C4::Context->dbh();
449
0
    my $isexception = 1;
450
0
    my $updateHoliday = $dbh->prepare("UPDATE special_holidays SET title = ?, description = ? WHERE day = ? AND month = ? AND year = ? AND branchcode = ? AND isexception = ?");
451
0
    $updateHoliday->execute($options{title},$options{description},$options{day},$options{month},$options{year},$self->{branchcode},$isexception);
452
0
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
453
0
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
454
0
    return $self;
455}
456
457 - 474
=head2 delete_holiday

    delete_holiday(weekday => $weekday
                   day => $day,
                   month => $month,
                   year => $year);

Delete a holiday for $self->{branchcode}.

C<$weekday> Is the week day to delete.

C<$day> Is the day month to make the date to delete.

C<$month> Is month to make the date to delete.

C<$year> Is year to make the date to delete.

=cut
475
476sub delete_holiday {
477
0
    my $self = shift @_;
478
0
    my %options = @_;
479
480    # Verify what kind of holiday that day is. For example, if it is
481    # a repeatable holiday, this should check if there are some exception
482        # for that holiday rule. Otherwise, if it is a regular holiday, it´s
483    # ok just deleting it.
484
485
0
    my $dbh = C4::Context->dbh();
486
0
    my $isSingleHoliday = $dbh->prepare("SELECT id FROM special_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?) AND (year = ?)");
487
0
    $isSingleHoliday->execute($self->{branchcode}, $options{day}, $options{month}, $options{year});
488
0
    if ($isSingleHoliday->rows) {
489
0
        my $id = $isSingleHoliday->fetchrow;
490
0
        $isSingleHoliday->finish; # Close the last query
491
492
0
        my $deleteHoliday = $dbh->prepare("DELETE FROM special_holidays WHERE id = ?");
493
0
        $deleteHoliday->execute($id);
494
0
        delete($self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"});
495    } else {
496
0
        $isSingleHoliday->finish; # Close the last query
497
498
0
        my $isWeekdayHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE branchcode = ? AND weekday = ?");
499
0
        $isWeekdayHoliday->execute($self->{branchcode}, $options{weekday});
500
0
        if ($isWeekdayHoliday->rows) {
501
0
            my $id = $isWeekdayHoliday->fetchrow;
502
0
            $isWeekdayHoliday->finish; # Close the last query
503
504
0
            my $updateExceptions = $dbh->prepare("UPDATE special_holidays SET isexception = 0 WHERE (WEEKDAY(CONCAT(special_holidays.year,'-',special_holidays.month,'-',special_holidays.day)) = ?) AND (branchcode = ?)");
505
0
            $updateExceptions->execute($options{weekday}, $self->{branchcode});
506
0
            $updateExceptions->finish; # Close the last query
507
508
0
            my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE id = ?");
509
0
            $deleteHoliday->execute($id);
510
0
            delete($self->{'week_days_holidays'}->{$options{weekday}});
511        } else {
512
0
            $isWeekdayHoliday->finish; # Close the last query
513
514
0
            my $isDayMonthHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?)");
515
0
            $isDayMonthHoliday->execute($self->{branchcode}, $options{day}, $options{month});
516
0
            if ($isDayMonthHoliday->rows) {
517
0
                my $id = $isDayMonthHoliday->fetchrow;
518
0
                $isDayMonthHoliday->finish;
519
0
                my $updateExceptions = $dbh->prepare("UPDATE special_holidays SET isexception = 0 WHERE (special_holidays.branchcode = ?) AND (special_holidays.day = ?) and (special_holidays.month = ?)");
520
0
                $updateExceptions->execute($self->{branchcode}, $options{day}, $options{month});
521
0
                $updateExceptions->finish; # Close the last query
522
523
0
                my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE (id = ?)");
524
0
                $deleteHoliday->execute($id);
525
0
                delete($self->{'day_month_holidays'}->{"$options{month}/$options{day}"});
526            }
527        }
528    }
529
0
    return $self;
530}
531
532 - 542
=head2 isHoliday

    $isHoliday = isHoliday($day, $month $year);

C<$day> Is the day to check whether if is a holiday or not.

C<$month> Is the month to check whether if is a holiday or not.

C<$year> Is the year to check whether if is a holiday or not.

=cut
543
544sub isHoliday {
545
0
    my ($self, $day, $month, $year) = @_;
546        # FIXME - date strings are stored in non-padded metric format. should change to iso.
547        # FIXME - should change arguments to accept C4::Dates object
548
0
        $month=$month+0;
549
0
        $year=$year+0;
550
0
        $day=$day+0;
551
0
    my $weekday = &Date::Calc::Day_of_Week($year, $month, $day) % 7;
552
0
    my $weekDays = $self->get_week_days_holidays();
553
0
    my $dayMonths = $self->get_day_month_holidays();
554
0
    my $exceptions = $self->get_exception_holidays();
555
0
    my $singles = $self->get_single_holidays();
556
0
    if (defined($exceptions->{"$year/$month/$day"})) {
557
0
        return 0;
558    } else {
559
0
        if ((exists($weekDays->{$weekday})) ||
560            (exists($dayMonths->{"$month/$day"})) ||
561            (exists($singles->{"$year/$month/$day"}))) {
562
0
                  return 1;
563        } else {
564
0
            return 0;
565        }
566    }
567
568}
569
570 - 578
=head2 addDate

    my ($day, $month, $year) = $calendar->addDate($date, $offset)

C<$date> is a C4::Dates object representing the starting date of the interval.

C<$offset> Is the number of days that this function has to count from $date.

=cut
579
580sub addDate {
581
0
    my ($self, $startdate, $offset) = @_;
582
0
    my ($year,$month,$day) = split("-",$startdate->output('iso'));
583
0
        my $daystep = 1;
584
0
        if ($offset < 0) { # In case $offset is negative
585       # $offset = $offset*(-1);
586
0
                $daystep = -1;
587    }
588
0
        my $daysMode = C4::Context->preference('useDaysMode');
589
0
    if ($daysMode eq 'Datedue') {
590
0
        ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset );
591
0
          while ($self->isHoliday($day, $month, $year)) {
592
0
            ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep);
593        }
594    } elsif($daysMode eq 'Calendar') {
595
0
        while ($offset != 0) {
596
0
            ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep);
597
0
            if (!($self->isHoliday($day, $month, $year))) {
598
0
                $offset = $offset - $daystep;
599                        }
600        }
601        } else { ## ($daysMode eq 'Days')
602
0
        ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset );
603    }
604
0
    return(C4::Dates->new( sprintf("%04d-%02d-%02d",$year,$month,$day),'iso'));
605}
606
607 - 615
=head2 daysBetween

    my $daysBetween = $calendar->daysBetween($startdate, $enddate)

C<$startdate> and C<$enddate> are C4::Dates objects that define the interval.

Returns the number of non-holiday days in the interval.
useDaysMode syspref has no effect here.
=cut
616
617sub daysBetween ($$$) {
618
0
    my $self = shift or return undef;
619
0
    my $startdate = shift or return undef;
620
0
    my $enddate = shift or return undef;
621
0
        my ($yearFrom,$monthFrom,$dayFrom) = split("-",$startdate->output('iso'));
622
0
        my ($yearTo, $monthTo, $dayTo ) = split("-", $enddate->output('iso'));
623
0
        if (Date_to_Days($yearFrom,$monthFrom,$dayFrom) > Date_to_Days($yearTo,$monthTo,$dayTo)) {
624
0
                return 0;
625                # we don't go backwards ( FIXME - handle this error better )
626        }
627
0
    my $count = 0;
628
0
    while (1) {
629
0
        ($yearFrom != $yearTo or $monthFrom != $monthTo or $dayFrom != $dayTo) or last; # if they all match, it's the last day
630
0
        unless ($self->isHoliday($dayFrom, $monthFrom, $yearFrom)) {
631
0
            $count++;
632        }
633
0
        ($yearFrom, $monthFrom, $dayFrom) = &Date::Calc::Add_Delta_Days($yearFrom, $monthFrom, $dayFrom, 1);
634    }
635
0
    return($count);
636}
637
6381;
639