/** * updates an array with dates based on a recur pattern * * if missing, UNTIL is set 1 year from startdate (emergency break) * * @author Kjell-Inge Gustafsson, kigkonsult <*****@*****.**> * @since 2.10.19 - 2011-10-31 * @param array $result, array to update, array([timestamp] => timestamp) * @param array $recur, pattern for recurrency (only value part, params ignored) * @param array $wdate, component start date * @param array $startdate, start date * @param array $enddate, optional * @return void * @todo BYHOUR, BYMINUTE, BYSECOND, WEEKLY at year end/start */ public static function _recur2date(&$result, $recur, $wdate, $startdate, $enddate = FALSE) { foreach ($wdate as $k => $v) { if (ctype_digit($v)) { $wdate[$k] = (int) $v; } } $wdateStart = $wdate; $wdatets = iCalUtilityFunctions::_date2timestamp($wdate); $startdatets = iCalUtilityFunctions::_date2timestamp($startdate); if (!$enddate) { $enddate = $startdate; $enddate['year'] += 1; } // echo "recur __in_ comp start ".implode('-',$wdate)." period start ".implode('-',$startdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test### $endDatets = iCalUtilityFunctions::_date2timestamp($enddate); // fix break if (!isset($recur['COUNT']) && !isset($recur['UNTIL'])) { $recur['UNTIL'] = $enddate; } // create break if (isset($recur['UNTIL'])) { $tdatets = iCalUtilityFunctions::_date2timestamp($recur['UNTIL']); if ($endDatets > $tdatets) { $endDatets = $tdatets; // emergency break $enddate = iCalUtilityFunctions::_timestamp2date($endDatets, 6); } else { $recur['UNTIL'] = iCalUtilityFunctions::_timestamp2date($endDatets, 6); } } if ($wdatets > $endDatets) { // echo "recur out of date ".date('Y-m-d H:i:s',$wdatets)."<br />\n";//test return array(); // nothing to do.. . } if (!isset($recur['FREQ'])) { // "MUST be specified.. ." $recur['FREQ'] = 'DAILY'; } // ?? $wkst = isset($recur['WKST']) && 'SU' == $recur['WKST'] ? 24 * 60 * 60 : 0; // ?? $weekStart = (int) date('W', $wdatets + $wkst); if (!isset($recur['INTERVAL'])) { $recur['INTERVAL'] = 1; } $countcnt = !isset($recur['BYSETPOS']) ? 1 : 0; // DTSTART counts as the first occurrence /* find out how to step up dates and set index for interval count */ $step = array(); if ('YEARLY' == $recur['FREQ']) { $step['year'] = 1; } elseif ('MONTHLY' == $recur['FREQ']) { $step['month'] = 1; } elseif ('WEEKLY' == $recur['FREQ']) { $step['day'] = 7; } else { $step['day'] = 1; } if (isset($step['year']) && isset($recur['BYMONTH'])) { $step = array('month' => 1); } if (empty($step) && isset($recur['BYWEEKNO'])) { // ?? $step = array('day' => 7); } if (isset($recur['BYYEARDAY']) || isset($recur['BYMONTHDAY']) || isset($recur['BYDAY'])) { $step = array('day' => 1); } $intervalarr = array(); if (1 < $recur['INTERVAL']) { $intervalix = iCalUtilityFunctions::_recurIntervalIx($recur['FREQ'], $wdate, $wkst); $intervalarr = array($intervalix => 0); } if (isset($recur['BYSETPOS'])) { // save start date + weekno $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array(); // echo "bysetposXold_start=$bysetposYold $bysetposMold $bysetposDold<br />\n"; // test ### if (is_array($recur['BYSETPOS'])) { foreach ($recur['BYSETPOS'] as $bix => $bval) { $recur['BYSETPOS'][$bix] = (int) $bval; } } else { $recur['BYSETPOS'] = array((int) $recur['BYSETPOS']); } if ('YEARLY' == $recur['FREQ']) { $wdate['month'] = $wdate['day'] = 1; // start from beginning of year $wdatets = iCalUtilityFunctions::_date2timestamp($wdate); iCalUtilityFunctions::_stepdate($enddate, $endDatets, array('year' => 1)); // make sure to count whole last year } elseif ('MONTHLY' == $recur['FREQ']) { $wdate['day'] = 1; // start from beginning of month $wdatets = iCalUtilityFunctions::_date2timestamp($wdate); iCalUtilityFunctions::_stepdate($enddate, $endDatets, array('month' => 1)); // make sure to count whole last month } else { iCalUtilityFunctions::_stepdate($enddate, $endDatets, $step); } // make sure to count whole last period // echo "BYSETPOS endDat++ =".implode('-',$enddate).' step='.var_export($step,TRUE)."<br />\n";//test### $bysetposWold = (int) date('W', $wdatets + $wkst); $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; $bysetposDold = $wdate['day']; } else { iCalUtilityFunctions::_stepdate($wdate, $wdatets, $step); } $year_old = null; $daynames = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); /* MAIN LOOP */ // echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test while (TRUE) { if (isset($endDatets) && $wdatets > $endDatets) { break; } if (isset($recur['COUNT']) && $countcnt >= $recur['COUNT']) { break; } if ($year_old != $wdate['year']) { $year_old = $wdate['year']; $daycnts = array(); $yeardays = $weekno = 0; $yeardaycnt = array(); foreach ($daynames as $dn) { $yeardaycnt[$dn] = 0; } for ($m = 1; $m <= 12; $m++) { // count up and update up-counters $daycnts[$m] = array(); $weekdaycnt = array(); foreach ($daynames as $dn) { $weekdaycnt[$dn] = 0; } $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year'])); for ($d = 1; $d <= $mcnt; $d++) { $daycnts[$m][$d] = array(); if (isset($recur['BYYEARDAY'])) { $yeardays++; $daycnts[$m][$d]['yearcnt_up'] = $yeardays; } if (isset($recur['BYDAY'])) { $day = date('w', mktime(0, 0, 0, $m, $d, $wdate['year'])); $day = $daynames[$day]; $daycnts[$m][$d]['DAY'] = $day; $weekdaycnt[$day]++; $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day]; $yeardaycnt[$day]++; $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day]; } if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') { $daycnts[$m][$d]['weekno_up'] = (int) date('W', mktime(0, 0, $wkst, $m, $d, $wdate['year'])); } } } $daycnt = 0; $yeardaycnt = array(); if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') { $weekno = null; for ($d = 31; $d > 25; $d--) { // get last weekno for year if (!$weekno) { $weekno = $daycnts[12][$d]['weekno_up']; } elseif ($weekno < $daycnts[12][$d]['weekno_up']) { $weekno = $daycnts[12][$d]['weekno_up']; break; } } } for ($m = 12; $m > 0; $m--) { // count down and update down-counters $weekdaycnt = array(); foreach ($daynames as $dn) { $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0; } $monthcnt = 0; $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year'])); for ($d = $mcnt; $d > 0; $d--) { if (isset($recur['BYYEARDAY'])) { $daycnt -= 1; $daycnts[$m][$d]['yearcnt_down'] = $daycnt; } if (isset($recur['BYMONTHDAY'])) { $monthcnt -= 1; $daycnts[$m][$d]['monthcnt_down'] = $monthcnt; } if (isset($recur['BYDAY'])) { $day = $daycnts[$m][$d]['DAY']; $weekdaycnt[$day] -= 1; $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day]; $yeardaycnt[$day] -= 1; $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day]; } if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') { $daycnts[$m][$d]['weekno_down'] = $daycnts[$m][$d]['weekno_up'] - $weekno - 1; } } } } /* check interval */ if (1 < $recur['INTERVAL']) { /* create interval index */ $intervalix = iCalUtilityFunctions::_recurIntervalIx($recur['FREQ'], $wdate, $wkst); /* check interval */ $currentKey = array_keys($intervalarr); $currentKey = end($currentKey); // get last index if ($currentKey != $intervalix) { $intervalarr = array($intervalix => $intervalarr[$currentKey] + 1); } if ($recur['INTERVAL'] != $intervalarr[$intervalix] && 0 != $intervalarr[$intervalix]) { /* step up date */ // echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test iCalUtilityFunctions::_stepdate($wdate, $wdatets, $step); continue; } else { // continue within the selected interval $intervalarr[$intervalix] = 0; } // echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test } $updateOK = TRUE; if ($updateOK && isset($recur['BYMONTH'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYMONTH'], $wdate['month'], $wdate['month'] - 13); } if ($updateOK && isset($recur['BYWEEKNO'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYWEEKNO'], $daycnts[$wdate['month']][$wdate['day']]['weekno_up'], $daycnts[$wdate['month']][$wdate['day']]['weekno_down']); } if ($updateOK && isset($recur['BYYEARDAY'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYYEARDAY'], $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up'], $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down']); } if ($updateOK && isset($recur['BYMONTHDAY'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYMONTHDAY'], $wdate['day'], $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down']); } // echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test### if ($updateOK && isset($recur['BYDAY'])) { $updateOK = FALSE; $m = $wdate['month']; $d = $wdate['day']; if (isset($recur['BYDAY']['DAY'])) { // single day, opt with year/month day order no $daynoexists = $daynosw = $daynamesw = FALSE; if ($recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY']) { $daynamesw = TRUE; } if (isset($recur['BYDAY'][0])) { $daynoexists = TRUE; if (isset($recur['FREQ']) && $recur['FREQ'] == 'MONTHLY' || isset($recur['BYMONTH'])) { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($recur['BYDAY'][0], $daycnts[$m][$d]['monthdayno_up'], $daycnts[$m][$d]['monthdayno_down']); } elseif (isset($recur['FREQ']) && $recur['FREQ'] == 'YEARLY') { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($recur['BYDAY'][0], $daycnts[$m][$d]['yeardayno_up'], $daycnts[$m][$d]['yeardayno_down']); } } if ($daynoexists && $daynosw && $daynamesw || !$daynoexists && !$daynosw && $daynamesw) { $updateOK = TRUE; // echo "m=$m d=$d day=".$daycnts[$m][$d]['DAY']." yeardayno_up=".$daycnts[$m][$d]['yeardayno_up']." daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw updateOK:$updateOK<br />\n"; // test ### } //echo "m=$m d=$d day=".$daycnts[$m][$d]['DAY']." yeardayno_up=".$daycnts[$m][$d]['yeardayno_up']." daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw updateOK:$updateOK<br />\n"; // test ### } else { foreach ($recur['BYDAY'] as $bydayvalue) { $daynoexists = $daynosw = $daynamesw = FALSE; if (isset($bydayvalue['DAY']) && $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY']) { $daynamesw = TRUE; } if (isset($bydayvalue[0])) { $daynoexists = TRUE; if (isset($recur['FREQ']) && $recur['FREQ'] == 'MONTHLY' || isset($recur['BYMONTH'])) { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($bydayvalue['0'], $daycnts[$m][$d]['monthdayno_up'], $daycnts[$m][$d]['monthdayno_down']); } elseif (isset($recur['FREQ']) && $recur['FREQ'] == 'YEARLY') { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($bydayvalue['0'], $daycnts[$m][$d]['yeardayno_up'], $daycnts[$m][$d]['yeardayno_down']); } } // echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ### if ($daynoexists && $daynosw && $daynamesw || !$daynoexists && !$daynosw && $daynamesw) { $updateOK = TRUE; break; } } } } // echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ### /* check BYSETPOS */ if ($updateOK) { if (isset($recur['BYSETPOS']) && in_array($recur['FREQ'], array('YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY'))) { if (isset($recur['WEEKLY'])) { if ($bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up']) { $bysetposw1[] = $wdatets; } else { $bysetposw2[] = $wdatets; } } else { if (isset($recur['FREQ']) && 'YEARLY' == $recur['FREQ'] && $bysetposYold == $wdate['year'] || isset($recur['FREQ']) && 'MONTHLY' == $recur['FREQ'] && ($bysetposYold == $wdate['year'] && $bysetposMold == $wdate['month']) || isset($recur['FREQ']) && 'DAILY' == $recur['FREQ'] && ($bysetposYold == $wdate['year'] && $bysetposMold == $wdate['month'] && $bysetposDold == $wdate['day'])) { // echo "bysetposymd1[]=".date('Y-m-d H:i:s',$wdatets)."<br />\n";//test $bysetposymd1[] = $wdatets; } else { // echo "bysetposymd2[]=".date('Y-m-d H:i:s',$wdatets)."<br />\n";//test $bysetposymd2[] = $wdatets; } } } else { /* update result array if BYSETPOS is set */ $countcnt++; if ($startdatets <= $wdatets) { // only output within period $result[$wdatets] = TRUE; // echo "recur ".date('Y-m-d H:i:s',$wdatets)."<br />\n";//test } // echo "recur undate ".date('Y-m-d H:i:s',$wdatets)." okdatstart ".date('Y-m-d H:i:s',$startdatets)."<br />\n";//test $updateOK = FALSE; } } /* step up date */ iCalUtilityFunctions::_stepdate($wdate, $wdatets, $step); /* check if BYSETPOS is set for updating result array */ if ($updateOK && isset($recur['BYSETPOS'])) { $bysetpos = FALSE; if (isset($recur['FREQ']) && 'YEARLY' == $recur['FREQ'] && $bysetposYold != $wdate['year']) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; } elseif (isset($recur['FREQ']) && ('MONTHLY' == $recur['FREQ'] && ($bysetposYold != $wdate['year'] || $bysetposMold != $wdate['month']))) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; } elseif (isset($recur['FREQ']) && 'WEEKLY' == $recur['FREQ']) { $weekno = (int) date('W', mktime(0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year'])); if ($bysetposWold != $weekno) { $bysetposWold = $weekno; $bysetpos = TRUE; } } elseif (isset($recur['FREQ']) && 'DAILY' == $recur['FREQ'] && ($bysetposYold != $wdate['year'] || $bysetposMold != $wdate['month'] || $bysetposDold != $wdate['day'])) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; $bysetposDold = $wdate['day']; } if ($bysetpos) { if (isset($recur['BYWEEKNO'])) { $bysetposarr1 =& $bysetposw1; $bysetposarr2 =& $bysetposw2; } else { $bysetposarr1 =& $bysetposymd1; $bysetposarr2 =& $bysetposymd2; } // echo 'test före out startYMD (weekno)='.$wdateStart['year'].':'.$wdateStart['month'].':'.$wdateStart['day']." ($weekStart) "; // test ### foreach ($recur['BYSETPOS'] as $ix) { if (0 > $ix) { // both positive and negative BYSETPOS allowed $ix = count($bysetposarr1) + $ix + 1; } $ix--; if (isset($bysetposarr1[$ix])) { if ($startdatets <= $bysetposarr1[$ix]) { // only output within period // $testdate = iCalUtilityFunctions::_timestamp2date( $bysetposarr1[$ix], 6 ); // test ### // $testweekno = (int) date( 'W', mktime( 0, 0, $wkst, $testdate['month'], $testdate['day'], $testdate['year'] )); // test ### // echo " testYMD (weekno)=".$testdate['year'].':'.$testdate['month'].':'.$testdate['day']." ($testweekno)"; // test ### $result[$bysetposarr1[$ix]] = TRUE; // echo " recur ".date('Y-m-d H:i:s',$bysetposarr1[$ix]); // test ### } $countcnt++; } if (isset($recur['COUNT']) && $countcnt >= $recur['COUNT']) { break; } } // echo "<br />\n"; // test ### $bysetposarr1 = $bysetposarr2; $bysetposarr2 = array(); } } } }
/** * updates an array with dates based on a recur pattern * * if missing, UNTIL is set 1 year from startdate (emergency break) * * @author Kjell-Inge Gustafsson, kigkonsult <*****@*****.**> * @since 2.21.11 - 2015-03-10 * @param array $result array to update, array([Y-m-d] => bool) * @param array $recur pattern for recurrency (only value part, params ignored) * @param mixed $wdate component start date, string / array / (datetime) obj * @param mixed $fcnStart start date, string / array / (datetime) obj * @param mixed $fcnEnd end date, string / array / (datetime) obj * @uses iCalUtilityFunctions::_strDate2arr() * @uses iCalUtilityFunctions::$fmt * @uses iCalUtilityFunctions::_stepdate() * @uses iCalUtilityFunctions::_recurIntervalIx() * @uses iCalUtilityFunctions::_recurBYcntcheck() * @return void * @todo BYHOUR, BYMINUTE, BYSECOND, WEEKLY at year end/start OR not at all */ public static function _recur2date(&$result, $recur, $wdate, $fcnStart, $fcnEnd = FALSE) { if (is_string($wdate)) { iCalUtilityFunctions::_strDate2arr($wdate); } elseif (is_a($wdate, 'DateTime')) { $wdate = $wdate->format(iCalUtilityFunctions::$fmt['YmdHis2']); iCalUtilityFunctions::_strDate2arr($wdate); } foreach ($wdate as $k => $v) { if (ctype_digit($v)) { $wdate[$k] = (int) $v; } } $wdateYMD = sprintf(iCalUtilityFunctions::$fmt['Ymd'], $wdate['year'], $wdate['month'], $wdate['day']); $wdateHis = sprintf(iCalUtilityFunctions::$fmt['His'], $wdate['hour'], $wdate['min'], $wdate['sec']); $untilHis = $wdateHis; if (is_string($fcnStart)) { iCalUtilityFunctions::_strDate2arr($fcnStart); } elseif (is_a($fcnStart, 'DateTime')) { $fcnStart = $fcnStart->format(iCalUtilityFunctions::$fmt['YmdHis2']); iCalUtilityFunctions::_strDate2arr($fcnStart); } foreach ($fcnStart as $k => $v) { if (ctype_digit($v)) { $fcnStart[$k] = (int) $v; } } $fcnStartYMD = sprintf(iCalUtilityFunctions::$fmt['Ymd'], $fcnStart['year'], $fcnStart['month'], $fcnStart['day']); if (is_string($fcnEnd)) { iCalUtilityFunctions::_strDate2arr($fcnEnd); } elseif (is_a($fcnEnd, 'DateTime')) { $fcnEnd = $fcnEnd->format(iCalUtilityFunctions::$fmt['YmdHis2']); iCalUtilityFunctions::_strDate2arr($fcnEnd); } if (!$fcnEnd) { $fcnEnd = $fcnStart; $fcnEnd['year'] += 1; } foreach ($fcnEnd as $k => $v) { if (ctype_digit($v)) { $fcnEnd[$k] = (int) $v; } } $fcnEndYMD = sprintf(iCalUtilityFunctions::$fmt['Ymd'], $fcnEnd['year'], $fcnEnd['month'], $fcnEnd['day']); // echo "<b>recur _in_ comp</b> start ".implode('-',$wdate)." period start ".implode('-',$fcnStart)." period end ".implode('-',$fcnEnd)."<br>\n"; // echo 'recur='.str_replace( array( PHP_EOL, ' ' ), '', var_export( $recur, TRUE ))."<br> \n"; // test ### if (!isset($recur['COUNT']) && !isset($recur['UNTIL'])) { $recur['UNTIL'] = $fcnEnd; } // create break if (isset($recur['UNTIL'])) { foreach ($recur['UNTIL'] as $k => $v) { if (ctype_digit($v)) { $recur['UNTIL'][$k] = (int) $v; } } unset($recur['UNTIL']['tz']); if ($fcnEnd > $recur['UNTIL']) { $fcnEnd = $recur['UNTIL']; // emergency break $fcnEndYMD = sprintf(iCalUtilityFunctions::$fmt['Ymd'], $fcnEnd['year'], $fcnEnd['month'], $fcnEnd['day']); } if (isset($recur['UNTIL']['hour'])) { $untilHis = sprintf(iCalUtilityFunctions::$fmt['His'], $recur['UNTIL']['hour'], $recur['UNTIL']['min'], $recur['UNTIL']['sec']); } else { $untilHis = sprintf(iCalUtilityFunctions::$fmt['His'], 23, 59, 59); } // echo 'recurUNTIL='.str_replace( array( PHP_EOL, ' ' ), '', var_export( $recur['UNTIL'], TRUE )).", untilHis={$untilHis}<br> \n"; // test ### } // echo 'fcnEnd:'.$fcnEndYMD.$untilHis."<br>\n";//test if ($wdateYMD > $fcnEndYMD) { // echo 'recur out of date, '.implode('-',$wdate).', end='.implode('-',$fcnEnd)."<br>\n";//test return array(); // nothing to do.. . } if (!isset($recur['FREQ'])) { // "MUST be specified.. ." $recur['FREQ'] = 'DAILY'; } // ?? $wkst = isset($recur['WKST']) && 'SU' == $recur['WKST'] ? 24 * 60 * 60 : 0; // ?? if (!isset($recur['INTERVAL'])) { $recur['INTERVAL'] = 1; } $countcnt = !isset($recur['BYSETPOS']) ? 1 : 0; // DTSTART counts as the first occurrence /* find out how to step up dates and set index for interval count */ $step = array(); if ('YEARLY' == $recur['FREQ']) { $step['year'] = 1; } elseif ('MONTHLY' == $recur['FREQ']) { $step['month'] = 1; } elseif ('WEEKLY' == $recur['FREQ']) { $step['day'] = 7; } else { $step['day'] = 1; } if (isset($step['year']) && isset($recur['BYMONTH'])) { $step = array('month' => 1); } if (empty($step) && isset($recur['BYWEEKNO'])) { // ?? $step = array('day' => 7); } if (isset($recur['BYYEARDAY']) || isset($recur['BYMONTHDAY']) || isset($recur['BYDAY'])) { $step = array('day' => 1); } $intervalarr = array(); if (1 < $recur['INTERVAL']) { $intervalix = iCalUtilityFunctions::_recurIntervalIx($recur['FREQ'], $wdate, $wkst); $intervalarr = array($intervalix => 0); } if (isset($recur['BYSETPOS'])) { // save start date + weekno $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array(); // echo "bysetposXold_start=$bysetposYold $bysetposMold $bysetposDold<br>\n"; // test ### if (is_array($recur['BYSETPOS'])) { foreach ($recur['BYSETPOS'] as $bix => $bval) { $recur['BYSETPOS'][$bix] = (int) $bval; } } else { $recur['BYSETPOS'] = array((int) $recur['BYSETPOS']); } if ('YEARLY' == $recur['FREQ']) { $wdate['month'] = $wdate['day'] = 1; // start from beginning of year $wdateYMD = sprintf(iCalUtilityFunctions::$fmt['Ymd'], $wdate['year'], $wdate['month'], $wdate['day']); iCalUtilityFunctions::_stepdate($fcnEnd, $fcnEndYMD, array('year' => 1)); // make sure to count whole last year } elseif ('MONTHLY' == $recur['FREQ']) { $wdate['day'] = 1; // start from beginning of month $wdateYMD = sprintf(iCalUtilityFunctions::$fmt['Ymd'], $wdate['year'], $wdate['month'], $wdate['day']); iCalUtilityFunctions::_stepdate($fcnEnd, $fcnEndYMD, array('month' => 1)); // make sure to count whole last month } else { iCalUtilityFunctions::_stepdate($fcnEnd, $fcnEndYMD, $step); } // make sure to count whole last period // echo "BYSETPOS endDat =".implode('-',$fcnEnd).' step='.var_export($step,TRUE)."<br>\n";//test### $bysetposWold = (int) date('W', mktime(0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year'])); $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; $bysetposDold = $wdate['day']; } else { iCalUtilityFunctions::_stepdate($wdate, $wdateYMD, $step); } $year_old = null; static $daynames = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); /* MAIN LOOP */ // echo "recur start:$wdateYMD, end:$fcnEndYMD<br>\n";//test while (TRUE) { // echo "recur while:$wdateYMD, end:$fcnEndYMD<br>\n";//test if ($wdateYMD . $wdateHis > $fcnEndYMD . $untilHis) { break; } if (isset($recur['COUNT']) && $countcnt >= $recur['COUNT']) { break; } if ($year_old != $wdate['year']) { $year_old = $wdate['year']; $daycnts = array(); $yeardays = $weekno = 0; $yeardaycnt = array(); foreach ($daynames as $dn) { $yeardaycnt[$dn] = 0; } for ($m = 1; $m <= 12; $m++) { // count up and update up-counters $daycnts[$m] = array(); $weekdaycnt = array(); foreach ($daynames as $dn) { $weekdaycnt[$dn] = 0; } $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year'])); for ($d = 1; $d <= $mcnt; $d++) { $daycnts[$m][$d] = array(); if (isset($recur['BYYEARDAY'])) { $yeardays++; $daycnts[$m][$d]['yearcnt_up'] = $yeardays; } if (isset($recur['BYDAY'])) { $day = date('w', mktime(0, 0, 0, $m, $d, $wdate['year'])); $day = $daynames[$day]; $daycnts[$m][$d]['DAY'] = $day; $weekdaycnt[$day]++; $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day]; $yeardaycnt[$day]++; $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day]; } if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') { $daycnts[$m][$d]['weekno_up'] = (int) date('W', mktime(0, 0, $wkst, $m, $d, $wdate['year'])); } } // end for( $d = 1; $d <= $mcnt; $d++ ) } // end for( $m = 1; $m <= 12; $m++ ) $daycnt = 0; $yeardaycnt = array(); if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') { $weekno = null; for ($d = 31; $d > 25; $d--) { // get last weekno for year if (!$weekno) { $weekno = $daycnts[12][$d]['weekno_up']; } elseif ($weekno < $daycnts[12][$d]['weekno_up']) { $weekno = $daycnts[12][$d]['weekno_up']; break; } } } for ($m = 12; $m > 0; $m--) { // count down and update down-counters $weekdaycnt = array(); foreach ($daynames as $dn) { $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0; } $monthcnt = 0; $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year'])); for ($d = $mcnt; $d > 0; $d--) { if (isset($recur['BYYEARDAY'])) { $daycnt -= 1; $daycnts[$m][$d]['yearcnt_down'] = $daycnt; } if (isset($recur['BYMONTHDAY'])) { $monthcnt -= 1; $daycnts[$m][$d]['monthcnt_down'] = $monthcnt; } if (isset($recur['BYDAY'])) { $day = $daycnts[$m][$d]['DAY']; $weekdaycnt[$day] -= 1; $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day]; $yeardaycnt[$day] -= 1; $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day]; } if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') { $daycnts[$m][$d]['weekno_down'] = $daycnts[$m][$d]['weekno_up'] - $weekno - 1; } } } // end for( $m = 12; $m > 0; $m-- ) } // end if( $year_old != $wdate['year'] ) /* check interval */ if (1 < $recur['INTERVAL']) { /* create interval index */ $intervalix = iCalUtilityFunctions::_recurIntervalIx($recur['FREQ'], $wdate, $wkst); /* check interval */ $currentKey = array_keys($intervalarr); $currentKey = end($currentKey); // get last index if ($currentKey != $intervalix) { $intervalarr = array($intervalix => $intervalarr[$currentKey] + 1); } if ($recur['INTERVAL'] != $intervalarr[$intervalix] && 0 != $intervalarr[$intervalix]) { /* step up date */ // echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br>\n";//test iCalUtilityFunctions::_stepdate($wdate, $wdateYMD, $step); continue; } else { // continue within the selected interval $intervalarr[$intervalix] = 0; } // echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br>\n";//test } // endif( 1 < $recur['INTERVAL'] ) $updateOK = TRUE; if ($updateOK && isset($recur['BYMONTH'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYMONTH'], $wdate['month'], $wdate['month'] - 13); } if ($updateOK && isset($recur['BYWEEKNO'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYWEEKNO'], $daycnts[$wdate['month']][$wdate['day']]['weekno_up'], $daycnts[$wdate['month']][$wdate['day']]['weekno_down']); } if ($updateOK && isset($recur['BYYEARDAY'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYYEARDAY'], $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up'], $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down']); } if ($updateOK && isset($recur['BYMONTHDAY'])) { $updateOK = iCalUtilityFunctions::_recurBYcntcheck($recur['BYMONTHDAY'], $wdate['day'], $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down']); } // echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br>\n";//test### if ($updateOK && isset($recur['BYDAY'])) { $updateOK = FALSE; $m = $wdate['month']; $d = $wdate['day']; if (isset($recur['BYDAY']['DAY'])) { // single day, opt with year/month day order no $daynoexists = $daynosw = $daynamesw = FALSE; if ($recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY']) { $daynamesw = TRUE; } if (isset($recur['BYDAY'][0])) { $daynoexists = TRUE; if (isset($recur['FREQ']) && $recur['FREQ'] == 'MONTHLY' || isset($recur['BYMONTH'])) { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($recur['BYDAY'][0], $daycnts[$m][$d]['monthdayno_up'], $daycnts[$m][$d]['monthdayno_down']); } elseif (isset($recur['FREQ']) && $recur['FREQ'] == 'YEARLY') { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($recur['BYDAY'][0], $daycnts[$m][$d]['yeardayno_up'], $daycnts[$m][$d]['yeardayno_down']); } } if ($daynoexists && $daynosw && $daynamesw || !$daynoexists && !$daynosw && $daynamesw) { $updateOK = TRUE; // echo "m=$m d=$d day=".$daycnts[$m][$d]['DAY']." yeardayno_up=".$daycnts[$m][$d]['yeardayno_up']." daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw updateOK:$updateOK<br>\n"; // test ### } // echo "m=$m d=$d day=".$daycnts[$m][$d]['DAY']." yeardayno_up=".$daycnts[$m][$d]['yeardayno_up']." daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw updateOK:$updateOK<br>\n"; // test ### } else { foreach ($recur['BYDAY'] as $bydayvalue) { $daynoexists = $daynosw = $daynamesw = FALSE; if (isset($bydayvalue['DAY']) && $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY']) { $daynamesw = TRUE; } if (isset($bydayvalue[0])) { $daynoexists = TRUE; if (isset($recur['FREQ']) && $recur['FREQ'] == 'MONTHLY' || isset($recur['BYMONTH'])) { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($bydayvalue['0'], $daycnts[$m][$d]['monthdayno_up'], $daycnts[$m][$d]['monthdayno_down']); } elseif (isset($recur['FREQ']) && $recur['FREQ'] == 'YEARLY') { $daynosw = iCalUtilityFunctions::_recurBYcntcheck($bydayvalue['0'], $daycnts[$m][$d]['yeardayno_up'], $daycnts[$m][$d]['yeardayno_down']); } } // echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br>\n"; // test ### if ($daynoexists && $daynosw && $daynamesw || !$daynoexists && !$daynosw && $daynamesw) { $updateOK = TRUE; break; } } } } // echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br>\n"; // test ### /* check BYSETPOS */ if ($updateOK) { if (isset($recur['BYSETPOS']) && in_array($recur['FREQ'], array('YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY'))) { if (isset($recur['WEEKLY'])) { if ($bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up']) { $bysetposw1[] = $wdateYMD; } else { $bysetposw2[] = $wdateYMD; } } else { if (isset($recur['FREQ']) && 'YEARLY' == $recur['FREQ'] && $bysetposYold == $wdate['year'] || isset($recur['FREQ']) && 'MONTHLY' == $recur['FREQ'] && ($bysetposYold == $wdate['year'] && $bysetposMold == $wdate['month']) || isset($recur['FREQ']) && 'DAILY' == $recur['FREQ'] && ($bysetposYold == $wdate['year'] && $bysetposMold == $wdate['month'] && $bysetposDold == $wdate['day'])) { // echo "bysetposymd1[]=".date('Y-m-d H:i:s',$wdatets)."<br>\n";//test $bysetposymd1[] = $wdateYMD; } else { // echo "bysetposymd2[]=".date('Y-m-d H:i:s',$wdatets)."<br>\n";//test $bysetposymd2[] = $wdateYMD; } } } else { if (checkdate($wdate['month'], $wdate['day'], $wdate['year'])) { /* update result array if BYSETPOS is not set */ $countcnt++; if ($fcnStartYMD <= $wdateYMD) { // only output within period $result[$wdateYMD] = TRUE; // echo "recur $wdateYMD<br>\n";//test } } // else echo "recur, no date $wdateYMD<br>\n";//test $updateOK = FALSE; } } /* step up date */ iCalUtilityFunctions::_stepdate($wdate, $wdateYMD, $step); /* check if BYSETPOS is set for updating result array */ if ($updateOK && isset($recur['BYSETPOS'])) { $bysetpos = FALSE; if (isset($recur['FREQ']) && 'YEARLY' == $recur['FREQ'] && $bysetposYold != $wdate['year']) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; } elseif (isset($recur['FREQ']) && ('MONTHLY' == $recur['FREQ'] && ($bysetposYold != $wdate['year'] || $bysetposMold != $wdate['month']))) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; } elseif (isset($recur['FREQ']) && 'WEEKLY' == $recur['FREQ']) { $weekno = (int) date('W', mktime(0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year'])); if ($bysetposWold != $weekno) { $bysetposWold = $weekno; $bysetpos = TRUE; } } elseif (isset($recur['FREQ']) && 'DAILY' == $recur['FREQ'] && ($bysetposYold != $wdate['year'] || $bysetposMold != $wdate['month'] || $bysetposDold != $wdate['day'])) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; $bysetposDold = $wdate['day']; } if ($bysetpos) { if (isset($recur['BYWEEKNO'])) { $bysetposarr1 =& $bysetposw1; $bysetposarr2 =& $bysetposw2; } else { $bysetposarr1 =& $bysetposymd1; $bysetposarr2 =& $bysetposymd2; } foreach ($recur['BYSETPOS'] as $ix) { if (0 > $ix) { // both positive and negative BYSETPOS allowed $ix = count($bysetposarr1) + $ix + 1; } $ix--; if (isset($bysetposarr1[$ix])) { if ($fcnStartYMD <= $bysetposarr1[$ix]) { // only output within period // $testweekno = (int) date( 'W', mktime( 0, 0, $wkst, (int) substr( $bysetposarr1[$ix], 4, 2 ), (int) substr( $bysetposarr1[$ix], 6, 2 ), (int) substr( $bysetposarr1[$ix], 0, 3 ))); // test ### // echo " testYMD (weekno)=$bysetposarr1[$ix] ($testweekno)"; // test ### $result[$bysetposarr1[$ix]] = TRUE; } $countcnt++; } if (isset($recur['COUNT']) && $countcnt >= $recur['COUNT']) { break; } } // echo "<br>\n"; // test ### $bysetposarr1 = $bysetposarr2; $bysetposarr2 = array(); } // end if( $bysetpos ) } // end if( $updateOK && isset( $recur['BYSETPOS'] )) } // end while( TRUE ) // echo 'output='.str_replace( array( PHP_EOL, ' ' ), '', var_export( $result, TRUE ))."<br> \n"; // test ### }