ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
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 
24 include_once './Services/Calendar/classes/class.ilCalendarRecurrence.php';
25 include_once('./Services/Calendar/classes/class.ilDateList.php');
26 include_once('./Services/Calendar/classes/class.ilTimeZone.php');
27 include_once('./Services/Calendar/classes/class.ilCalendarUtil.php');
28 include_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 $recurrence = null;
54 
55  protected $frequence_context = 0;
56 
65  {
66  global $ilLog;
67 
68  $this->log = $ilLog;
69  $this->event = $entry;
70  $this->recurrence = $rec;
71  }
72 
81  public function calculateDateListByMonth($a_month,$a_year)
82  {
83 
84  }
85 
86 
96  public function calculateDateList(ilDateTime $a_start,ilDateTime $a_end,$a_limit = -1)
97  {
98 # echo $a_start;
99 # echo $a_end;
100 # echo $this->event->getStart();
101 # echo $this->event->getEnd();
102 
103 
104  $this->valid_dates = $this->initDateList();
105 
106  // Check invalid settings: e.g no frequence given, invalid start/end dates ...
107  if(!$this->validateRecurrence())
108  {
109  $this->valid_dates->add($this->event->getStart());
110  return $this->valid_dates;
111  }
112 
113  // Performance fix: Switching the timezone for many dates seems to be
114  // quite time consuming.
115  // Therfore we adjust the timezone of all input dates (start,end, event start)
116  // to the same tz (UTC for fullday events, Recurrence tz for all others).
117  $this->adjustTimeZones($a_start,$a_end);
118 
119 
120  // Add start of event if it is in the period
121  if((ilDateTime::_after($this->event->getStart(),$this->period_start,IL_CAL_DAY) and
122  ilDateTime::_before($this->event->getStart(),$this->period_end,IL_CAL_DAY)) or
123  ilDateTime::_equals($this->event->getStart(),$this->period_start,IL_CAL_DAY))
124  {
125  // begin-patch aptar
126  $this->valid_dates->add($this->event->getStart());
127  #$this->valid_dates->add($this->event->getStart());
128  // end patch aptar
129  }
130 
131  // Calculate recurrences based on frequency (e.g. MONTHLY)
132  $time = microtime(true);
133 
134  $start = $this->optimizeStartingTime();
135 
136  #echo "ZEIT: ADJUST: ".(microtime(true) - $time).'<br>';
137  $counter = 0;
138  do
139  {
140  ++$counter;
141  // initialize context for applied rules
142  // E.g
143  // RRULE:FREQ=YEARLY;BYMONTH=1;BYWEEKNO=1,50 => context for BYWERKNO is monthly because it filters to the weeks in JAN
144  // RRULE:FREQ=YEARLY;BYWEEKNO=1,50 => context for BYWERKNO is yearly because it adds all weeks.
145  $this->frequence_context = $this->recurrence->getFrequenceType();
146 
147  $freq_res = $this->initDateList();
148  $freq_res->add($start);
149 
150  // Fixed sequence of applying rules (RFC 2445 4.3.10)
151  $freq_res = $this->applyBYMONTHRules($freq_res);
152  #echo "BYMONTH: ".$freq_res;
153 
154  $freq_res = $this->applyBYWEEKNORules($freq_res);
155  #echo "BYWEEKNO: ".$freq_res;
156 
157  $freq_res = $this->applyBYYEARDAYRules($freq_res);
158  #echo "BYYEARDAY: ".$freq_res;
159 
160 
161  $freq_res = $this->applyBYMONTHDAYRules($freq_res);
162  #echo "BYMONTHDAY: ".$freq_res;
163 
164  #$time = microtime(true);
165  $freq_res = $this->applyBYDAYRules($freq_res);
166  #echo "ZEIT: ".(microtime(true) - $time);
167  #echo "BYDAY: ".$freq_res;
168 
169 
170  $freq_res = $this->applyBYSETPOSRules($freq_res);
171  #echo "BYSETPOS: ".$freq_res;
172 
173  $freq_res = $this->applyLimits($freq_res);
174  #echo $freq_res;
175 
177 
178  if(ilDateTime::_after($start,$this->period_end) or $this->limit_reached)
179  {
180  break;
181  }
182  }
183  while(true);
184 
185  $this->applyExclusionDates();
186 
187  $this->valid_dates->sort();
188 
189  // Restore default timezone
191  return $this->valid_dates;
192  }
193 
199  protected function adjustTimeZones(ilDateTime $a_start,ilDateTime $a_end)
200  {
201  $this->timezone = $this->event->isFullday() ? ilTimeZone::UTC : $this->recurrence->getTimeZone();
202  ilTimeZone::_setDefaultTimeZone($this->timezone);
203 
204  $this->period_start = clone $a_start;
205  $this->period_end = clone $a_end;
206  $this->start = clone $this->event->getStart();
207 
208  try
209  {
210  if($this->event->isFullday())
211  {
212  $this->period_start->switchTimeZone(ilTimeZone::UTC);
213  $this->period_end->switchTimeZone(ilTimeZone::UTC);
214  $this->start->switchTimeZone(ilTimeZone::UTC);
215  }
216  else
217  {
218  $this->period_start->switchTimeZone($this->recurrence->getTimeZone());
219  $this->period_end->switchTimeZone($this->recurrence->getTimeZone());
220  $this->start->switchTimeZone($this->recurrence->getTimeZone());
221  }
222  return true;
223  }
224  catch(ilDateTimeException $e)
225  {
226  $this->log->write(__METHOD__.': '.$e->getMessage());
227  return false;
228  }
229  }
230 
236  protected function optimizeStartingTime()
237  {
238  $time = microtime(true);
239 
240  // starting time cannot be optimzed if RRULE UNTIL is given.
241  // In that case we have to calculate all dates until "UNTIL" is reached.
242  if($this->recurrence->getFrequenceUntilCount() > 0)
243  {
244  // Switch the date to the original defined timzone for this recurrence
245  return $this->createDate($this->start->get(IL_CAL_UNIX,$this->timezone));
246  }
247  $optimized = $start = $this->createDate($this->start->get(IL_CAL_UNIX,$this->timezone));
248  while(ilDateTime::_before($start,$this->period_start))
249  {
250  $optimized = clone $start;
251  $start = $this->incrementByFrequency($start);
252  }
253 
254  return $optimized;
255  }
256 
262  protected function incrementByFrequency($start)
263  {
264  global $ilLog;
265 
266  switch($this->recurrence->getFrequenceType())
267  {
269  $start->increment(ilDateTime::YEAR,$this->recurrence->getInterval());
270  break;
271 
273  $start->increment(ilDateTime::MONTH,$this->recurrence->getInterval());
274  break;
275 
277  $start->increment(ilDateTime::WEEK,$this->recurrence->getInterval());
278  break;
279 
281  $start->increment(ilDateTime::DAY,$this->recurrence->getInterval());
282  break;
283 
284  default:
285  $ilLog->write(__METHOD__.'No frequence defined.');
286  break;
287  }
288  return $start;
289  }
290 
297  protected function applyBYMONTHRules(ilDateList $list)
298  {
299  // return unmodified, if no bymonth rules are available
300  if(!$this->recurrence->getBYMONTHList())
301  {
302  return $list;
303  }
304  $month_list = $this->initDateList();
305  foreach($list->get() as $date)
306  {
307  #echo "SEED: ".$seed;
308 
309  foreach($this->recurrence->getBYMONTHList() as $month)
310  {
311  #echo "RULW_MONTH:".$month;
312 
313  // YEARLY rules extend the seed to every month given in the BYMONTH rule
314  // Rules < YEARLY must match the month of the seed
315  if($this->recurrence->getFrequenceType() == ilCalendarRecurrence::FREQ_YEARLY)
316  {
317  $month_date = $this->createDate($date->get(IL_CAL_UNIX,'',$this->timezone));
318  $month_date->increment(ilDateTime::MONTH,-($date->get(IL_CAL_FKT_DATE,'n',$this->timezone) - $month));
319 
320  #echo "BYMONTH: ".$month_date;
321  $month_list->add($month_date);
322  }
323  elseif($date->get(IL_CAL_FKT_DATE,'n',$this->timezone) == $month)
324  {
325  $month_list->add($date);
326  }
327  }
328  }
329  // decrease the frequence_context for YEARLY rules
330  if($this->recurrence->getFrequenceType() == ilCalendarRecurrence::FREQ_YEARLY)
331  {
332  $this->frequence_context = ilCalendarRecurrence::FREQ_MONTHLY;
333  }
334  return $month_list;
335  }
336 
343  protected function applyBYWEEKNORules(ilDateList $list)
344  {
345  if($this->recurrence->getFrequenceType() != ilCalendarRecurrence::FREQ_YEARLY)
346  {
347  return $list;
348  }
349  // return unmodified, if no byweekno rules are available
350  if(!$this->recurrence->getBYWEEKNOList())
351  {
352  return $list;
353  }
354  $weeks_list = $this->initDateList();
355  foreach($list->get() as $seed)
356  {
357  $weeks_in_year = date('W',mktime(0,0,0,12,28,$seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone)));
358  $this->log->write(__METHOD__.': Year '.$seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone).' has '.$weeks_in_year.' weeks');
359  foreach($this->recurrence->getBYWEEKNOList() as $week_no)
360  {
361  $week_no = $week_no < 0 ? ($weeks_in_year + $week_no + 1) : $week_no;
362 
363  switch($this->frequence_context)
364  {
366  $this->log->write(__METHOD__.': Handling BYWEEKNO in MONTHLY context');
367  // Check if week matches
368  if($seed->get(IL_CAL_FKT_DATE,'W',$this->timezone) == $week_no)
369  {
370  $weeks_list->add($seed);
371  }
372  break;
373 
375  $this->log->write(__METHOD__.': Handling BYWEEKNO in YEARLY context');
376  $week_diff = $week_no - $seed->get(IL_CAL_FKT_DATE,'W',$this->timezone);
377 
378  // TODO: think about tz here
379  $new_week = $this->createDate($seed->get(IL_CAL_UNIX,'',$this->timezone));
380  $new_week->increment(ilDateTime::WEEK,$week_diff);
381  $weeks_list->add($new_week);
382  break;
383  }
384  }
385  }
386  $this->frequence_context = ilCalendarRecurrence::FREQ_WEEKLY;
387 
388  return $weeks_list;
389  }
390 
396  protected function applyBYYEARDAYRules(ilDateList $list)
397  {
398  // return unmodified, if no byweekno rules are available
399  if(!$this->recurrence->getBYYEARDAYList())
400  {
401  return $list;
402  }
403  $days_list = $this->initDateList();
404  foreach($list->get() as $seed)
405  {
406  $num_days = date('z',mktime(0,0,0,12,31,$seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone)));
407  $this->log->write(__METHOD__.': Year '.$seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone).' has '.$num_days.' days.');
408 
409  foreach($this->recurrence->getBYYEARDAYList() as $day_no)
410  {
411  $day_no = $day_no < 0 ? ($num_days + $day_no + 1) : $day_no;
412 
413  $day_diff = $day_no - $seed->get(IL_CAL_FKT_DATE,'z',$this->timezone);
414  $new_day = $this->createDate($seed->get(IL_CAL_UNIX,'',$this->timezone));
415  $new_day->increment(ilDateTime::DAY,$day_diff);
416 
417  switch($this->frequence_context)
418  {
420  // Check if day matches
421  if($seed->get(IL_CAL_FKT_DATE,'z',$this->timezone) == $day_no)
422  {
423  $days_list->add($new_day);
424  }
425  break;
427  // Check if week matches
428  if($seed->get(IL_CAL_FKT_DATE,'W',$this->timezone) == $new_day->get(IL_CAL_FKT_DATE,'W',$this->timezone))
429  {
430  $days_list->add($new_day);
431  }
432  break;
434  // Check if month matches
435  if($seed->get(IL_CAL_FKT_DATE,'n',$this->timezone) == $new_day->get(IL_CAL_FKT_DATE,'n',$this->timezone))
436  {
437  $days_list->add($new_day);
438  }
439  break;
441  // Simply add
442  $day_list->add($new_day);
443  break;
444  }
445  }
446  }
447 
448  $this->frequence_context = ilCalendarRecurrence::FREQ_DAILY;
449  return $days_list;
450  }
451 
457  protected function applyBYMONTHDAYRules(ilDateList $list)
458  {
459  // return unmodified, if no byweekno rules are available
460  if(!$this->recurrence->getBYMONTHDAYList())
461  {
462  return $list;
463  }
464  $days_list = $this->initDateList();
465  foreach($list->get() as $seed)
466  {
468  $seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone),
469  $seed->get(IL_CAL_FKT_DATE,'n',$this->timezone));
470  /*
471  $num_days = cal_days_in_month(CAL_GREGORIAN,
472  $seed->get(IL_CAL_FKT_DATE,'n',$this->timezone),
473  $seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone));
474  */
475  #$this->log->write(__METHOD__.': Month '.$seed->get(IL_CAL_FKT_DATE,'M',$this->timezone).' has '.$num_days.' days.');
476 
477  foreach($this->recurrence->getBYMONTHDAYList() as $bymonth_no)
478  {
479  $day_no = $bymonth_no < 0 ? ($num_days + $bymonth_no + 1) : $bymonth_no;
480  if($this->frequence_context != ilCalendarRecurrence::FREQ_YEARLY)
481  {
482  if($day_no < 1 or $day_no > $num_days)
483  {
484  $this->log->write(__METHOD__.': Ignoring BYMONTHDAY rule: '.$day_no.' for month '.
485  $seed->get(IL_CAL_FKT_DATE,'M',$this->timezone));
486  continue;
487  }
488  }
489  $day_diff = $day_no - $seed->get(IL_CAL_FKT_DATE,'j',$this->timezone);
490  $new_day = $this->createDate($seed->get(IL_CAL_UNIX,'',$this->timezone));
491  $new_day->increment(ilDateTime::DAY,$day_diff);
492 
493  switch($this->frequence_context)
494  {
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  {
500  $days_list->add($new_day);
501  }
502  break;
503 
505  // Check if week matches
506  if($seed->get(IL_CAL_FKT_DATE,'W',$this->timezone) == $new_day->get(IL_CAL_FKT_DATE,'W',$this->timezone))
507  {
508  $days_list->add($new_day);
509  }
510  break;
511 
513  // seed and new day are in the same month.
514  $days_list->add($new_day);
515  break;
516 
518  $h = $this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE,'H',$this->timezone);
519  $i = $this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE,'i',$this->timezone);
520  $s = $this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE,'s',$this->timezone);
521  $y = $seed->get(IL_CAL_FKT_DATE,'Y',$this->timezone);
522 
523  // TODO: the chosen monthday has to added to all months
524  for($month = 1;$month <= 12;$month++)
525  {
526  #$num_days = cal_days_in_month(CAL_GREGORIAN,
527  # $month,
528  # $y);
530  $y,
531  $month);
532  $day_no = $bymonth_no < 0 ? ($num_days + $bymonth_no + 1) : $bymonth_no;
533  if($day_no < 1 or $day_no > $num_days)
534  {
535  $this->log->write(__METHOD__.': Ignoring BYMONTHDAY rule: '.$day_no.' for month '.$month);
536  }
537  else
538  {
539  $tz_obj = ilTimeZone::_getInstance($this->timezone);
540  $tz_obj->switchTZ();
541  $unix = mktime($h,$i,$s,$month,$day_no,$y);
542  $tz_obj->restoreTZ();
543  $new_day = $this->createDate($unix);
544  $days_list->add($new_day);
545  }
546  }
547  break;
548  }
549  }
550  }
551  $this->frequence_context = ilCalendarRecurrence::FREQ_DAILY;
552  return $days_list;
553  }
554 
555 
563  protected function applyBYDAYRules(ilDateList $list)
564  {
565  // return unmodified, if no byday rules are available
566  if(!$this->recurrence->getBYDAYList())
567  {
568  return $list;
569  }
570 
571  $days_list = $this->initDateList();
572 
573  // generate a list of e.g all Sundays for the given year
574  // or e.g a list of all week days in a give month (FREQ = MONTHLY,WEEKLY or DAILY)
575  foreach($list->get() as $seed)
576  {
577  $seed_info = $seed->get(IL_CAL_FKT_GETDATE);
578 
579  // TODO: maybe not correct in dst cases
580  $date_info = $seed->get(IL_CAL_FKT_GETDATE);
581  $date_info['mday'] = 1;
582  $date_info['mon'] = 1;
583  $start = $this->createDate($date_info,IL_CAL_FKT_GETDATE);
584 
585  switch($this->frequence_context)
586  {
588  $day_sequence = $this->getYearWeekDays($seed);
589  break;
590 
592  $day_sequence = $this->getMonthWeekDays($seed_info['year'],$seed_info['mon']);
593  break;
594 
596  // TODO or RFC bug: FREQ>WEEKLY;BYMONTH=1;BYDAY=FR returns FR 1.2.2008
597  // Ical says: apply BYMONTH rules and after that apply byday rules on that date list.
598  $day_sequence = $this->getWeekWeekDays($seed_info);
599  break;
600 
602  $day_sequence[strtoupper(substr($seed->get(IL_CAL_FKT_DATE,'D'),0,2))] = array($seed_info['yday']);
603  break;
604 
605  }
606  foreach($this->recurrence->getBYDAYList() as $byday)
607  {
608  $year_day = array();
609  $day = strtoupper(substr($byday,-2));
610  $num_by_day = (int) $byday;
611 
612  if($num_by_day)
613  {
614  if($num_by_day > 0)
615  {
616  if(isset($day_sequence[$day][$num_by_day - 1]))
617  {
618  $year_day = array($day_sequence[$day][$num_by_day - 1]);
619  }
620  }
621  else
622  {
623  if(isset($day_sequence[$day][count($day_sequence[$day]) + $num_by_day]))
624  {
625  $year_day = array($day_sequence[$day][count($day_sequence[$day]) + $num_by_day]);
626  }
627  }
628  }
629  else
630  {
631  if(isset($day_sequence[$day]))
632  {
633  $year_day = $day_sequence[$day];
634  }
635  }
636  foreach($year_day as $day)
637  {
638  switch($this->frequence_context)
639  {
644  $tmp_date = clone $start;
645  $tmp_date->increment(IL_CAL_DAY,$day);
646  $days_list->add($tmp_date);
647  break;
648  }
649 
650  }
651  }
652  }
653  #echo $days_list;
654 
655  return $days_list;
656  }
657 
663  protected function getYearWeekDays(ilDateTime $seed)
664  {
665  $time = microtime(true);
666 
667  $year_days = array();
668 
669  $current_year = $seed->get(IL_CAL_FKT_DATE,'Y');
670  $start = new ilDate($current_year.'-01-01',IL_CAL_DATE);
671  $offset = $start->get(IL_CAL_FKT_DATE,'w');
672  $days = array(0 => 'SU',1 => 'MO',2 => 'TU',3 => 'WE',4 => 'TH',5 => 'FR',6 => 'SA');
673  for($i = 0;$i < $offset;$i++)
674  {
675  next($days);
676  }
677 
678  $num_days = ilCalendarUtil::_isLeapYear($current_year) ? 366 : 365;
679  for($i = 0;$i < $num_days;$i++)
680  {
681  if(($current_day = current($days)) == false)
682  {
683  $current_day = reset($days);
684  }
685  $year_days[$current_day][] = $i;
686  next($days);
687  }
688  return $year_days;
689  }
690 
698  protected function getMonthWeekDays($year,$month)
699  {
700  static $month_days = array();
701 
702  if(isset($month_days[$year][$month]))
703  {
704  return $month_days[$year][$month];
705  }
706 
707  $month_str = $month < 10 ? ('0'.$month) : $month;
708  $begin_month = new ilDate($year.'-'.$month_str.'-01',IL_CAL_DATE);
709  $begin_month_info = $begin_month->get(IL_CAL_FKT_GETDATE);
710 
711  $days = array(0 => 'SU',1 => 'MO',2 => 'TU',3 => 'WE',4 => 'TH',5 => 'FR',6 => 'SA');
712  for($i = 0;$i < $begin_month_info['wday'];$i++)
713  {
714  next($days);
715  }
716  for($i = $begin_month_info['yday']; $i < $begin_month_info['yday'] + ilCalendarUtil::_getMaxDayOfMonth($year,$month) ; $i++)
717  {
718  if(($current_day = current($days)) == false)
719  {
720  $current_day = reset($days);
721  }
722  $month_days[$year][$month][$current_day][] = $i;
723  next($days);
724  }
725  return $month_days[$year][$month];
726  }
727 
735  protected function getWeekWeekDays($seed_info)
736  {
737  $days = array(0 => 'SU',1 => 'MO',2 => 'TU',3 => 'WE',4 => 'TH',5 => 'FR',6 => 'SA');
738 
739  $start_day = $seed_info['yday'] - $seed_info['wday'];
740  foreach($days as $num => $day)
741  {
742  $week_days[$day][] = $start_day++;
743  }
744  return $week_days;
745  }
746 
747 
755  protected function applyBYSETPOSRules(ilDateList $list)
756  {
757  // return unmodified, if no bysetpos rules are available
758  if(!$this->recurrence->getBYSETPOSList())
759  {
760  return $list;
761  }
762  $pos_list = $this->initDateList();
763  $list->sort();
764  $candidates = $list->get();
765  $candidates_count = count($candidates);
766  foreach($this->recurrence->getBYSETPOSList() as $position)
767  {
768  if($position > 0 and $date = $list->getAtPosition($position))
769  {
770  $pos_list->add($date);
771  }
772  if($position < 0 and $date = $list->getAtPosition($candidates_count + $position + 1))
773  {
774  $pos_list->add($date);
775  }
776  }
777  return $pos_list;
778  }
779 
787  protected function applyLimits(ilDateList $list)
788  {
789  $list->sort();
790 
791  #echo "list: ";
792  #echo $list;
793  #echo '<br />';
794 
795  // Check valid dates before starting time
796  foreach($list->get() as $check_date)
797  {
798  if(ilDateTime::_before($check_date,$this->event->getStart(),IL_CAL_DAY))
799  {
800  #echo 'Removed: '.$check_date.'<br/>';
801  $list->remove($check_date);
802  }
803  }
804 
805  #echo 'Until date '.$this->recurrence->getFrequenceUntilDate();
806 
807  // Check count if given
808  if($this->recurrence->getFrequenceUntilCount())
809  {
810  foreach($list->get() as $res)
811  {
812  // check smaller than since the start time counts as one
813  if(count($this->valid_dates->get()) < $this->recurrence->getFrequenceUntilCount())
814  {
815  $this->valid_dates->add($res);
816  }
817  else
818  {
819  $this->limit_reached = true;
820  return false;
821  }
822  }
823  return true;
824  }
825  elseif($this->recurrence->getFrequenceUntilDate())
826  {
827  #echo 'Until date '.$this->recurrence->getFrequenceUntilDate();
828  $date = $this->recurrence->getFrequenceUntilDate();
829  foreach($list->get() as $res)
830  {
831  #echo 'Check date '.$res;
833  {
834  #echo 'Limit reached';
835  $this->limit_reached = true;
836  return false;
837  }
838  $this->valid_dates->add($res);
839  }
840  return true;
841  }
842 
843  $this->valid_dates->merge($list);
844  return true;
845  }
846 
852  protected function applyExclusionDates()
853  {
854  if(!$this->recurrence->getExclusionDates())
855  {
856  return true;
857  }
858  foreach($this->recurrence->getExclusionDates() as $excl)
859  {
860  $this->valid_dates->removeByDAY($excl->getDate());
861  }
862  }
863 
869  protected function initDateList()
870  {
871  return new ilDateList($this->event->isFullday() ? ilDateList::TYPE_DATE : ilDateList::TYPE_DATETIME);
872  }
873 
879  protected function createDate($a_date,$a_format_type = IL_CAL_UNIX)
880  {
881  if($this->event->isFullday())
882  {
883  return new ilDate($a_date,$a_format_type);
884  }
885  else
886  {
887  // TODO: the timezone for this recurrence must be stored in the db
888  return new ilDateTime($a_date,$a_format_type,$this->timezone);
889  }
890  }
891 
898  protected function validateRecurrence()
899  {
900  return $this->recurrence->validate();
901  }
902 }
903 
904 
905 ?>