ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilCalendarRecurrenceCalculator.php
Go to the documentation of this file.
1<?php
2/*
3 +-----------------------------------------------------------------------------+
4 | ILIAS open source |
5 +-----------------------------------------------------------------------------+
6 | Copyright (c) 1998-2006 ILIAS open source, University of Cologne |
7 | |
8 | This program is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU General Public License |
10 | as published by the Free Software Foundation; either version 2 |
11 | of the License, or (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21 +-----------------------------------------------------------------------------+
22*/
23
24include_once './Services/Calendar/classes/class.ilCalendarRecurrence.php';
25include_once('./Services/Calendar/classes/class.ilDateList.php');
26include_once('./Services/Calendar/classes/class.ilTimeZone.php');
27include_once('./Services/Calendar/classes/class.ilCalendarUtil.php');
28include_once './Services/Calendar/interfaces/interface.ilCalendarRecurrenceCalculation.php';
29
42{
43 protected $timezone = null;
44 protected $log = null;
45
46 protected $limit_reached = false;
47 protected $valid_dates = null;
48 protected $period_start = null;
49 protected $period_end = null;
50 protected $start = null;
51
52 protected $event = null;
53 protected $duration = null;
54 protected $recurrence = null;
55
56 protected $frequence_context = 0;
57
66 {
67 $this->log = $GLOBALS['DIC']->logger()->cal();
68 $this->event = $entry;
69 $this->recurrence = $rec;
70
71 $this->duration = $entry->getEnd()->get(IL_CAL_UNIX) - $entry->getStart()->get(IL_CAL_UNIX);
72 }
73
78 protected function getDuration()
79 {
80 return $this->duration;
81 }
82
91 public function calculateDateListByMonth($a_month, $a_year)
92 {
93 }
94
95
105 public function calculateDateList(ilDateTime $a_start, ilDateTime $a_end, $a_limit = -1)
106 {
107 # echo $a_start;
108 # echo $a_end;
109 # echo $this->event->getStart();
110 # echo $this->event->getEnd();
111
112
113 $this->valid_dates = $this->initDateList();
114
115 // Check invalid settings: e.g no frequence given, invalid start/end dates ...
116 if (!$this->validateRecurrence()) {
117 $this->valid_dates->add($this->event->getStart());
118 return $this->valid_dates;
119 }
120
121 // Performance fix: Switching the timezone for many dates seems to be
122 // quite time consuming.
123 // Therfore we adjust the timezone of all input dates (start,end, event start)
124 // to the same tz (UTC for fullday events, Recurrence tz for all others).
125 $this->adjustTimeZones($a_start, $a_end);
126
127
128
129 // Add start of event if it is in the period
130 if ((ilDateTime::_after($this->event->getStart(), $this->period_start, IL_CAL_DAY) and
131 ilDateTime::_before($this->event->getStart(), $this->period_end, IL_CAL_DAY)) or
132 ilDateTime::_equals($this->event->getStart(), $this->period_start, IL_CAL_DAY)) {
133 // begin-patch aptar
134 $this->valid_dates->add($this->event->getStart());
135 #$this->valid_dates->add($this->event->getStart());
136 // end patch aptar
137 }
138
139 // Calculate recurrences based on frequency (e.g. MONTHLY)
140 $time = microtime(true);
141
142 $start = $this->optimizeStartingTime();
143
144 #echo "ZEIT: ADJUST: ".(microtime(true) - $time).'<br>';
145 $counter = 0;
146 do {
147 ++$counter;
148 // initialize context for applied rules
149 // E.g
150 // RRULE:FREQ=YEARLY;BYMONTH=1;BYWEEKNO=1,50 => context for BYWERKNO is monthly because it filters to the weeks in JAN
151 // RRULE:FREQ=YEARLY;BYWEEKNO=1,50 => context for BYWERKNO is yearly because it adds all weeks.
152 $this->frequence_context = $this->recurrence->getFrequenceType();
153
154 $freq_res = $this->initDateList();
155 $freq_res->add($start);
156
157 // Fixed sequence of applying rules (RFC 2445 4.3.10)
158 $freq_res = $this->applyBYMONTHRules($freq_res);
159 #echo "BYMONTH: ".$freq_res;
160
161 $freq_res = $this->applyBYWEEKNORules($freq_res);
162 #echo "BYWEEKNO: ".$freq_res;
163
164 $freq_res = $this->applyBYYEARDAYRules($freq_res);
165 #echo "BYYEARDAY: ".$freq_res;
166
167
168 $freq_res = $this->applyBYMONTHDAYRules($freq_res);
169 #echo "BYMONTHDAY: ".$freq_res;
170
171 #$time = microtime(true);
172 $freq_res = $this->applyBYDAYRules($freq_res);
173 #echo "ZEIT: ".(microtime(true) - $time);
174 #echo "BYDAY: ".$freq_res;
175
176
177 $freq_res = $this->applyBYSETPOSRules($freq_res);
178 #echo "BYSETPOS: ".$freq_res;
179
180 $freq_res = $this->applyLimits($freq_res);
181 #echo $freq_res;
182
184
185 if (ilDateTime::_after($start, $this->period_end) or $this->limit_reached) {
186 break;
187 }
188 } while (true);
189
190 $this->applyExclusionDates();
191
192 $this->applyDurationPeriod($this->valid_dates, $this->period_start, $this->period_end);
193
194 $this->valid_dates->sort();
195
196 // Restore default timezone
198 return $this->valid_dates;
199 }
200
206 {
207 $list_copy = clone $list;
208 foreach ($list_copy as $start_date) {
209 $end_date = clone $start_date;
210 $end_date->increment(ilDateTime::MINUTE, $this->getDuration() / 60);
211
212 if (
213 (
214 ilDateTime::_after($start_date, $this->period_end)
215 ) ||
216 (
217 ilDateTime::_before($end_date, $this->period_start)
218 )
219 ) {
220 $this->log->debug('Removed invalid date ' . (string) $start_date . ' <-> ' . (string) $end_date);
221 $list->remove($start_date);
222 }
223 }
224 }
225
231 protected function adjustTimeZones(ilDateTime $a_start, ilDateTime $a_end)
232 {
233 $this->timezone = $this->event->isFullday() ? ilTimeZone::UTC : $this->recurrence->getTimeZone();
234 ilTimeZone::_setDefaultTimeZone($this->timezone);
235
236 $this->period_start = clone $a_start;
237 $this->period_end = clone $a_end;
238 $this->start = clone $this->event->getStart();
239
240 try {
241 if ($this->event->isFullday()) {
242 $this->period_start->switchTimeZone(ilTimeZone::UTC);
243 $this->period_end->switchTimeZone(ilTimeZone::UTC);
244 $this->start->switchTimeZone(ilTimeZone::UTC);
245 } else {
246 $this->period_start->switchTimeZone($this->recurrence->getTimeZone());
247 $this->period_end->switchTimeZone($this->recurrence->getTimeZone());
248 $this->start->switchTimeZone($this->recurrence->getTimeZone());
249 }
250 return true;
251 } catch (ilDateTimeException $e) {
252 $this->log->write(__METHOD__ . ': ' . $e->getMessage());
253 return false;
254 }
255 }
256
262 protected function optimizeStartingTime()
263 {
264 $time = microtime(true);
265
266 // starting time cannot be optimzed if RRULE UNTIL is given.
267 // In that case we have to calculate all dates until "UNTIL" is reached.
268 if ($this->recurrence->getFrequenceUntilCount() > 0) {
269 // Switch the date to the original defined timzone for this recurrence
270 return $this->createDate($this->start->get(IL_CAL_UNIX, '', $this->timezone));
271 }
272 $optimized = $start = $this->createDate($this->start->get(IL_CAL_UNIX, '', $this->timezone));
273 while (ilDateTime::_before($start, $this->period_start)) {
274 $optimized = clone $start;
275 $start = $this->incrementByFrequency($start);
276 }
277
278 return $optimized;
279 }
280
286 protected function incrementByFrequency($start)
287 {
288 global $DIC;
289
290 $logger = $DIC->logger()->cal();
291
292 switch ($this->recurrence->getFrequenceType()) {
294 $start->increment(ilDateTime::YEAR, $this->recurrence->getInterval());
295 break;
296
298 $start->increment(ilDateTime::MONTH, $this->recurrence->getInterval());
299 break;
300
302 $start->increment(ilDateTime::WEEK, $this->recurrence->getInterval());
303 break;
304
306 $start->increment(ilDateTime::DAY, $this->recurrence->getInterval());
307 break;
308
309 default:
310 $logger->warning('No frequence defined.');
311 break;
312 }
313 return $start;
314 }
315
323 {
324 // return unmodified, if no bymonth rules are available
325 if (!$this->recurrence->getBYMONTHList()) {
326 return $list;
327 }
328 $month_list = $this->initDateList();
329 foreach ($list->get() as $date) {
330 #echo "SEED: ".$seed;
331
332 foreach ($this->recurrence->getBYMONTHList() as $month) {
333 #echo "RULW_MONTH:".$month;
334
335 // YEARLY rules extend the seed to every month given in the BYMONTH rule
336 // Rules < YEARLY must match the month of the seed
337 if ($this->recurrence->getFrequenceType() == ilCalendarRecurrence::FREQ_YEARLY) {
338 $month_date = $this->createDate($date->get(IL_CAL_UNIX, '', $this->timezone));
339 $month_date->increment(ilDateTime::MONTH, -($date->get(IL_CAL_FKT_DATE, 'n', $this->timezone) - $month));
340
341 #echo "BYMONTH: ".$month_date;
342 $month_list->add($month_date);
343 } elseif ($date->get(IL_CAL_FKT_DATE, 'n', $this->timezone) == $month) {
344 $month_list->add($date);
345 }
346 }
347 }
348 // decrease the frequence_context for YEARLY rules
349 if ($this->recurrence->getFrequenceType() == ilCalendarRecurrence::FREQ_YEARLY) {
350 $this->frequence_context = ilCalendarRecurrence::FREQ_MONTHLY;
351 }
352 return $month_list;
353 }
354
362 {
363 if ($this->recurrence->getFrequenceType() != ilCalendarRecurrence::FREQ_YEARLY) {
364 return $list;
365 }
366 // return unmodified, if no byweekno rules are available
367 if (!$this->recurrence->getBYWEEKNOList()) {
368 return $list;
369 }
370 $weeks_list = $this->initDateList();
371 foreach ($list->get() as $seed) {
372 $weeks_in_year = date('W', mktime(0, 0, 0, 12, 28, $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone)));
373 $this->log->write(__METHOD__ . ': Year ' . $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone) . ' has ' . $weeks_in_year . ' weeks');
374 foreach ($this->recurrence->getBYWEEKNOList() as $week_no) {
375 $week_no = $week_no < 0 ? ($weeks_in_year + $week_no + 1) : $week_no;
376
377 switch ($this->frequence_context) {
379 $this->log->write(__METHOD__ . ': Handling BYWEEKNO in MONTHLY context');
380 // Check if week matches
381 if ($seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone) == $week_no) {
382 $weeks_list->add($seed);
383 }
384 break;
385
387 $this->log->write(__METHOD__ . ': Handling BYWEEKNO in YEARLY context');
388 $week_diff = $week_no - $seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone);
389
390 // TODO: think about tz here
391 $new_week = $this->createDate($seed->get(IL_CAL_UNIX, '', $this->timezone));
392 $new_week->increment(ilDateTime::WEEK, $week_diff);
393 $weeks_list->add($new_week);
394 break;
395 }
396 }
397 }
398 $this->frequence_context = ilCalendarRecurrence::FREQ_WEEKLY;
399
400 return $weeks_list;
401 }
402
409 {
410 // return unmodified, if no byweekno rules are available
411 if (!$this->recurrence->getBYYEARDAYList()) {
412 return $list;
413 }
414 $days_list = $this->initDateList();
415 foreach ($list->get() as $seed) {
416 $num_days = date('z', mktime(0, 0, 0, 12, 31, $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone)));
417 $this->log->write(__METHOD__ . ': Year ' . $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone) . ' has ' . $num_days . ' days.');
418
419 foreach ($this->recurrence->getBYYEARDAYList() as $day_no) {
420 $day_no = $day_no < 0 ? ($num_days + $day_no + 1) : $day_no;
421
422 $day_diff = $day_no - $seed->get(IL_CAL_FKT_DATE, 'z', $this->timezone);
423 $new_day = $this->createDate($seed->get(IL_CAL_UNIX, '', $this->timezone));
424 $new_day->increment(ilDateTime::DAY, $day_diff);
425
426 switch ($this->frequence_context) {
428 // Check if day matches
429 if ($seed->get(IL_CAL_FKT_DATE, 'z', $this->timezone) == $day_no) {
430 $days_list->add($new_day);
431 }
432 break;
434 // Check if week matches
435 if ($seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone) == $new_day->get(IL_CAL_FKT_DATE, 'W', $this->timezone)) {
436 $days_list->add($new_day);
437 }
438 break;
440 // Check if month matches
441 if ($seed->get(IL_CAL_FKT_DATE, 'n', $this->timezone) == $new_day->get(IL_CAL_FKT_DATE, 'n', $this->timezone)) {
442 $days_list->add($new_day);
443 }
444 break;
446 // Simply add
447 $days_list->add($new_day);
448 break;
449 }
450 }
451 }
452
453 $this->frequence_context = ilCalendarRecurrence::FREQ_DAILY;
454 return $days_list;
455 }
456
463 {
464 // return unmodified, if no byweekno rules are available
465 if (!$this->recurrence->getBYMONTHDAYList()) {
466 return $list;
467 }
468 $days_list = $this->initDateList();
469 foreach ($list->get() as $seed) {
471 $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone),
472 $seed->get(IL_CAL_FKT_DATE, 'n', $this->timezone)
473 );
474 /*
475 $num_days = cal_days_in_month(CAL_GREGORIAN,
476 $seed->get(IL_CAL_FKT_DATE,'n',$this->timezone),
477 $seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone));
478 */
479 #$this->log->write(__METHOD__.': Month '.$seed->get(IL_CAL_FKT_DATE,'M',$this->timezone).' has '.$num_days.' days.');
480
481 foreach ($this->recurrence->getBYMONTHDAYList() as $bymonth_no) {
482 $day_no = $bymonth_no < 0 ? ($num_days + $bymonth_no + 1) : $bymonth_no;
483 if ($this->frequence_context != ilCalendarRecurrence::FREQ_YEARLY) {
484 if ($day_no < 1 or $day_no > $num_days) {
485 $this->log->write(__METHOD__ . ': Ignoring BYMONTHDAY rule: ' . $day_no . ' for month ' .
486 $seed->get(IL_CAL_FKT_DATE, 'M', $this->timezone));
487 continue;
488 }
489 }
490 $day_diff = $day_no - $seed->get(IL_CAL_FKT_DATE, 'j', $this->timezone);
491 $new_day = $this->createDate($seed->get(IL_CAL_UNIX, '', $this->timezone));
492 $new_day->increment(ilDateTime::DAY, $day_diff);
493
494 switch ($this->frequence_context) {
496 // Check if day matches
497 #var_dump("<pre>",$seed->get(IL_CAL_FKT_DATE,'z',$this->timezone),$day_no,"</pre>");
498 if ($seed->get(IL_CAL_FKT_DATE, 'j', $this->timezone) == $day_no) {
499 $days_list->add($new_day);
500 }
501 break;
502
504 // Check if week matches
505 if ($seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone) == $new_day->get(IL_CAL_FKT_DATE, 'W', $this->timezone)) {
506 $days_list->add($new_day);
507 }
508 break;
509
511 // seed and new day are in the same month.
512 $days_list->add($new_day);
513 break;
514
516 $h = $this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE, 'H', $this->timezone);
517 $i = $this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE, 'i', $this->timezone);
518 $s = $this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE, 's', $this->timezone);
519 $y = $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone);
520
521 // TODO: the chosen monthday has to added to all months
522 for ($month = 1;$month <= 12;$month++) {
523 #$num_days = cal_days_in_month(CAL_GREGORIAN,
524 # $month,
525 # $y);
527 $y,
528 $month
529 );
530 $day_no = $bymonth_no < 0 ? ($num_days + $bymonth_no + 1) : $bymonth_no;
531 if ($day_no < 1 or $day_no > $num_days) {
532 $this->log->write(__METHOD__ . ': Ignoring BYMONTHDAY rule: ' . $day_no . ' for month ' . $month);
533 } else {
534 $tz_obj = ilTimeZone::_getInstance($this->timezone);
535 $tz_obj->switchTZ();
536 $unix = mktime($h, $i, $s, $month, $day_no, $y);
537 $tz_obj->restoreTZ();
538 $new_day = $this->createDate($unix);
539 $days_list->add($new_day);
540 }
541 }
542 break;
543 }
544 }
545 }
546 $this->frequence_context = ilCalendarRecurrence::FREQ_DAILY;
547 return $days_list;
548 }
549
550
558 protected function applyBYDAYRules(ilDateList $list)
559 {
560 // return unmodified, if no byday rules are available
561 if (!$this->recurrence->getBYDAYList()) {
562 return $list;
563 }
564
565 $days_list = $this->initDateList();
566
567 // generate a list of e.g all Sundays for the given year
568 // or e.g a list of all week days in a give month (FREQ = MONTHLY,WEEKLY or DAILY)
569 foreach ($list->get() as $seed) {
570 $seed_info = $seed->get(IL_CAL_FKT_GETDATE);
571
572 // TODO: maybe not correct in dst cases
573 $date_info = $seed->get(IL_CAL_FKT_GETDATE);
574 $date_info['mday'] = 1;
575 $date_info['mon'] = 1;
576 $start = $this->createDate($date_info, IL_CAL_FKT_GETDATE);
577
578 switch ($this->frequence_context) {
580 $day_sequence = $this->getYearWeekDays($seed);
581 break;
582
584 $day_sequence = $this->getMonthWeekDays($seed_info['year'], $seed_info['mon']);
585 break;
586
588 // TODO or RFC bug: FREQ>WEEKLY;BYMONTH=1;BYDAY=FR returns FR 1.2.2008
589 // Ical says: apply BYMONTH rules and after that apply byday rules on that date list.
590 $day_sequence = $this->getWeekWeekDays($seed_info);
591 break;
592
594 $day_sequence[strtoupper(substr($seed->get(IL_CAL_FKT_DATE, 'D'), 0, 2))] = array($seed_info['yday']);
595 break;
596
597 }
598 foreach ($this->recurrence->getBYDAYList() as $byday) {
599 $year_day = array();
600 $day = strtoupper(substr($byday, -2));
601 $num_by_day = (int) $byday;
602
603 if ($num_by_day) {
604 if ($num_by_day > 0) {
605 if (isset($day_sequence[$day][$num_by_day - 1])) {
606 $year_day = array($day_sequence[$day][$num_by_day - 1]);
607 }
608 } else {
609 if (isset($day_sequence[$day][count($day_sequence[$day]) + $num_by_day])) {
610 $year_day = array($day_sequence[$day][count($day_sequence[$day]) + $num_by_day]);
611 }
612 }
613 } else {
614 if (isset($day_sequence[$day])) {
615 $year_day = $day_sequence[$day];
616 }
617 }
618 foreach ($year_day as $day) {
619 switch ($this->frequence_context) {
624 $tmp_date = clone $start;
625 $tmp_date->increment(IL_CAL_DAY, $day);
626 $days_list->add($tmp_date);
627 break;
628 }
629 }
630 }
631 }
632 #echo $days_list;
633
634 return $days_list;
635 }
636
642 protected function getYearWeekDays(ilDateTime $seed)
643 {
644 $time = microtime(true);
645
646 $year_days = array();
647
648 $current_year = $seed->get(IL_CAL_FKT_DATE, 'Y');
649 $start = new ilDate($current_year . '-01-01', IL_CAL_DATE);
650 $offset = $start->get(IL_CAL_FKT_DATE, 'w');
651 $days = array(0 => 'SU',1 => 'MO',2 => 'TU',3 => 'WE',4 => 'TH',5 => 'FR',6 => 'SA');
652 for ($i = 0;$i < $offset;$i++) {
653 next($days);
654 }
655
656 $num_days = ilCalendarUtil::_isLeapYear($current_year) ? 366 : 365;
657 for ($i = 0;$i < $num_days;$i++) {
658 if (($current_day = current($days)) == false) {
659 $current_day = reset($days);
660 }
661 $year_days[$current_day][] = $i;
662 next($days);
663 }
664 return $year_days;
665 }
666
674 protected function getMonthWeekDays($year, $month)
675 {
676 static $month_days = array();
677
678 if (isset($month_days[$year][$month])) {
679 return $month_days[$year][$month];
680 }
681
682 $month_str = $month < 10 ? ('0' . $month) : $month;
683 $begin_month = new ilDate($year . '-' . $month_str . '-01', IL_CAL_DATE);
684 $begin_month_info = $begin_month->get(IL_CAL_FKT_GETDATE);
685
686 $days = array(0 => 'SU',1 => 'MO',2 => 'TU',3 => 'WE',4 => 'TH',5 => 'FR',6 => 'SA');
687 for ($i = 0;$i < $begin_month_info['wday'];$i++) {
688 next($days);
689 }
690 for ($i = $begin_month_info['yday']; $i < $begin_month_info['yday'] + ilCalendarUtil::_getMaxDayOfMonth($year, $month) ; $i++) {
691 if (($current_day = current($days)) == false) {
692 $current_day = reset($days);
693 }
694 $month_days[$year][$month][$current_day][] = $i;
695 next($days);
696 }
697 return $month_days[$year][$month];
698 }
699
707 protected function getWeekWeekDays($seed_info)
708 {
709 $days = array(0 => 'SU',1 => 'MO',2 => 'TU',3 => 'WE',4 => 'TH',5 => 'FR',6 => 'SA');
710
711 $start_day = $seed_info['yday'] - $seed_info['wday'];
712 foreach ($days as $num => $day) {
713 $week_days[$day][] = $start_day++;
714 }
715 return $week_days;
716 }
717
718
727 {
728 // return unmodified, if no bysetpos rules are available
729 if (!$this->recurrence->getBYSETPOSList()) {
730 return $list;
731 }
732 $pos_list = $this->initDateList();
733 $list->sort();
734 $candidates = $list->get();
735 $candidates_count = count($candidates);
736 foreach ($this->recurrence->getBYSETPOSList() as $position) {
737 if ($position > 0 and $date = $list->getAtPosition($position)) {
738 $pos_list->add($date);
739 }
740 if ($position < 0 and $date = $list->getAtPosition($candidates_count + $position + 1)) {
741 $pos_list->add($date);
742 }
743 }
744 return $pos_list;
745 }
746
754 protected function applyLimits(ilDateList $list)
755 {
756 $list->sort();
757
758 #echo "list: ";
759 #echo $list;
760 #echo '<br />';
761
762 // Check valid dates before starting time
763 foreach ($list->get() as $check_date) {
764 if (ilDateTime::_before($check_date, $this->event->getStart(), IL_CAL_DAY)) {
765 $this->log->debug('Removed invalid date: ' . (string) $check_date . ' before starting date: ' . (string) $this->event->getStart());
766 $list->remove($check_date);
767 }
768 }
769
770 #echo 'Until date '.$this->recurrence->getFrequenceUntilDate();
771
772 // Check count if given
773 if ($this->recurrence->getFrequenceUntilCount()) {
774 foreach ($list->get() as $res) {
775 // check smaller than since the start time counts as one
776 if (count($this->valid_dates->get()) < $this->recurrence->getFrequenceUntilCount()) {
777 $this->valid_dates->add($res);
778 } else {
779 $this->limit_reached = true;
780 return false;
781 }
782 }
783 return true;
784 } elseif ($this->recurrence->getFrequenceUntilDate()) {
785 #echo 'Until date '.$this->recurrence->getFrequenceUntilDate();
786 $date = $this->recurrence->getFrequenceUntilDate();
787 foreach ($list->get() as $res) {
788 #echo 'Check date '.$res;
789 if (ilDateTime::_after($res, $date, IL_CAL_DAY)) {
790 #echo 'Limit reached';
791 $this->limit_reached = true;
792 return false;
793 }
794 $this->valid_dates->add($res);
795 }
796 return true;
797 }
798
799 $this->valid_dates->merge($list);
800 return true;
801 }
802
808 protected function applyExclusionDates()
809 {
810 if (!$this->recurrence->getExclusionDates()) {
811 return true;
812 }
813 foreach ($this->recurrence->getExclusionDates() as $excl) {
814 $this->valid_dates->removeByDAY($excl->getDate());
815 }
816 }
817
823 protected function initDateList()
824 {
825 return new ilDateList($this->event->isFullday() ? ilDateList::TYPE_DATE : ilDateList::TYPE_DATETIME);
826 }
827
833 protected function createDate($a_date, $a_format_type = IL_CAL_UNIX)
834 {
835 if ($this->event->isFullday()) {
836 return new ilDate($a_date, $a_format_type);
837 } else {
838 // TODO: the timezone for this recurrence must be stored in the db
839 return new ilDateTime($a_date, $a_format_type, $this->timezone);
840 }
841 }
842
849 protected function validateRecurrence()
850 {
851 return $this->recurrence->validate();
852 }
853}
An exception for terminatinating execution or to throw for unit testing.
const IL_CAL_FKT_GETDATE
const IL_CAL_DATE
const IL_CAL_UNIX
const IL_CAL_FKT_DATE
const IL_CAL_DAY
Calculates an ilDateList for a given calendar entry and recurrence rule.
getMonthWeekDays($year, $month)
get a list of month days
createDate($a_date, $a_format_type=IL_CAL_UNIX)
create date
applyBYMONTHDAYRules(ilDateList $list)
Apply BYMONTHDAY rules.
__construct(ilDatePeriod $entry, ilCalendarRecurrenceCalculation $rec)
@access public
applyBYSETPOSRules(ilDateList $list)
Apply BYSETPOST rules.
applyBYMONTHRules(ilDateList $list)
Apply BYMONTH rules.
applyBYYEARDAYRules(ilDateList $list)
Apply BYYEARDAY rules.
getYearWeekDays(ilDateTime $seed)
get a list of year week days according to the BYMONTH rule
incrementByFrequency($start)
increment starting time by frequency
calculateDateListByMonth($a_month, $a_year)
calculate day list by month(s) uses a cache of calculated recurring events @access public
calculateDateList(ilDateTime $a_start, ilDateTime $a_end, $a_limit=-1)
calculate date list
applyLimits(ilDateList $list)
Apply limits (count or until)
adjustTimeZones(ilDateTime $a_start, ilDateTime $a_end)
Adjust timezone.
applyBYWEEKNORules(ilDateList $list)
Apply BYWEEKNO rules (1 to 53 and -1 to -53).
applyDurationPeriod(ilDateList $list, ilDateTime $start, ilDateTime $end)
Apply duration period.
applyBYDAYRules(ilDateList $list)
Apply BYDAY rules.
static _getMaxDayOfMonth($a_year, $a_month)
get max day of month 2008,2 => 29
static _isLeapYear($a_year)
check if a given year is a leap year
List of dates.
sort()
Sort list.
Class for DateTime exceptions.
@classDescription Date and time handling
static _equals(ilDateTime $start, ilDateTime $end, $a_compare_field='', $a_tz='')
Check if two date are equal.
switchTimeZone($a_timezone_identifier='')
Switch timezone.
static _after(ilDateTime $start, ilDateTime $end, $a_compare_field='', $a_tz='')
compare two dates and check start is after end This method does not consider tz offsets.
get($a_format, $a_format_str='', $a_tz='')
get formatted date
static _before(ilDateTime $start, ilDateTime $end, $a_compare_field='', $a_tz='')
compare two dates and check start is before end This method does not consider tz offsets.
Class for single dates.
static _restoreDefaultTimeZone()
restore default timezone to server timezone
static _setDefaultTimeZone($a_tz)
set default timezone
static _getInstance($a_tz='')
get instance by timezone
$i
Definition: disco.tpl.php:19
$y
Definition: example_007.php:83
$h
getEnd()
Interface method get end.
getStart()
Interface method get start.
$time
Definition: cron.php:21
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
$s
Definition: pwgen.php:45
if(isset($_REQUEST['delete'])) $list
Definition: registry.php:41
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res