ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilCalendarRecurrenceCalculator.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
28{
29 protected string $timezone = ilTimeZone::UTC;
30 protected ilLogger $log;
31
32 protected bool $limit_reached = false;
33 protected ?ilDateList $valid_dates = null;
34 protected ?ilDateTime $period_start = null;
35 protected ?ilDateTime $period_end = null;
36 protected ?ilDateTime $start = null;
37
40 protected int $duration = 0;
41 protected string $frequence_context = '';
42
44 {
45 $this->log = $GLOBALS['DIC']->logger()->cal();
46 $this->event = $entry;
47 $this->recurrence = $rec;
48
49 $this->duration = (int) $entry->getEnd()->get(IL_CAL_UNIX) - (int) $entry->getStart()->get(IL_CAL_UNIX);
50 }
51
55 protected function getDuration(): int
56 {
57 return $this->duration;
58 }
59
67 public function calculateDateList(ilDateTime $a_start, ilDateTime $a_end, int $a_limit = -1): ilDateList
68 {
69 $this->valid_dates = $this->initDateList();
70
71 // Check invalid settings: e.g no frequence given, invalid start/end dates ...
72 if (!$this->validateRecurrence()) {
73 $this->valid_dates->add($this->event->getStart());
74 return $this->valid_dates;
75 }
76
77 // Performance fix: Switching the timezone for many dates seems to be
78 // quite time consuming.
79 // Therfore we adjust the timezone of all input dates (start,end, event start)
80 // to the same tz (UTC for fullday events, Recurrence tz for all others).
81 $this->adjustTimeZones($a_start, $a_end);
82
83 // Add start of event if it is in the period
84 if ((ilDateTime::_after($this->event->getStart(), $this->period_start, IL_CAL_DAY) and
85 ilDateTime::_before($this->event->getStart(), $this->period_end, IL_CAL_DAY)) or
86 ilDateTime::_equals($this->event->getStart(), $this->period_start, IL_CAL_DAY)) {
87 // begin-patch aptar
88 $this->valid_dates->add($this->event->getStart());
89 #$this->valid_dates->add($this->event->getStart());
90 // end patch aptar
91 }
92
93 // Calculate recurrences based on frequency (e.g. MONTHLY)
94 $time = microtime(true);
95
97 $end = $this->optimizeEndingTime();
98
99 #echo "ZEIT: ADJUST: ".(microtime(true) - $time).'<br>';
100 $counter = 0;
101 do {
102 ++$counter;
103 // initialize context for applied rules
104 // E.g
105 // RRULE:FREQ=YEARLY;BYMONTH=1;BYWEEKNO=1,50 => context for BYWERKNO is monthly because it filters to the weeks in JAN
106 // RRULE:FREQ=YEARLY;BYWEEKNO=1,50 => context for BYWERKNO is yearly because it adds all weeks.
107 $this->frequence_context = $this->recurrence->getFrequenceType();
108
109 $freq_res = $this->initDateList();
110 $freq_res->add($start);
111
112 // Fixed sequence of applying rules (RFC 2445 4.3.10)
113 $freq_res = $this->applyBYMONTHRules($freq_res);
114 #echo "BYMONTH: ".$freq_res;
115
116 $freq_res = $this->applyBYWEEKNORules($freq_res);
117 #echo "BYWEEKNO: ".$freq_res;
118
119 $freq_res = $this->applyBYYEARDAYRules($freq_res);
120 #echo "BYYEARDAY: ".$freq_res;
121
122 $freq_res = $this->applyBYMONTHDAYRules($freq_res);
123 #echo "BYMONTHDAY: ".$freq_res;
124
125 #$time = microtime(true);
126 $freq_res = $this->applyBYDAYRules($freq_res);
127 #echo "ZEIT: ".(microtime(true) - $time);
128 #echo "BYDAY: ".$freq_res;
129
130 $freq_res = $this->applyBYSETPOSRules($freq_res);
131 #echo "BYSETPOS: ".$freq_res;
132
133 $freq_res = $this->applyLimits($freq_res);
134 #echo $freq_res;
135
136 $start = $this->incrementByFrequency($start);
137
138 if (ilDateTime::_after($start, $end) || $this->limit_reached) {
139 break;
140 }
141 } while (true);
142
143 $this->applyExclusionDates();
144 $this->applyDurationPeriod($this->valid_dates, $this->period_start, $this->period_end);
145 $this->valid_dates->sort();
146
147 // Restore default timezone
149 return $this->valid_dates;
150 }
151
155 protected function applyDurationPeriod(ilDateList $list, ilDateTime $start, ilDateTime $end): void
156 {
157 $list_copy = clone $list;
158 foreach ($list_copy as $start_date) {
159 $end_date = clone $start_date;
160 $end_date->increment(ilDateTime::MINUTE, $this->getDuration() / 60);
161
162 if (
163 (
164 ilDateTime::_after($start_date, $this->period_end)
165 ) ||
166 (
167 ilDateTime::_before($end_date, $this->period_start)
168 )
169 ) {
170 $this->log->debug('Removed invalid date ' . $start_date . ' <-> ' . $end_date);
171 $list->remove($start_date);
172 }
173 }
174 }
175
179 protected function adjustTimeZones(ilDateTime $a_start, ilDateTime $a_end): void
180 {
181 $this->timezone = $this->event->isFullday() ? ilTimeZone::UTC : $this->recurrence->getTimeZone();
182 ilTimeZone::_setDefaultTimeZone($this->timezone);
183
184 $this->period_start = clone $a_start;
185 $this->period_end = clone $a_end;
186 $this->start = clone $this->event->getStart();
187
188 try {
189 if ($this->event->isFullday()) {
190 $this->period_start->switchTimeZone(ilTimeZone::UTC);
191 $this->period_end->switchTimeZone(ilTimeZone::UTC);
192 $this->start->switchTimeZone(ilTimeZone::UTC);
193 } else {
194 $this->period_start->switchTimeZone($this->recurrence->getTimeZone());
195 $this->period_end->switchTimeZone($this->recurrence->getTimeZone());
196 $this->start->switchTimeZone($this->recurrence->getTimeZone());
197 }
198 return;
199 } catch (ilDateTimeException $e) {
200 $this->log->debug(': ' . $e->getMessage());
201 return;
202 }
203 }
204
205 protected function optimizeStartingTime(): ilDateTime
206 {
207 // starting time cannot be optimzed if RRULE UNTIL is given.
208 // In that case we have to calculate all dates until "UNTIL" is reached.
209 if ($this->recurrence->getFrequenceUntilCount() > 0) {
210 // Switch the date to the original defined timzone for this recurrence
211 return $this->createDate($this->start->get(IL_CAL_UNIX, '', $this->timezone));
212 }
213 $optimized = $start = $this->createDate($this->start->get(IL_CAL_UNIX, '', $this->timezone));
214 while (ilDateTime::_before($start, $this->period_start)) {
215 $optimized = clone $start;
216 $start = $this->incrementByFrequency($start);
217 }
218 return $optimized;
219 }
220
221 protected function optimizeEndingTime(): ilDateTime
222 {
223 $end = clone $this->period_start;
224 $end = $this->incrementByFrequency($end);
225 if (ilDateTime::_before($this->period_end, $end, ilDateTime::DAY)) {
226 return $end;
227 }
228 return $this->period_end;
229 }
230
232 {
233 switch ($this->recurrence->getFrequenceType()) {
235 $start->increment(ilDateTime::YEAR, $this->recurrence->getInterval());
236 break;
237
239 $start->increment(ilDateTime::MONTH, $this->recurrence->getInterval());
240 break;
241
243 $start->increment(ilDateTime::WEEK, $this->recurrence->getInterval());
244 break;
245
247 $start->increment(ilDateTime::DAY, $this->recurrence->getInterval());
248 break;
249
250 default:
251 $this->log->warning('No frequence defined.');
252 break;
253 }
254 return $start;
255 }
256
257 protected function applyBYMONTHRules(ilDateList $list): ilDateList
258 {
259 // return unmodified, if no bymonth rules are available
260 if (!$this->recurrence->getBYMONTHList()) {
261 return $list;
262 }
263 $month_list = $this->initDateList();
264 foreach ($list->get() as $date) {
265 foreach ($this->recurrence->getBYMONTHList() as $month) {
266 // YEARLY rules extend the seed to every month given in the BYMONTH rule
267 // Rules < YEARLY must match the month of the seed
268 if ($this->recurrence->getFrequenceType() == ilCalendarRecurrence::FREQ_YEARLY) {
269 $month_date = $this->createDate($date->get(IL_CAL_UNIX, '', $this->timezone));
270 $month_date->increment(
272 -($date->get(IL_CAL_FKT_DATE, 'n', $this->timezone) - $month)
273 );
274
275 #echo "BYMONTH: ".$month_date;
276 $month_list->add($month_date);
277 } elseif ($date->get(IL_CAL_FKT_DATE, 'n', $this->timezone) == $month) {
278 $month_list->add($date);
279 }
280 }
281 }
282 // decrease the frequence_context for YEARLY rules
283 if ($this->recurrence->getFrequenceType() == ilCalendarRecurrence::FREQ_YEARLY) {
284 $this->frequence_context = ilCalendarRecurrence::FREQ_MONTHLY;
285 }
286 return $month_list;
287 }
288
293 protected function applyBYWEEKNORules(ilDateList $list): ilDateList
294 {
295 if ($this->recurrence->getFrequenceType() != ilCalendarRecurrence::FREQ_YEARLY) {
296 return $list;
297 }
298 // return unmodified, if no byweekno rules are available
299 if (!$this->recurrence->getBYWEEKNOList()) {
300 return $list;
301 }
302 $weeks_list = $this->initDateList();
303 foreach ($list->get() as $seed) {
304 $weeks_in_year = date('W', mktime(0, 0, 0, 12, 28, $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone)));
305 $this->log->debug(': Year ' . $seed->get(
307 'Y',
308 $this->timezone
309 ) . ' has ' . $weeks_in_year . ' weeks');
310 foreach ($this->recurrence->getBYWEEKNOList() as $week_no) {
311 $week_no = $week_no < 0 ? ((int) $weeks_in_year + $week_no + 1) : $week_no;
312
313 switch ($this->frequence_context) {
315 $this->log->debug(': Handling BYWEEKNO in MONTHLY context');
316 // Check if week matches
317 if ($seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone) == $week_no) {
318 $weeks_list->add($seed);
319 }
320 break;
321
323 $this->log->debug(': Handling BYWEEKNO in YEARLY context');
324 $week_diff = $week_no - $seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone);
325
326 // TODO: think about tz here
327 $new_week = $this->createDate($seed->get(IL_CAL_UNIX, '', $this->timezone));
328 $new_week->increment(ilDateTime::WEEK, $week_diff);
329 $weeks_list->add($new_week);
330 break;
331 }
332 }
333 }
334 $this->frequence_context = ilCalendarRecurrence::FREQ_WEEKLY;
335 return $weeks_list;
336 }
337
338 protected function applyBYYEARDAYRules(ilDateList $list): ilDateList
339 {
340 // return unmodified, if no byweekno rules are available
341 if (!$this->recurrence->getBYYEARDAYList()) {
342 return $list;
343 }
344 $days_list = $this->initDateList();
345 foreach ($list->get() as $seed) {
346 $num_days = date('z', mktime(0, 0, 0, 12, 31, $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone)));
347 $this->log->debug(': Year ' . $seed->get(
349 'Y',
350 $this->timezone
351 ) . ' has ' . $num_days . ' days.');
352
353 foreach ($this->recurrence->getBYYEARDAYList() as $day_no) {
354 $day_no = $day_no < 0 ? ((int) $num_days + $day_no + 1) : $day_no;
355
356 $day_diff = $day_no - $seed->get(IL_CAL_FKT_DATE, 'z', $this->timezone);
357 $new_day = $this->createDate($seed->get(IL_CAL_UNIX, '', $this->timezone));
358 $new_day->increment(ilDateTime::DAY, $day_diff);
359
360 switch ($this->frequence_context) {
362 // Check if day matches
363 if ($seed->get(IL_CAL_FKT_DATE, 'z', $this->timezone) == $day_no) {
364 $days_list->add($new_day);
365 }
366 break;
368 // Check if week matches
369 if ($seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone) == $new_day->get(
371 'W',
372 $this->timezone
373 )) {
374 $days_list->add($new_day);
375 }
376 break;
378 // Check if month matches
379 if ($seed->get(IL_CAL_FKT_DATE, 'n', $this->timezone) == $new_day->get(
381 'n',
382 $this->timezone
383 )) {
384 $days_list->add($new_day);
385 }
386 break;
388 // Simply add
389 $days_list->add($new_day);
390 break;
391 }
392 }
393 }
394
395 $this->frequence_context = ilCalendarRecurrence::FREQ_DAILY;
396 return $days_list;
397 }
398
399 protected function applyBYMONTHDAYRules(ilDateList $list): ilDateList
400 {
401 // return unmodified, if no byweekno rules are available
402 if (!$this->recurrence->getBYMONTHDAYList()) {
403 return $list;
404 }
405 $days_list = $this->initDateList();
406 foreach ($list->get() as $seed) {
408 (int) $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone),
409 (int) $seed->get(IL_CAL_FKT_DATE, 'n', $this->timezone)
410 );
411 foreach ($this->recurrence->getBYMONTHDAYList() as $bymonth_no) {
412 $day_no = $bymonth_no < 0 ? ($num_days + $bymonth_no + 1) : $bymonth_no;
413 if ($this->frequence_context != ilCalendarRecurrence::FREQ_YEARLY) {
414 if ($day_no < 1 or $day_no > $num_days) {
415 $this->log->debug(': Ignoring BYMONTHDAY rule: ' . $day_no . ' for month ' .
416 $seed->get(IL_CAL_FKT_DATE, 'M', $this->timezone));
417 continue;
418 }
419 }
420 $day_diff = $day_no - $seed->get(IL_CAL_FKT_DATE, 'j', $this->timezone);
421 $new_day = $this->createDate($seed->get(IL_CAL_UNIX, '', $this->timezone));
422 $new_day->increment(ilDateTime::DAY, $day_diff);
423
424 switch ($this->frequence_context) {
426 // Check if day matches
427 if ($seed->get(IL_CAL_FKT_DATE, 'j', $this->timezone) == $day_no) {
428 $days_list->add($new_day);
429 }
430 break;
431
433 // Check if week matches
434 if ($seed->get(IL_CAL_FKT_DATE, 'W', $this->timezone) == $new_day->get(
436 'W',
437 $this->timezone
438 )) {
439 $days_list->add($new_day);
440 }
441 break;
442
444 // seed and new day are in the same month.
445 $days_list->add($new_day);
446 break;
447
449 $h = (int) ($this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE, 'H', $this->timezone));
450 $i = (int) ($this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE, 'i', $this->timezone));
451 $s = (int) ($this->event->isFullday() ? 0 : $seed->get(IL_CAL_FKT_DATE, 's', $this->timezone));
452 $y = (int) $seed->get(IL_CAL_FKT_DATE, 'Y', $this->timezone);
453
454 // TODO: the chosen monthday has to added to all months
455 for ($month = 1; $month <= 12; $month++) {
457 $y,
458 $month
459 );
460 $day_no = $bymonth_no < 0 ? ($num_days + $bymonth_no + 1) : $bymonth_no;
461 if ($day_no < 1 or $day_no > $num_days) {
462 $this->log->debug(': Ignoring BYMONTHDAY rule: ' . $day_no . ' for month ' . $month);
463 } else {
464 $tz_obj = ilTimeZone::_getInstance($this->timezone);
465 $tz_obj->switchTZ();
466 $unix = mktime($h, $i, $s, $month, $day_no, $y);
467 $tz_obj->restoreTZ();
468 $new_day = $this->createDate($unix);
469 $days_list->add($new_day);
470 }
471 }
472 break;
473 }
474 }
475 }
476 $this->frequence_context = ilCalendarRecurrence::FREQ_DAILY;
477 return $days_list;
478 }
479
480 protected function applyBYDAYRules(ilDateList $list): ilDateList
481 {
482 // return unmodified, if no byday rules are available
483 if (!$this->recurrence->getBYDAYList()) {
484 return $list;
485 }
486
487 $days_list = $this->initDateList();
488
489 // generate a list of e.g all Sundays for the given year
490 // or e.g a list of all week days in a give month (FREQ = MONTHLY,WEEKLY or DAILY)
491 $day_array = [];
492 foreach ($list->get() as $seed) {
493 $seed_info = $seed->get(IL_CAL_FKT_GETDATE);
494
495 // TODO: maybe not correct in dst cases
496 $date_info = $seed->get(IL_CAL_FKT_GETDATE);
497 $date_info['mday'] = 1;
498 $date_info['mon'] = 1;
499 $start = $this->createDate($date_info, IL_CAL_FKT_GETDATE);
500
501 switch ($this->frequence_context) {
503 $day_array = $this->getYearWeekDays($seed);
504 break;
505
507 $day_array = $this->getMonthWeekDays($seed_info['year'], $seed_info['mon']);
508 break;
509
511 // TODO or RFC bug: FREQ>WEEKLY;BYMONTH=1;BYDAY=FR returns FR 1.2.2008
512 // Ical says: apply BYMONTH rules and after that apply byday rules on that date list.
513 $day_array = $this->getWeekWeekDays($seed_info);
514 break;
515
517 $day_array[strtoupper(substr($seed->get(IL_CAL_FKT_DATE, 'D'), 0, 2))] = array($seed_info['yday']);
518 break;
519 }
520 foreach ($this->recurrence->getBYDAYList() as $byday) {
521 $year_day = array();
522 $day = strtoupper(substr($byday, -2));
523 $num_by_day = (int) $byday;
524
525 if ($num_by_day) {
526 if ($num_by_day > 0) {
527 if (isset($day_array[$day][$num_by_day - 1])) {
528 $year_day = array($day_array[$day][$num_by_day - 1]);
529 }
530 } elseif (isset($day_array[$day][count($day_array[$day]) + $num_by_day])) {
531 $year_day = array($day_array[$day][count($day_array[$day]) + $num_by_day]);
532 }
533 } elseif (isset($day_array[$day])) {
534 $year_day = $day_array[$day];
535 }
536 foreach ($year_day as $day) {
537 switch ($this->frequence_context) {
542 $tmp_date = clone $start;
543 $tmp_date->increment(IL_CAL_DAY, $day);
544 $days_list->add($tmp_date);
545 break;
546 }
547 }
548 }
549 }
550 return $days_list;
551 }
552
556 protected function getYearWeekDays(ilDateTime $seed): array
557 {
558 $time = microtime(true);
559
560 $year_days = array();
561
562 $current_year = $seed->get(IL_CAL_FKT_DATE, 'Y');
563 $start = new ilDate($current_year . '-01-01', IL_CAL_DATE);
564 $offset = $start->get(IL_CAL_FKT_DATE, 'w');
565 $days = array(0 => 'SU', 1 => 'MO', 2 => 'TU', 3 => 'WE', 4 => 'TH', 5 => 'FR', 6 => 'SA');
566 for ($i = 0; $i < $offset; $i++) {
567 next($days);
568 }
569
570 $num_days = ilCalendarUtil::_isLeapYear($current_year) ? 366 : 365;
571 for ($i = 0; $i < $num_days; $i++) {
572 if (!($current_day = current($days))) {
573 $current_day = reset($days);
574 }
575 $year_days[$current_day][] = $i;
576 next($days);
577 }
578 return $year_days;
579 }
580
581 protected function getMonthWeekDays(int $year, int $month): array
582 {
583 static $month_days = array();
584
585 if (isset($month_days[$year][$month])) {
586 return $month_days[$year][$month];
587 }
588
589 $month_str = $month < 10 ? ('0' . $month) : $month;
590 $begin_month = new ilDate($year . '-' . $month_str . '-01', IL_CAL_DATE);
591 $begin_month_info = $begin_month->get(IL_CAL_FKT_GETDATE);
592
593 $days = array(0 => 'SU', 1 => 'MO', 2 => 'TU', 3 => 'WE', 4 => 'TH', 5 => 'FR', 6 => 'SA');
594 for ($i = 0; $i < $begin_month_info['wday']; $i++) {
595 next($days);
596 }
597 for ($i = $begin_month_info['yday']; $i < $begin_month_info['yday'] + ilCalendarUtil::_getMaxDayOfMonth(
598 $year,
599 $month
600 ); $i++) {
601 if (!($current_day = current($days))) {
602 $current_day = reset($days);
603 }
604 $month_days[$year][$month][$current_day][] = $i;
605 next($days);
606 }
607 return $month_days[$year][$month];
608 }
609
613 protected function getWeekWeekDays(array $seed_info): array
614 {
615 $days = array(0 => 'SU', 1 => 'MO', 2 => 'TU', 3 => 'WE', 4 => 'TH', 5 => 'FR', 6 => 'SA');
616
617 $start_day = $seed_info['yday'] - $seed_info['wday'];
618 foreach ($days as $num => $day) {
619 $week_days[$day][] = $start_day++;
620 }
621 return $week_days;
622 }
623
627 protected function applyBYSETPOSRules(ilDateList $list): ilDateList
628 {
629 // return unmodified, if no bysetpos rules are available
630 if (!$this->recurrence->getBYSETPOSList()) {
631 return $list;
632 }
633 $pos_list = $this->initDateList();
634 $list->sort();
635 $candidates = $list->get();
636 $candidates_count = count($candidates);
637 foreach ($this->recurrence->getBYSETPOSList() as $position) {
638 if ($position > 0 and $date = $list->getAtPosition($position)) {
639 $pos_list->add($date);
640 }
641 if ($position < 0 and $date = $list->getAtPosition($candidates_count + $position + 1)) {
642 $pos_list->add($date);
643 }
644 }
645 return $pos_list;
646 }
647
651 protected function applyLimits(ilDateList $list): bool
652 {
653 $list->sort();
654 // Check valid dates before starting time
655 foreach ($list->get() as $check_date) {
656 if (ilDateTime::_before($check_date, $this->event->getStart(), IL_CAL_DAY)) {
657 $this->log->debug('Removed invalid date: ' . $check_date . ' before starting date: ' . $this->event->getStart());
658 $list->remove($check_date);
659 }
660 }
661
662 // Check count if given
663 if ($this->recurrence->getFrequenceUntilCount()) {
664 foreach ($list->get() as $res) {
665 // check smaller than since the start time counts as one
666 if (count($this->valid_dates->get()) < $this->recurrence->getFrequenceUntilCount()) {
667 $this->valid_dates->add($res);
668 } else {
669 $this->limit_reached = true;
670 return false;
671 }
672 }
673 return true;
674 } elseif ($this->recurrence->getFrequenceUntilDate()) {
675 $date = $this->recurrence->getFrequenceUntilDate();
676 foreach ($list->get() as $res) {
677 if (ilDateTime::_after($res, $date, IL_CAL_DAY)) {
678 $this->limit_reached = true;
679 return false;
680 }
681 $this->valid_dates->add($res);
682 }
683 return true;
684 }
685 $this->valid_dates->merge($list);
686 return true;
687 }
688
689 protected function applyExclusionDates(): void
690 {
691 if (!$this->recurrence->getExclusionDates()) {
692 return;
693 }
694 foreach ($this->recurrence->getExclusionDates() as $excl) {
695 $this->valid_dates->removeByDAY($excl->getDate());
696 }
697 }
698
699 protected function initDateList(): ilDateList
700 {
701 return new ilDateList($this->event->isFullday() ? ilDateList::TYPE_DATE : ilDateList::TYPE_DATETIME);
702 }
703
704 protected function createDate($a_date, $a_format_type = IL_CAL_UNIX): ilDateTime
705 {
706 if ($this->event->isFullday()) {
707 return new ilDate($a_date, $a_format_type);
708 } else {
709 // TODO: the timezone for this recurrence must be stored in the db
710 return new ilDateTime($a_date, $a_format_type, $this->timezone);
711 }
712 }
713
714 protected function validateRecurrence(): bool
715 {
716 return $this->recurrence->validate();
717 }
718}
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.
createDate($a_date, $a_format_type=IL_CAL_UNIX)
__construct(ilDatePeriod $entry, ilCalendarRecurrenceCalculation $rec)
applyBYSETPOSRules(ilDateList $list)
Apply BYSETPOST rules.
getYearWeekDays(ilDateTime $seed)
get a list of year week days according to the BYMONTH rule
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).
getWeekWeekDays(array $seed_info)
get weedays of week
applyDurationPeriod(ilDateList $list, ilDateTime $start, ilDateTime $end)
Apply duration period.
calculateDateList(ilDateTime $a_start, ilDateTime $a_end, int $a_limit=-1)
calculate date list
static _getMaxDayOfMonth(int $a_year, int $a_month)
get max day of month 2008,2 => 29
static _isLeapYear(int $a_year)
check if a given year is a leap year
List of dates.
getAtPosition(int $a_pos)
remove(ilDateTime $remove)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
@classDescription Date and time handling
static _after(ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
compare two dates and check start is after end This method does not consider tz offsets.
static _equals(ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
Check if two date are equal.
switchTimeZone(string $a_timezone_identifier='')
Switch timezone.
get(int $a_format, string $a_format_str='', string $a_tz='')
get formatted date
increment(string $a_type, int $a_count=1)
static _before(ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
compare two dates and check start is before end This method does not consider tz offsets.
Class for single dates.
Component logger with individual log levels by component id.
static _restoreDefaultTimeZone()
static _setDefaultTimeZone(string $a_tz)
static _getInstance(string $a_tz='')
get instance by timezone
getEnd()
Get end of period.
getStart()
Get start of date period.
$res
Definition: ltiservices.php:69
$counter
$GLOBALS["DIC"]
Definition: wac.php:54