| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* Zap Calendar Recurring Date Helper Class |
| 5 |
* |
| 6 |
* @copyright Copyright (C) 2006 - 2016 by Dan Cogliano |
| 7 |
* @license GNU General Public License version 2 or later; see LICENSE.txt |
| 8 |
*/ |
| 9 |
|
| 10 |
// no direct access |
| 11 |
defined('_ZAPCAL') or die( 'Restricted access' ); |
| 12 |
|
| 13 |
/** |
| 14 |
* Class to expand recurring rule to a list of dates |
| 15 |
*/ |
| 16 |
class ZCRecurringDate { |
| 17 |
var $rules = ""; |
| 18 |
var $startdate = null; |
| 19 |
var $nextdate = null; |
| 20 |
var $freq = null; |
| 21 |
var $tzid = null; |
| 22 |
var $year=0; |
| 23 |
var $month=0; |
| 24 |
var $week=0; |
| 25 |
var $day=0; |
| 26 |
var $hour=0; |
| 27 |
var $minute=0; |
| 28 |
var $second=0; |
| 29 |
var $until=null; |
| 30 |
var $count=0; |
| 31 |
var $repeatmode=null; |
| 32 |
var $incr=0; |
| 33 |
var $bysecond=array(); |
| 34 |
var $byminute=array(); |
| 35 |
var $byhour=array(); |
| 36 |
var $byday=array(); |
| 37 |
var $bymonthday=array(); |
| 38 |
var $daybegin=array(); |
| 39 |
var $dayend=array(); |
| 40 |
var $bymonth=array(); |
| 41 |
var $byyear=array(); |
| 42 |
var $bysetpos=array(); |
| 43 |
var $ibymonthday = 0; |
| 44 |
var $ibymonth = 0; |
| 45 |
var $interval = 1; |
| 46 |
var $debug = 0; |
| 47 |
var $error; |
| 48 |
var $exdates=array(); |
| 49 |
|
| 50 |
// $startdate is in local timezone |
| 51 |
// $exdates array is in UTC timezone |
| 52 |
function ZCRecurringDate($rules, $startdate, $exdates = array(),$tzid = "UTC"){ |
| 53 |
if(strlen($rules) > 0){ |
| 54 |
//move exdates to event timezone for comparing with event date |
| 55 |
for($i = 0; $i < count($exdates); $i++) |
| 56 |
{ |
| 57 |
$exdates[$i] = ZDateHelper::toUnixDateTime(ZDateHelper::toLocalDateTime(ZDateHelper::toSQLDateTime($exdates[$i]),$tzid)); |
| 58 |
} |
| 59 |
|
| 60 |
$rules=str_replace("\'","",$rules); |
| 61 |
$this->rules = $rules; |
| 62 |
if($startdate == null){ |
| 63 |
// if not specified, use start date of beginning of last year |
| 64 |
$tdate=getdate(); |
| 65 |
$startdate=mktime(0,0,0,1,1,$tdate["year"] - 1); |
| 66 |
} |
| 67 |
$this->startdate = $startdate; |
| 68 |
$this->nextdate = $startdate; |
| 69 |
$this->tzid = $tzid; |
| 70 |
$this->exdates = $exdates; |
| 71 |
|
| 72 |
$rules=explode(";", $rules); |
| 73 |
$ruletype = ""; |
| 74 |
foreach($rules as $rule){ |
| 75 |
$item=explode("=",$rule); |
| 76 |
//echo $item[0] . "=" . $item[1] . "<br/>\n"; |
| 77 |
switch($item[0]){ |
| 78 |
case "FREQ": |
| 79 |
switch($item[1]){ |
| 80 |
case "YEARLY": |
| 81 |
$this->year = 1; |
| 82 |
$this->freq="y"; |
| 83 |
break; |
| 84 |
case "MONTHLY": |
| 85 |
$this->month = 1; |
| 86 |
$this->freq="m"; |
| 87 |
break; |
| 88 |
case "WEEKLY": |
| 89 |
$this->week = 1; |
| 90 |
$this->freq="w"; |
| 91 |
break; |
| 92 |
case "DAILY": |
| 93 |
$this->day = 1; |
| 94 |
$this->freq="d"; |
| 95 |
break; |
| 96 |
case "HOURLY": |
| 97 |
$this->hour = 1; |
| 98 |
$this->freq="h"; |
| 99 |
break; |
| 100 |
case "MINUTELY": |
| 101 |
$this->minute = 1; |
| 102 |
$this->freq="i"; |
| 103 |
break; |
| 104 |
case "SECONDLY": |
| 105 |
$this->second = 1; |
| 106 |
$this->freq="s"; |
| 107 |
break; |
| 108 |
} |
| 109 |
break; |
| 110 |
case "INTERVAL": |
| 111 |
$this->interval = $item[1]; |
| 112 |
break; |
| 113 |
case "BYSECOND": |
| 114 |
$this->bysecond = explode(",",$item[1]); |
| 115 |
$ruletype = $item[0]; |
| 116 |
break; |
| 117 |
case "BYMINUTE": |
| 118 |
$this->byminute = explode(",",$item[1]); |
| 119 |
$ruletype = $item[0]; |
| 120 |
break; |
| 121 |
case "BYHOUR": |
| 122 |
$this->byhour = explode(",",$item[1]); |
| 123 |
$ruletype = $item[0]; |
| 124 |
break; |
| 125 |
case "BYDAY": |
| 126 |
$this->byday = explode(",",$item[1]); |
| 127 |
$ruletype = $item[0]; |
| 128 |
break; |
| 129 |
case "BYMONTHDAY": |
| 130 |
$this->bymonthday = explode(",",$item[1]); |
| 131 |
$ruletype = $item[0]; |
| 132 |
break; |
| 133 |
case "BYMONTH": |
| 134 |
$this->bymonth = explode(",",$item[1]); |
| 135 |
$ruletype = $item[0]; |
| 136 |
break; |
| 137 |
case "BYYEAR": |
| 138 |
$this->byyear = explode(",",$item[1]); |
| 139 |
$ruletype = $item[0]; |
| 140 |
break; |
| 141 |
case "COUNT": |
| 142 |
$this->count = intval($item[1]); |
| 143 |
$this->repeatmode = "c"; |
| 144 |
break; |
| 145 |
case "BYSETPOS": |
| 146 |
$this->bysetpos = explode(",",$item[1]); |
| 147 |
break; |
| 148 |
case "UNTIL": |
| 149 |
$this->until = ZDateHelper::fromiCaltoUnixDateTime($item[1]); |
| 150 |
$this->repeatmode = "u"; |
| 151 |
break; |
| 152 |
} |
| 153 |
} |
| 154 |
if(count($this->bysetpos) > 0){ |
| 155 |
switch($ruletype){ |
| 156 |
case "BYYEAR": |
| 157 |
$this->byyear = $this->bySetPos($this->byyear,$this->bysetpos); |
| 158 |
break; |
| 159 |
case "BYMONTH": |
| 160 |
$this->bymonth = $this->bySetPos($this->bymonth,$this->bysetpos); |
| 161 |
break; |
| 162 |
case "BYMONTHDAY": |
| 163 |
$this->bymonthday = $this->bySetPos($this->bymonthday,$this->bysetpos); |
| 164 |
break; |
| 165 |
case "BYDAY": |
| 166 |
$this->byday = $this->bySetPos($this->byday,$this->bysetpos); |
| 167 |
break; |
| 168 |
case "BYHOUR": |
| 169 |
$this->byhour = $this->bySetPos($this->byhour,$this->bysetpos); |
| 170 |
break; |
| 171 |
case "BYMINUTE": |
| 172 |
$this->byminute = $this->bySetPos($this->byminute,$this->bysetpos); |
| 173 |
break; |
| 174 |
case "BYSECOND": |
| 175 |
$this->bysecond = $this->bySetPos($this->bysecond,$this->bysetpos); |
| 176 |
break; |
| 177 |
} |
| 178 |
} |
| 179 |
if(is_array($this->byday)){ |
| 180 |
$dow = array("SU","MO","TU","WE","TH","FR","SA"); |
| 181 |
for($w=0; $w<=5; $w++){ |
| 182 |
for($d=0; $d < 7; $d++){ |
| 183 |
$this->daybegin[$d][$w] = 0; |
| 184 |
$this->dayend[$d][$w] = 0; |
| 185 |
if(in_array($dow[$d],$this->byday)|| |
| 186 |
in_array(($w+1) . $dow[$d], $this->byday)|| |
| 187 |
in_array(($w+1) . $dow[$d], $this->byday)) |
| 188 |
$this->daybegin[$d][$w] = 1; |
| 189 |
if(in_array("-" . ($w+1) . $dow[$d], $this->byday)){ |
| 190 |
$this->dayend[$d][$w] = 1; |
| 191 |
} |
| 192 |
// echo $this->daybegin[$d][$w] . " "; |
| 193 |
} |
| 194 |
// echo "<br />\n"; |
| 195 |
} |
| 196 |
} |
| 197 |
|
| 198 |
} |
| 199 |
} |
| 200 |
|
| 201 |
function bySetPos($bytype, $bysetpos){ |
| 202 |
$result = array(); |
| 203 |
for($i=0; $i < count($bysetpos); $i++){ |
| 204 |
for($j=0; $j < count($bytype); $j++){ |
| 205 |
$result[] = $bysetpos[$i] . $bytype[$j]; |
| 206 |
} |
| 207 |
} |
| 208 |
return $result; |
| 209 |
} |
| 210 |
|
| 211 |
function error($msg){ |
| 212 |
$this->error = $msg; |
| 213 |
echo "ZCRecurringDate() error:" . $this->error . "<br />\n"; |
| 214 |
} |
| 215 |
|
| 216 |
function debug($level, $msg){ |
| 217 |
if($this->debug >= $level) |
| 218 |
echo $msg . "<br/>\n"; |
| 219 |
} |
| 220 |
|
| 221 |
function getError(){ |
| 222 |
return $this->error; |
| 223 |
} |
| 224 |
|
| 225 |
function byYear($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 226 |
self::debug(1,"byYear(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 227 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 228 |
$count = 0; |
| 229 |
if(count($this->byyear) > 0){ |
| 230 |
foreach($this->byyear as $year){ |
| 231 |
$t = getdate($startdate); |
| 232 |
$wdate = mktime($t[hours],$t[minutes],$t[seconds],$t[month],$t[mday],$year); |
| 233 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 234 |
$count = $this->byMonth($wdate, $enddate, $rdates, $tzid); |
| 235 |
if($count == 0) { |
| 236 |
$rdates[] = $wdate; |
| 237 |
$count++; |
| 238 |
} |
| 239 |
} |
| 240 |
} |
| 241 |
} |
| 242 |
else if(!$this->maxDates($rdates)) |
| 243 |
$count = $this->byMonth($startdate, $enddate, $rdates, $tzid); |
| 244 |
self::debug(1,"byYear() returned " . $count ); |
| 245 |
return $count; |
| 246 |
} |
| 247 |
|
| 248 |
function byMonth($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 249 |
self::debug(1,"byMonth(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 250 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 251 |
$count = 0; |
| 252 |
if(count($this->bymonth) > 0){ |
| 253 |
foreach($this->bymonth as $month){ |
| 254 |
$t = getdate($startdate); |
| 255 |
$wdate = mktime($t["hours"],$t["minutes"],$t["seconds"],$month,$t["mday"],$t["year"]); |
| 256 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 257 |
$count = $this->byMonthDay($wdate, $enddate, $rdates, $tzid); |
| 258 |
if($count == 0) { |
| 259 |
$rdates[] = $wdate; |
| 260 |
$count++; |
| 261 |
} |
| 262 |
} |
| 263 |
} |
| 264 |
} |
| 265 |
else if(!$this->maxDates($rdates)) |
| 266 |
$count = $this->byMonthDay($startdate, $enddate, $rdates, $tzid); |
| 267 |
self::debug(1,"byMonth() returned " . $count ); |
| 268 |
return $count; |
| 269 |
} |
| 270 |
|
| 271 |
function byMonthDay($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 272 |
self::debug(1,"byMonthDay(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 273 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 274 |
$count = 0; |
| 275 |
self::debug(1,"start date: " . ZDateHelper::toSqlDateTime($startdate)); |
| 276 |
if(count($this->bymonthday) > 0){ |
| 277 |
foreach($this->bymonthday as $day){ |
| 278 |
$day = intval($day); |
| 279 |
$t = getdate($startdate); |
| 280 |
$wdate = mktime($t['hours'],$t['minutes'],$t['seconds'],$t['mon'],$day,$t['year']); |
| 281 |
self::debug(2,"mktime(" . $t['hours'] . ", " . $t['minutes'] |
| 282 |
. ", " . $t['mon'] . ", " . $day . ", " . $t['year'] . ") returned $wdate"); |
| 283 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 284 |
$count = $this->byDay($wdate, $enddate, $rdates, $tzid); |
| 285 |
if($count == 0) { |
| 286 |
$rdates[] = $wdate; |
| 287 |
$count++; |
| 288 |
} |
| 289 |
} |
| 290 |
} |
| 291 |
} |
| 292 |
else if(!$this->maxDates($rdates)) { |
| 293 |
self::debug(1,"start date: " . ZDateHelper::toSqlDateTime($startdate)); |
| 294 |
$count = $this->byDay($startdate, $enddate, $rdates, $tzid); |
| 295 |
} |
| 296 |
self::debug(1,"byMonthDay() returned " . $count ); |
| 297 |
return $count; |
| 298 |
} |
| 299 |
|
| 300 |
function byDay($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 301 |
self::debug(1,"byDay(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 302 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 303 |
$days = array( |
| 304 |
"SU" => 0, |
| 305 |
"MO" => 1, |
| 306 |
"TU" => 2, |
| 307 |
"WE" => 3, |
| 308 |
"TH" => 4, |
| 309 |
"FR" => 5, |
| 310 |
"SA" => 6); |
| 311 |
$idays = array( |
| 312 |
0 => "SU", |
| 313 |
1 => "MO", |
| 314 |
2 => "TU", |
| 315 |
3 => "WE", |
| 316 |
4 => "TH", |
| 317 |
5 => "FR", |
| 318 |
6 => "SA"); |
| 319 |
|
| 320 |
$count = 0; |
| 321 |
if(count($this->byday) > 0){ |
| 322 |
if(empty($this->byday[0])) |
| 323 |
{ |
| 324 |
$this->byday[0] = $idays[date("w",$startdate)]; |
| 325 |
} |
| 326 |
foreach($this->byday as $tday){ |
| 327 |
$t = getdate($startdate); |
| 328 |
$day = substr($tday,strlen($tday) - 2); |
| 329 |
if(strlen($day) < 2) |
| 330 |
{ |
| 331 |
// missing start day, use current date for DOW |
| 332 |
$day = $idays[date("w",$startdate)]; |
| 333 |
} |
| 334 |
if(strlen($tday) > 2) { |
| 335 |
$imin = 1; |
| 336 |
$imax = 5; // max # of occurances in a month |
| 337 |
if(strlen($tday) > 2) |
| 338 |
$imin = $imax = substr($tday,0,strlen($tday) - 2); |
| 339 |
self::debug(2,"imin: $imin, imax: $imax, tday: $tday, day: $day, daynum: {$days[$day]}"); |
| 340 |
for($i = $imin; $i <= $imax; $i++){ |
| 341 |
$wdate = ZDateHelper::getDateFromDay($startdate,$i-1,$days[$day],$tzid); |
| 342 |
self::debug(2,"getDateFromDay(" . ZDateHelper::toSqlDateTime($startdate) |
| 343 |
. ",$i,{$days[$day]}) returned " . ZDateHelper::toSqlDateTime($wdate)); |
| 344 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 345 |
$count = $this->byHour($wdate, $enddate, $rdates); |
| 346 |
if($count == 0){ |
| 347 |
$rdates[] = $wdate; |
| 348 |
$count++; |
| 349 |
//break; |
| 350 |
} |
| 351 |
} |
| 352 |
} |
| 353 |
} |
| 354 |
else { |
| 355 |
// day of week version |
| 356 |
$startdate_dow = date("w",$startdate); |
| 357 |
$datedelta = $days[$day] - $startdate_dow; |
| 358 |
self::debug(2, "start_dow: $startdate_dow, datedelta: $datedelta"); |
| 359 |
if($datedelta >= 0) |
| 360 |
{ |
| 361 |
$wdate = ZDateHelper::addDate($startdate,0,0,0,0,$datedelta,0,$this->tzid); |
| 362 |
self::debug(2, "wdate: " . ZDateHelper::toSqlDateTime($wdate)); |
| 363 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 364 |
$count = $this->byHour($wdate, $enddate, $rdates); |
| 365 |
if($count == 0){ |
| 366 |
$rdates[] = $wdate; |
| 367 |
$count++; |
| 368 |
self::debug(2,"adding date " . ZDateHelper::toSqlDateTime($wdate) ); |
| 369 |
} |
| 370 |
} |
| 371 |
} |
| 372 |
} |
| 373 |
} |
| 374 |
} |
| 375 |
else if(!$this->maxDates($rdates)) |
| 376 |
$count = $this->byHour($startdate, $enddate, $rdates); |
| 377 |
self::debug(1,"byDay() returned " . $count ); |
| 378 |
return $count; |
| 379 |
} |
| 380 |
|
| 381 |
function byHour($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 382 |
self::debug(1,"byHour(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 383 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 384 |
$count = 0; |
| 385 |
if(count($this->byhour) > 0){ |
| 386 |
foreach($this->byhour as $hour){ |
| 387 |
$t = getdate($startdate); |
| 388 |
$wdate = mktime($hour,$t["minutes"],$t["seconds"],$t["mon"],$t["mday"],$t["year"]); |
| 389 |
self::debug(2,"checking date/time " . ZDateHelper::toSqlDateTime($wdate)); |
| 390 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 391 |
$count = $this->byMinute($wdate, $enddate, $rdates); |
| 392 |
if($count == 0) { |
| 393 |
$rdates[] = $wdate; |
| 394 |
$count++; |
| 395 |
} |
| 396 |
} |
| 397 |
} |
| 398 |
} |
| 399 |
else if(!$this->maxDates($rdates)) |
| 400 |
$count = $this->byMinute($startdate, $enddate, $rdates); |
| 401 |
self::debug(1,"byHour() returned " . $count ); |
| 402 |
return $count; |
| 403 |
} |
| 404 |
|
| 405 |
function byMinute($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 406 |
self::debug(1,"byMinute(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 407 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 408 |
$count = 0; |
| 409 |
if(count($this->byminute) > 0){ |
| 410 |
foreach($this->byminute as $minute){ |
| 411 |
$t = getdate($startdate); |
| 412 |
$wdate = mktime($t["hours"],$minute,$t["seconds"],$t["mon"],$t["mday"],$t["year"]); |
| 413 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 414 |
$count = $this->bySecond($wdate, $enddate, $rdates); |
| 415 |
if($count == 0) { |
| 416 |
$rdates[] = $wdate; |
| 417 |
$count++; |
| 418 |
} |
| 419 |
} |
| 420 |
} |
| 421 |
} |
| 422 |
else if(!$this->maxDates($rdates)) |
| 423 |
$count = $this->bySecond($startdate, $enddate, $rdates); |
| 424 |
self::debug(1,"byMinute() returned " . $count ); |
| 425 |
return $count; |
| 426 |
} |
| 427 |
|
| 428 |
function bySecond($startdate, $enddate, &$rdates, $tzid="UTC"){ |
| 429 |
self::debug(1,"bySecond(" . ZDateHelper::toSqlDateTime($startdate) . "," |
| 430 |
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)"); |
| 431 |
$count = 0; |
| 432 |
if(count($this->bysecond) > 0){ |
| 433 |
foreach($this->bysecond as $second){ |
| 434 |
$t = getdate($startdate); |
| 435 |
$wdate = mktime($t["hours"],$t["minutes"],$second,$t["mon"],$t["mday"],$t["year"]); |
| 436 |
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){ |
| 437 |
$rdates[] = $wdate; |
| 438 |
$count++; |
| 439 |
} |
| 440 |
} |
| 441 |
} |
| 442 |
self::debug(1,"bySecond() returned " . $count ); |
| 443 |
return $count; |
| 444 |
} |
| 445 |
|
| 446 |
function maxDates($rdates){ |
| 447 |
if($this->repeatmode == "c" && count($rdates) >= $this->count) |
| 448 |
return true; // exceeded count |
| 449 |
else if(count($rdates) > 0 && $this->repeatmode == "u" && $rdates[count($rdates) - 1] > $this->until){ |
| 450 |
return true; //past date |
| 451 |
} |
| 452 |
return false; |
| 453 |
} |
| 454 |
|
| 455 |
function getDates($maxdate = null){ |
| 456 |
//$this->debug = 2; |
| 457 |
self::debug(1,"getDates()"); |
| 458 |
$nextdate = $enddate = $this->startdate; |
| 459 |
$rdates = array(); |
| 460 |
$done = false; |
| 461 |
$eventcount = 0; |
| 462 |
$loopcount = 0; |
| 463 |
self::debug(2,"freq: " . $this->freq . ", interval: " . $this->interval); |
| 464 |
while(!$done){ |
| 465 |
self::debug(1,"<b>*** Frequency ({$this->freq}) loop pass $loopcount ***</b>"); |
| 466 |
switch($this->freq){ |
| 467 |
case "y": |
| 468 |
if($eventcount > 0) |
| 469 |
{ |
| 470 |
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,0,$this->interval,$this->tzid); |
| 471 |
self::debug(2,"addDate() returned " . ZDateHelper::toSqlDateTime($nextdate)); |
| 472 |
if(!empty($this->byday)){ |
| 473 |
$t = getdate($nextdate); |
| 474 |
$nextdate = gmmktime($t["hours"],$t["minutes"],$t["seconds"],$t["mon"],1,$t["year"]); |
| 475 |
} |
| 476 |
self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")"); |
| 477 |
} |
| 478 |
$enddate=ZDateHelper::addDate($nextdate,0,0,0,0,0,1); |
| 479 |
break; |
| 480 |
case "m": |
| 481 |
if($eventcount > 0) |
| 482 |
{ |
| 483 |
|
| 484 |
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0,$this->tzid); |
| 485 |
self::debug(2,"addDate() returned " . ZDateHelper::toSqlDateTime($nextdate)); |
| 486 |
} |
| 487 |
if(count($this->byday) > 0) |
| 488 |
{ |
| 489 |
$t = getdate($nextdate); |
| 490 |
if($t["mday"] > 28) |
| 491 |
{ |
| 492 |
//check for short months when using month by day, make sure we do not overshoot the counter and skip a month |
| 493 |
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0,$this->tzid); |
| 494 |
$t2 = getdate($nextdate); |
| 495 |
if($t2["mday"] < $t["mday"]) |
| 496 |
{ |
| 497 |
// oops, skipped a month, backup to previous month |
| 498 |
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$t2["mday"] - $t["mday"],0,$this->tzid); |
| 499 |
} |
| 500 |
} |
| 501 |
$t = getdate($nextdate); |
| 502 |
$nextdate = mktime($t["hours"],$t["minutes"],$t["seconds"],$t["mon"],1,$t["year"]); |
| 503 |
} |
| 504 |
self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")"); |
| 505 |
$enddate=ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0); |
| 506 |
break; |
| 507 |
case "w": |
| 508 |
if($eventcount == 0) |
| 509 |
$nextdate=$nextdate; |
| 510 |
else { |
| 511 |
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval*7,0,$this->tzid); |
| 512 |
if(count($this->byday) > 0){ |
| 513 |
$dow = date("w", $nextdate); |
| 514 |
// move to beginning of week (Sunday) |
| 515 |
$bow = 0; |
| 516 |
$diff = $bow - $dow; |
| 517 |
if($diff > 0) |
| 518 |
$diff = $diff - 7; |
| 519 |
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$diff,0); |
| 520 |
} |
| 521 |
self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")"); |
| 522 |
} |
| 523 |
$enddate=ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval*7,0); |
| 524 |
break; |
| 525 |
case "d": |
| 526 |
$nextdate=($eventcount==0?$nextdate: |
| 527 |
ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval,0,$this->tzid)); |
| 528 |
$enddate=ZDateHelper::addDate($nextdate,0,0,0,0,1,0); |
| 529 |
break; |
| 530 |
} |
| 531 |
|
| 532 |
$count = $this->byYear($nextdate,$enddate,$rdates,$this->tzid); |
| 533 |
$eventcount += $count; |
| 534 |
if($maxdate > 0 && $maxdate < $nextdate) |
| 535 |
{ |
| 536 |
array_pop($rdates); |
| 537 |
$done = true; |
| 538 |
} |
| 539 |
else if($count == 0 && !$this->maxDates($rdates)){ |
| 540 |
$rdates[] = $nextdate; |
| 541 |
$eventcount++; |
| 542 |
} |
| 543 |
if($this->maxDates($rdates)) |
| 544 |
$done = true; |
| 545 |
|
| 546 |
$year = date("Y", $nextdate); |
| 547 |
if($year > _ZAPCAL_MAXYEAR) |
| 548 |
{ |
| 549 |
$done = true; |
| 550 |
} |
| 551 |
$loopcount++; |
| 552 |
if($loopcount > _ZAPCAL_MAXYEAR){ |
| 553 |
$done = true; |
| 554 |
throw new Exception("Infinite loop detected in getDates()"); |
| 555 |
} |
| 556 |
} |
| 557 |
if($this->repeatmode == "u" && $rdates[count($rdates) - 1] > $this->until){ |
| 558 |
// erase last item |
| 559 |
array_pop($rdates); |
| 560 |
} |
| 561 |
$count1 = count($rdates); |
| 562 |
$rdates = array_unique($rdates); |
| 563 |
$count2 = count($rdates); |
| 564 |
$dups = $count1 - $count2; |
| 565 |
$excount = 0; |
| 566 |
|
| 567 |
foreach($this->exdates as $exdate) |
| 568 |
{ |
| 569 |
if($pos = array_search($exdate,$rdates)) |
| 570 |
{ |
| 571 |
array_splice($rdates,$pos,1); |
| 572 |
$excount++; |
| 573 |
} |
| 574 |
} |
| 575 |
self::debug(1,"getDates() returned " . count($rdates) . " dates, removing $dups duplicates, $excount exceptions"); |
| 576 |
|
| 577 |
|
| 578 |
if($this->debug >= 2) |
| 579 |
{ |
| 580 |
self::debug(2,"Recurring Dates:"); |
| 581 |
foreach($rdates as $rdate) |
| 582 |
{ |
| 583 |
$d = getdate($rdate); |
| 584 |
self::debug(2,ZDateHelper::toSQLDateTime($rdate) . " " . $d["wday"] ); |
| 585 |
} |
| 586 |
self::debug(2,"Exception Dates:"); |
| 587 |
foreach($this->exdates as $exdate) |
| 588 |
{ |
| 589 |
self::debug(2, ZDateHelper::toSQLDateTime($exdate)); |
| 590 |
} |
| 591 |
//exit; |
| 592 |
} |
| 593 |
|
| 594 |
return $rdates; |
| 595 |
} |
| 596 |
} |
| 597 |
|