@@ -85,30 +85,27 @@ public function rewind()
85
85
86
86
/**
87
87
* Goes on to the next iteration.
88
+ * @param int $amount
88
89
*/
89
- public function next ()
90
+ public function next ($ amount = 1 )
90
91
{
91
92
// Otherwise, we find the next event in the normal RRULE
92
93
// sequence.
93
94
switch ($ this ->frequency ) {
94
- case 'hourly ' :
95
- $ this ->nextHourly ();
95
+ case 'hourly ' :
96
+ $ this ->nextHourly ($ amount );
96
97
break ;
97
-
98
- case 'daily ' :
99
- $ this ->nextDaily ();
98
+ case 'daily ' :
99
+ $ this ->nextDaily ($ amount );
100
100
break ;
101
-
102
- case 'weekly ' :
103
- $ this ->nextWeekly ();
101
+ case 'weekly ' :
102
+ $ this ->nextWeekly ($ amount );
104
103
break ;
105
-
106
- case 'monthly ' :
107
- $ this ->nextMonthly ();
104
+ case 'monthly ' :
105
+ $ this ->nextMonthly ($ amount );
108
106
break ;
109
-
110
- case 'yearly ' :
111
- $ this ->nextYearly ();
107
+ case 'yearly ' :
108
+ $ this ->nextYearly ($ amount );
112
109
break ;
113
110
}
114
111
++$ this ->counter ;
@@ -134,9 +131,49 @@ public function isInfinite()
134
131
*/
135
132
public function fastForward (DateTimeInterface $ dt )
136
133
{
134
+ if (!isset ($ this ->count )) {
135
+ do {
136
+ $ diff = $ this ->currentDate ->diff ($ dt );
137
+ switch ($ this ->frequency ) {
138
+ case 'hourly ' :
139
+ $ i = $ diff ->days * 24 ;
140
+ break ;
141
+ case 'daily ' :
142
+ $ i = $ diff ->days ;
143
+ break ;
144
+ case 'weekly ' :
145
+ $ i = $ diff ->days / 7 ;
146
+ break ;
147
+ case 'monthly ' :
148
+ $ i = $ diff ->days / 30 ;
149
+ break ;
150
+ case 'yearly ' :
151
+ $ i = $ diff ->days / 365 ;
152
+ break ;
153
+ }
154
+ $ i /= $ this ->interval ;
155
+ $ i /= 4 ;
156
+ $ i = floor ($ i );
157
+ $ i = max (1 , $ i );
158
+ do {
159
+ $ previousDate = clone $ this ->currentDate ;
160
+ $ this ->next ($ i );
161
+ } while ($ this ->valid () && $ this ->currentDate < $ dt );
162
+
163
+ $ this ->currentDate = $ previousDate ;
164
+ // do one step to avoid deadlock
165
+ $ this ->next ();
166
+ } while ($ i > 5 && $ this ->valid () && $ this ->currentDate < $ dt );
167
+ }
168
+
137
169
while ($ this ->valid () && $ this ->currentDate < $ dt ) {
138
170
$ this ->next ();
139
171
}
172
+
173
+ if (!isset ($ this ->count )) {
174
+ // We don't know the counter at this point anymore
175
+ $ this ->counter = NAN ;
176
+ }
140
177
}
141
178
142
179
/**
@@ -306,19 +343,18 @@ public function fastForward(DateTimeInterface $dt)
306
343
/**
307
344
* Does the processing for advancing the iterator for hourly frequency.
308
345
*/
309
- protected function nextHourly ()
346
+ protected function nextHourly ($ amount = 1 )
310
347
{
311
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' hours ' );
348
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ amount * $ this ->interval .' hours ' );
312
349
}
313
350
314
351
/**
315
352
* Does the processing for advancing the iterator for daily frequency.
316
353
*/
317
- protected function nextDaily ()
354
+ protected function nextDaily ($ amount = 1 )
318
355
{
319
356
if (!$ this ->byHour && !$ this ->byDay ) {
320
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' days ' );
321
-
357
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ amount * $ this ->interval .' days ' );
322
358
return ;
323
359
}
324
360
@@ -338,14 +374,17 @@ protected function nextDaily()
338
374
if ($ this ->byHour ) {
339
375
if ('23 ' == $ this ->currentDate ->format ('G ' )) {
340
376
// to obey the interval rule
341
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval - 1 .' days ' );
377
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .(($ amount * $ this ->interval ) - 1 ).' days ' );
378
+ $ amount = 1 ;
342
379
}
343
380
344
381
$ this ->currentDate = $ this ->currentDate ->modify ('+1 hours ' );
345
382
} else {
346
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' days ' );
383
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .($ amount * $ this ->interval ).' days ' );
384
+ $ amount = 1 ;
347
385
}
348
386
387
+
349
388
// Current month of the year
350
389
$ currentMonth = $ this ->currentDate ->format ('n ' );
351
390
@@ -364,11 +403,10 @@ protected function nextDaily()
364
403
/**
365
404
* Does the processing for advancing the iterator for weekly frequency.
366
405
*/
367
- protected function nextWeekly ()
368
- {
369
- if (!$ this ->byHour && !$ this ->byDay ) {
370
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' weeks ' );
406
+ protected function nextWeekly ($ amount = 1 ) {
371
407
408
+ if (!$ this ->byHour && !$ this ->byDay ) {
409
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .($ amount * $ this ->interval ).' weeks ' );
372
410
return ;
373
411
}
374
412
@@ -397,9 +435,9 @@ protected function nextWeekly()
397
435
$ currentHour = (int ) $ this ->currentDate ->format ('G ' );
398
436
399
437
// We need to roll over to the next week
400
- if ($ currentDay === $ firstDay && (!$ this ->byHour || ' 0 ' == $ currentHour )) {
401
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval - 1 .' weeks ' );
402
-
438
+ if ($ currentDay === $ firstDay && (!$ this ->byHour || $ currentHour == ' 0 ' )) {
439
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .(( $ amount * $ this ->interval ) - 1 ) .' weeks ' );
440
+ $ amount = 1 ;
403
441
// We need to go to the first day of this week, but only if we
404
442
// are not already on this first day of this week.
405
443
if ($ this ->currentDate ->format ('w ' ) != $ firstDay ) {
@@ -414,7 +452,7 @@ protected function nextWeekly()
414
452
/**
415
453
* Does the processing for advancing the iterator for monthly frequency.
416
454
*/
417
- protected function nextMonthly ()
455
+ protected function nextMonthly ($ amount = 1 )
418
456
{
419
457
$ currentDayOfMonth = $ this ->currentDate ->format ('j ' );
420
458
$ currentHourOfMonth = $ this ->currentDate ->format ('G ' );
@@ -425,9 +463,9 @@ protected function nextMonthly()
425
463
// occur to the next month. We Must skip these invalid
426
464
// entries.
427
465
if ($ currentDayOfMonth < 29 ) {
428
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' months ' );
466
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .( $ amount * $ this ->interval ) .' months ' );
429
467
} else {
430
- $ increase = 0 ;
468
+ $ increase = $ amount - 1 ;
431
469
do {
432
470
++$ increase ;
433
471
$ tempDate = clone $ this ->currentDate ;
@@ -443,7 +481,7 @@ protected function nextMonthly()
443
481
$ occurrences = $ this ->getMonthlyOccurrences ();
444
482
445
483
foreach ($ occurrences as $ occurrence ) {
446
- // The first occurrence thats higher than the current
484
+ // The first occurrence that's higher than the current
447
485
// day of the month wins.
448
486
if ($ occurrence [0 ] > $ currentDayOfMonth ) {
449
487
break 2 ;
@@ -469,13 +507,14 @@ protected function nextMonthly()
469
507
// If we made it all the way here, it means there were no
470
508
// valid occurrences, and we need to advance to the next
471
509
// month.
472
- //
473
- // This line does not currently work in hhvm. Temporary workaround
474
- // follows:
475
- // $this->currentDate->modify('first day of this month');
476
- $ this -> currentDate = new DateTimeImmutable ( $ this -> currentDate -> format ( ' Y-m-1 H:i:s ' ), $ this -> currentDate -> getTimezone () );
510
+ $ this -> currentDate = $ this -> currentDate -> setDate (
511
+ ( int ) $ this -> currentDate -> format ( ' Y ' ),
512
+ ( int ) $ this -> currentDate -> format ( ' n ' ),
513
+ 1
514
+ );
477
515
// end of workaround
478
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' months ' );
516
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .($ amount * $ this ->interval ).' months ' );
517
+ $ amount = 1 ;
479
518
480
519
// This goes to 0 because we need to start counting at the
481
520
// beginning.
@@ -495,10 +534,10 @@ protected function nextMonthly()
495
534
/**
496
535
* Does the processing for advancing the iterator for yearly frequency.
497
536
*/
498
- protected function nextYearly ()
537
+ protected function nextYearly ($ amount = 1 )
499
538
{
500
- $ currentMonth = $ this ->currentDate ->format ('n ' );
501
539
$ currentYear = $ this ->currentDate ->format ('Y ' );
540
+ $ currentMonth = $ this ->currentDate ->format ('n ' );
502
541
$ currentDayOfMonth = $ this ->currentDate ->format ('j ' );
503
542
$ currentHourOfMonth = $ this ->currentDate ->format ('G ' );
504
543
$ currentMinuteOfMonth = $ this ->currentDate ->format ('i ' );
@@ -562,7 +601,8 @@ protected function nextYearly()
562
601
}
563
602
564
603
// if there is no date found, check the next year
565
- $ currentYear += $ this ->interval ;
604
+ $ currentYear += $ amount * $ this ->interval ;
605
+ $ amount = 1 ;
566
606
}
567
607
}
568
608
@@ -604,12 +644,13 @@ protected function nextYearly()
604
644
}
605
645
606
646
// if there is no date found, check the next year
607
- $ currentYear += $ this ->interval ;
647
+ $ currentYear += ($ amount * $ this ->interval );
648
+ $ amount = 1 ;
608
649
}
609
650
}
610
651
611
652
// The easiest form
612
- $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .$ this ->interval .' years ' );
653
+ $ this ->currentDate = $ this ->currentDate ->modify ('+ ' .( $ amount * $ this ->interval ) .' years ' );
613
654
614
655
return ;
615
656
}
@@ -656,7 +697,8 @@ protected function nextYearly()
656
697
do {
657
698
++$ currentMonth ;
658
699
if ($ currentMonth > 12 ) {
659
- $ currentYear += $ this ->interval ;
700
+ $ currentYear += ($ amount * $ this ->interval );
701
+ $ amount = 1 ;
660
702
$ currentMonth = 1 ;
661
703
}
662
704
} while (!in_array ($ currentMonth , $ this ->byMonth ));
0 commit comments