1
1
package rrule
2
2
3
3
import (
4
+ "fmt"
4
5
"time"
5
6
)
6
7
@@ -224,14 +225,20 @@ func (rrule RRule) Iterator() Iterator {
224
225
switch rrule .Frequency {
225
226
case Secondly :
226
227
return setSecondly (rrule )
228
+ case Minutely :
229
+ return setMinutely (rrule )
230
+ case Hourly :
231
+ return setHourly (rrule )
227
232
case Daily :
228
233
return setDaily (rrule )
229
234
case Weekly :
230
235
return setWeekly (rrule )
231
236
case Monthly :
232
237
return setMonthly (rrule )
238
+ case Yearly :
239
+ return setYearly (rrule )
233
240
default :
234
- panic ("not implemented" )
241
+ panic (fmt . Sprintf ( "invalid frequency %v" , rrule . Frequency ) )
235
242
}
236
243
}
237
244
@@ -276,6 +283,89 @@ func setSecondly(rrule RRule) *iterator {
276
283
}
277
284
}
278
285
286
+ func setMinutely (rrule RRule ) * iterator {
287
+ start := rrule .Dtstart
288
+ if start .IsZero () {
289
+ start = time .Now ()
290
+ }
291
+
292
+ interval := 1
293
+ if rrule .Interval != 0 {
294
+ interval = rrule .Interval
295
+ }
296
+
297
+ current := start
298
+
299
+ return & iterator {
300
+ minTime : start ,
301
+ queueCap : rrule .Count ,
302
+ next : func () * time.Time {
303
+ ret := current // copy current
304
+ current = current .Add (time .Duration (interval ) * time .Minute )
305
+ return & ret
306
+ },
307
+
308
+ valid : func (t time.Time ) bool {
309
+ return checkLimiters (t ,
310
+ validMonth (rrule .ByMonths ),
311
+ validWeek (rrule .ByWeekNumbers ),
312
+ validYearDay (rrule .ByYearDays ),
313
+ validMonthDay (rrule .ByMonthDays ),
314
+ validWeekday (rrule .ByWeekdays ),
315
+ validHour (rrule .ByHours ),
316
+ validMinute (rrule .ByMinutes ),
317
+ )
318
+ },
319
+
320
+ variations : func (t time.Time ) []time.Time {
321
+ tt := expandBySeconds ([]time.Time {t }, rrule .BySeconds ... )
322
+ return tt
323
+ },
324
+ }
325
+ }
326
+
327
+ func setHourly (rrule RRule ) * iterator {
328
+ start := rrule .Dtstart
329
+ if start .IsZero () {
330
+ start = time .Now ()
331
+ }
332
+
333
+ interval := 1
334
+ if rrule .Interval != 0 {
335
+ interval = rrule .Interval
336
+ }
337
+
338
+ current := start
339
+
340
+ return & iterator {
341
+ minTime : start ,
342
+ queueCap : rrule .Count ,
343
+ next : func () * time.Time {
344
+ ret := current // copy current
345
+ current = current .Add (time .Duration (interval ) * time .Hour )
346
+ return & ret
347
+ },
348
+
349
+ valid : func (t time.Time ) bool {
350
+ return true
351
+ return checkLimiters (t ,
352
+ validMonth (rrule .ByMonths ),
353
+ validWeek (rrule .ByWeekNumbers ),
354
+ validYearDay (rrule .ByYearDays ),
355
+ validMonthDay (rrule .ByMonthDays ),
356
+ validWeekday (rrule .ByWeekdays ),
357
+ validHour (rrule .ByHours ),
358
+ )
359
+ },
360
+
361
+ variations : func (t time.Time ) []time.Time {
362
+ tt := expandByMinutes ([]time.Time {t }, rrule .ByMinutes ... )
363
+ tt = expandBySeconds (tt , rrule .BySeconds ... )
364
+ return tt
365
+ },
366
+ }
367
+ }
368
+
279
369
func setMonthly (rrule RRule ) * iterator {
280
370
start := rrule .Dtstart
281
371
if start .IsZero () {
@@ -404,6 +494,48 @@ func setWeekly(rrule RRule) *iterator {
404
494
}
405
495
}
406
496
497
+ func setYearly (rrule RRule ) * iterator {
498
+ start := rrule .Dtstart
499
+ if start .IsZero () {
500
+ start = time .Now ()
501
+ }
502
+
503
+ interval := 1
504
+ if rrule .Interval != 0 {
505
+ interval = rrule .Interval
506
+ }
507
+
508
+ current := start
509
+
510
+ return & iterator {
511
+ minTime : start ,
512
+ queueCap : rrule .Count ,
513
+ next : func () * time.Time {
514
+ ret := current // copy current
515
+ current = current .AddDate (interval , 0 , 0 )
516
+ return & ret
517
+ },
518
+
519
+ valid : func (t time.Time ) bool {
520
+ return checkLimiters (t ,
521
+ validMonth (rrule .ByMonths ),
522
+ )
523
+ },
524
+
525
+ variations : func (t time.Time ) []time.Time {
526
+ tt := expandBySeconds ([]time.Time {t }, rrule .BySeconds ... )
527
+ tt = expandByMinutes (tt , rrule .ByMinutes ... )
528
+ tt = expandByHours (tt , rrule .ByHours ... )
529
+ // tt = expandByWeekdays(tt, rrule.weekStart(), rrule.ByWeekdays...)
530
+ tt = expandByMonthDays (tt , rrule .ByMonthDays ... )
531
+ tt = expandByYearDays (tt , rrule .ByYearDays ... )
532
+ tt = expandByWeekNumbers (tt , rrule .weekStart (), rrule .ByWeekNumbers ... )
533
+ tt = expandByMonths (tt , rrule .IB , rrule .ByMonths ... )
534
+ return tt
535
+ },
536
+ }
537
+ }
538
+
407
539
func (rrule * RRule ) weekStart () time.Weekday {
408
540
if rrule .WeekStart == nil {
409
541
return time .Monday
@@ -461,7 +593,7 @@ func expandByWeekdays(tt []time.Time, weekStart time.Weekday, weekdays ...Qualif
461
593
return tt
462
594
}
463
595
464
- e := make ([]time.Time , len (tt )* len (weekdays ))
596
+ e := make ([]time.Time , 0 , len (tt )* len (weekdays ))
465
597
for _ , t := range tt {
466
598
t = backToWeekday (t , weekStart )
467
599
for _ , wd := range weekdays {
@@ -575,7 +707,7 @@ func expandByMonthDays(tt []time.Time, monthdays ...int) []time.Time {
575
707
return tt
576
708
}
577
709
578
- e := make ([]time.Time , len (tt )* len (monthdays ))
710
+ e := make ([]time.Time , 0 , len (tt )* len (monthdays ))
579
711
for _ , t := range tt {
580
712
for _ , md := range monthdays {
581
713
e = append (e , time .Date (t .Year (), t .Month (), md , t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ()))
@@ -585,6 +717,70 @@ func expandByMonthDays(tt []time.Time, monthdays ...int) []time.Time {
585
717
return e
586
718
}
587
719
720
+ func expandByYearDays (tt []time.Time , yeardays ... int ) []time.Time {
721
+ if len (yeardays ) == 0 {
722
+ return tt
723
+ }
724
+
725
+ e := make ([]time.Time , 0 , len (tt )* len (yeardays ))
726
+ for _ , t := range tt {
727
+ yearStart := time .Date (t .Year (), time .January , 1 , t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
728
+
729
+ for _ , yd := range yeardays {
730
+ e = append (e , yearStart .AddDate (0 , 0 , yd ))
731
+ }
732
+ }
733
+
734
+ return e
735
+ }
736
+
737
+ func expandByWeekNumbers (tt []time.Time , weekStarts time.Weekday , weekNumbers ... int ) []time.Time {
738
+ if len (weekNumbers ) == 0 {
739
+ return tt
740
+ }
741
+
742
+ e := make ([]time.Time , 0 , len (tt )* len (weekNumbers ))
743
+ for _ , t := range tt {
744
+ yearStart := time .Date (t .Year (), time .January , 1 , t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
745
+ yearStart = forwardToWeekday (yearStart , t .Weekday ())
746
+
747
+ for _ , w := range weekNumbers {
748
+ e = append (e , yearStart .AddDate (0 , 0 , (w - 1 )* 7 ))
749
+ }
750
+ }
751
+
752
+ return e
753
+ }
754
+
755
+ func expandByMonths (tt []time.Time , ib InvalidBehavior , months ... time.Month ) []time.Time {
756
+ if len (months ) == 0 {
757
+ return tt
758
+ }
759
+
760
+ e := make ([]time.Time , 0 , len (tt )* len (months ))
761
+ for _ , t := range tt {
762
+ for _ , m := range months {
763
+ set := time .Date (t .Year (), m , t .Day (), t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
764
+ if set .Month () != m {
765
+ switch ib {
766
+ case PrevInvalid :
767
+ set = time .Date (t .Year (), t .Month ()+ 1 , - 1 , t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
768
+ e = append (e , set )
769
+ case NextInvalid :
770
+ set = time .Date (t .Year (), t .Month ()+ 1 , 1 , t .Hour (), t .Minute (), t .Second (), t .Nanosecond (), t .Location ())
771
+ e = append (e , set )
772
+ case OmitInvalid :
773
+ // do nothing
774
+ }
775
+ } else {
776
+ e = append (e , set )
777
+ }
778
+ }
779
+ }
780
+
781
+ return e
782
+ }
783
+
588
784
type iterator struct {
589
785
queue []time.Time
590
786
totalQueued uint64
0 commit comments