0
# Recurrence and Scheduling
1
2
GCSA provides powerful recurrence capabilities through the Recurrence class and Duration utilities. These classes enable creation of recurring events with complex scheduling patterns using RRULE (RFC 5545) format, exception handling, and flexible timing options.
3
4
## Package Information
5
6
```python
7
from gcsa.recurrence import (
8
Recurrence, Duration,
9
SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY,
10
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
11
SU, MO, TU, WE, TH, FR, SA,
12
DEFAULT_WEEK_START
13
)
14
```
15
16
## Recurrence Class
17
18
### Basic Recurrence Rules
19
20
```python { .api }
21
class Recurrence:
22
@staticmethod
23
def rule(
24
freq,
25
until = None,
26
count = None,
27
interval = None,
28
by_month = None,
29
by_month_day = None,
30
by_year_day = None,
31
by_week_no = None,
32
by_weekday = None,
33
by_hour = None,
34
by_minute = None,
35
by_second = None,
36
by_set_pos = None,
37
week_start = None
38
):
39
"""
40
Create a recurrence rule (RRULE) string.
41
42
:param freq: Frequency of recurrence (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY)
43
:param until: End date/time for recurrence (datetime object)
44
:param count: Number of occurrences (int)
45
:param interval: Interval between occurrences (int, default=1)
46
:param by_month: Month(s) for recurrence (1-12, list or int)
47
:param by_month_day: Day(s) of month for recurrence (1-31, -31 to -1, list or int)
48
:param by_year_day: Day(s) of year for recurrence (1-366, -366 to -1, list or int)
49
:param by_week_no: Week number(s) for recurrence (1-53, -53 to -1, list or int)
50
:param by_weekday: Weekday(s) for recurrence (SU-SA, list or string)
51
:param by_hour: Hour(s) for recurrence (0-23, list or int)
52
:param by_minute: Minute(s) for recurrence (0-59, list or int)
53
:param by_second: Second(s) for recurrence (0-59, list or int)
54
:param by_set_pos: Position(s) in set (1-366, -366 to -1, list or int)
55
:param week_start: First day of week (SU-SA, default=SU)
56
:return: RRULE string
57
"""
58
```
59
60
### Exception Rules and Dates
61
62
```python { .api }
63
@staticmethod
64
def exclude_rule(
65
freq,
66
until = None,
67
count = None,
68
interval = None,
69
by_month = None,
70
by_month_day = None,
71
by_year_day = None,
72
by_week_no = None,
73
by_weekday = None,
74
by_hour = None,
75
by_minute = None,
76
by_second = None,
77
by_set_pos = None,
78
week_start = None
79
):
80
"""
81
Create an exception rule (EXRULE) string to exclude occurrences.
82
83
Parameters same as rule() method.
84
:return: EXRULE string
85
"""
86
87
@staticmethod
88
def dates(*dates):
89
"""
90
Convert dates to RDATE format for including specific dates.
91
92
:param dates: Date objects to include
93
:return: RDATE string
94
"""
95
96
@staticmethod
97
def times(*datetimes):
98
"""
99
Convert datetimes to RDATE format for including specific times.
100
101
:param datetimes: Datetime objects to include
102
:return: RDATE string
103
"""
104
105
@staticmethod
106
def periods(*periods):
107
"""
108
Convert periods to RDATE format for including specific periods.
109
110
:param periods: Period tuples (start, end) to include
111
:return: RDATE string
112
"""
113
114
@staticmethod
115
def exclude_dates(*dates):
116
"""
117
Convert dates to EXDATE format for excluding specific dates.
118
119
:param dates: Date objects to exclude
120
:return: EXDATE string
121
"""
122
123
@staticmethod
124
def exclude_times(*datetimes):
125
"""
126
Convert datetimes to EXDATE format for excluding specific times.
127
128
:param datetimes: Datetime objects to exclude
129
:return: EXDATE string
130
"""
131
132
@staticmethod
133
def exclude_periods(*periods):
134
"""
135
Convert periods to EXDATE format for excluding specific periods.
136
137
:param periods: Period tuples (start, end) to exclude
138
:return: EXDATE string
139
"""
140
```
141
142
## Duration Class
143
144
```python { .api }
145
class Duration:
146
def __init__(
147
self,
148
w = None, # weeks
149
d = None, # days
150
h = None, # hours
151
m = None, # minutes
152
s = None # seconds
153
):
154
"""
155
Create a duration for use in recurrence rules.
156
157
:param w: Number of weeks
158
:param d: Number of days
159
:param h: Number of hours
160
:param m: Number of minutes
161
:param s: Number of seconds
162
"""
163
```
164
165
## Frequency Constants
166
167
```python { .api }
168
# Recurrence frequency options
169
SECONDLY = "SECONDLY" # Every second
170
MINUTELY = "MINUTELY" # Every minute
171
HOURLY = "HOURLY" # Every hour
172
DAILY = "DAILY" # Every day
173
WEEKLY = "WEEKLY" # Every week
174
MONTHLY = "MONTHLY" # Every month
175
YEARLY = "YEARLY" # Every year
176
```
177
178
## Weekday Constants
179
180
```python { .api }
181
# Day constants for recurrence rules
182
SUNDAY = SU = "SU" # Sunday
183
MONDAY = MO = "MO" # Monday
184
TUESDAY = TU = "TU" # Tuesday
185
WEDNESDAY = WE = "WE" # Wednesday
186
THURSDAY = TH = "TH" # Thursday
187
FRIDAY = FR = "FR" # Friday
188
SATURDAY = SA = "SA" # Saturday
189
190
# Default week start
191
DEFAULT_WEEK_START = SUNDAY
192
```
193
194
## Basic Usage Examples
195
196
### Simple Recurring Events
197
198
```python
199
from gcsa.google_calendar import GoogleCalendar
200
from gcsa.event import Event
201
from gcsa.recurrence import Recurrence, DAILY, WEEKLY, MONTHLY
202
from datetime import datetime, date
203
204
gc = GoogleCalendar()
205
206
# Daily recurring event
207
daily_standup = Event(
208
summary="Daily Standup",
209
start=datetime(2024, 1, 15, 9, 0),
210
end=datetime(2024, 1, 15, 9, 15),
211
recurrence=[
212
Recurrence.rule(freq=DAILY, count=30) # 30 occurrences
213
]
214
)
215
gc.add_event(daily_standup)
216
217
# Weekly recurring event
218
weekly_meeting = Event(
219
summary="Team Meeting",
220
start=datetime(2024, 1, 15, 10, 0),
221
end=datetime(2024, 1, 15, 11, 0),
222
recurrence=[
223
Recurrence.rule(freq=WEEKLY, until=datetime(2024, 6, 15)) # Until June 15
224
]
225
)
226
gc.add_event(weekly_meeting)
227
228
# Monthly recurring event
229
monthly_review = Event(
230
summary="Monthly Review",
231
start=datetime(2024, 1, 1, 14, 0),
232
end=datetime(2024, 1, 1, 15, 0),
233
recurrence=[
234
Recurrence.rule(freq=MONTHLY, interval=1, count=12) # Monthly for 1 year
235
]
236
)
237
gc.add_event(monthly_review)
238
```
239
240
### Weekday-Specific Recurring Events
241
242
```python
243
from gcsa.recurrence import Recurrence, WEEKLY, MONDAY, WEDNESDAY, FRIDAY
244
from gcsa.event import Event
245
from datetime import datetime
246
247
# Every Monday, Wednesday, and Friday
248
mwf_workout = Event(
249
summary="Workout Session",
250
start=datetime(2024, 1, 15, 7, 0), # Start on a Monday
251
end=datetime(2024, 1, 15, 8, 0),
252
recurrence=[
253
Recurrence.rule(
254
freq=WEEKLY,
255
by_weekday=[MONDAY, WEDNESDAY, FRIDAY],
256
count=36 # 12 weeks × 3 days
257
)
258
]
259
)
260
gc.add_event(mwf_workout)
261
262
# Every Tuesday and Thursday
263
tt_meetings = Event(
264
summary="Client Check-in",
265
start=datetime(2024, 1, 16, 15, 0), # Start on a Tuesday
266
end=datetime(2024, 1, 16, 15, 30),
267
recurrence=[
268
Recurrence.rule(
269
freq=WEEKLY,
270
by_weekday=[TU, TH], # Can use short forms
271
until=datetime(2024, 12, 31)
272
)
273
]
274
)
275
gc.add_event(tt_meetings)
276
```
277
278
### Advanced Monthly Patterns
279
280
```python
281
from gcsa.recurrence import Recurrence, MONTHLY, FRIDAY
282
from gcsa.event import Event
283
from datetime import datetime
284
285
# First Friday of every month
286
first_friday = Event(
287
summary="First Friday Drinks",
288
start=datetime(2024, 2, 2, 17, 0), # First Friday in Feb
289
end=datetime(2024, 2, 2, 19, 0),
290
recurrence=[
291
Recurrence.rule(
292
freq=MONTHLY,
293
by_weekday=FRIDAY,
294
by_set_pos=1 # First occurrence
295
)
296
]
297
)
298
gc.add_event(first_friday)
299
300
# Last day of every month
301
month_end_report = Event(
302
summary="Month End Report Due",
303
start=datetime(2024, 1, 31, 17, 0),
304
end=datetime(2024, 1, 31, 17, 30),
305
recurrence=[
306
Recurrence.rule(
307
freq=MONTHLY,
308
by_month_day=-1 # Last day of month
309
)
310
]
311
)
312
gc.add_event(month_end_report)
313
314
# 15th of every month
315
mid_month_review = Event(
316
summary="Mid-Month Review",
317
start=datetime(2024, 1, 15, 10, 0),
318
end=datetime(2024, 1, 15, 11, 0),
319
recurrence=[
320
Recurrence.rule(
321
freq=MONTHLY,
322
by_month_day=15,
323
count=12
324
)
325
]
326
)
327
gc.add_event(mid_month_review)
328
```
329
330
### Yearly Recurring Events
331
332
```python
333
from gcsa.recurrence import Recurrence, YEARLY
334
from gcsa.event import Event
335
from datetime import datetime
336
337
# Annual company retreat
338
annual_retreat = Event(
339
summary="Annual Company Retreat",
340
start=datetime(2024, 6, 15, 9, 0),
341
end=datetime(2024, 6, 16, 17, 0), # 2-day event
342
recurrence=[
343
Recurrence.rule(
344
freq=YEARLY,
345
by_month=6, # June
346
by_month_day=15, # 15th
347
count=5 # Next 5 years
348
)
349
]
350
)
351
gc.add_event(annual_retreat)
352
353
# Birthday recurring event
354
birthday = Event(
355
summary="John's Birthday",
356
start=date(2024, 3, 10),
357
end=date(2024, 3, 11),
358
recurrence=[
359
Recurrence.rule(freq=YEARLY) # Every year forever
360
]
361
)
362
gc.add_event(birthday)
363
```
364
365
### Complex Intervals and Patterns
366
367
```python
368
from gcsa.recurrence import Recurrence, DAILY, WEEKLY, MONTHLY
369
from gcsa.event import Event
370
from datetime import datetime
371
372
# Every other day
373
every_other_day = Event(
374
summary="Alternate Day Workout",
375
start=datetime(2024, 1, 15, 6, 0),
376
end=datetime(2024, 1, 15, 7, 0),
377
recurrence=[
378
Recurrence.rule(
379
freq=DAILY,
380
interval=2, # Every 2 days
381
count=50
382
)
383
]
384
)
385
gc.add_event(every_other_day)
386
387
# Every 3 weeks
388
tri_weekly = Event(
389
summary="Tri-weekly Sprint Planning",
390
start=datetime(2024, 1, 15, 9, 0),
391
end=datetime(2024, 1, 15, 10, 30),
392
recurrence=[
393
Recurrence.rule(
394
freq=WEEKLY,
395
interval=3, # Every 3 weeks
396
by_weekday=MONDAY
397
)
398
]
399
)
400
gc.add_event(tri_weekly)
401
402
# Quarterly meetings (every 3 months)
403
quarterly = Event(
404
summary="Quarterly Business Review",
405
start=datetime(2024, 1, 31, 14, 0),
406
end=datetime(2024, 1, 31, 16, 0),
407
recurrence=[
408
Recurrence.rule(
409
freq=MONTHLY,
410
interval=3, # Every 3 months
411
by_month_day=-1 # Last day of quarter-ending month
412
)
413
]
414
)
415
gc.add_event(quarterly)
416
```
417
418
### Recurring Events with Exceptions
419
420
```python
421
from gcsa.recurrence import Recurrence, WEEKLY, MONDAY
422
from gcsa.event import Event
423
from datetime import datetime, date
424
425
# Weekly meeting with holiday exceptions
426
weekly_with_exceptions = Event(
427
summary="Weekly Staff Meeting",
428
start=datetime(2024, 1, 8, 10, 0),
429
end=datetime(2024, 1, 8, 11, 0),
430
recurrence=[
431
# Main rule: every Monday
432
Recurrence.rule(freq=WEEKLY, by_weekday=MONDAY, count=52),
433
434
# Exclude specific dates (holidays)
435
Recurrence.exclude_dates(
436
date(2024, 2, 19), # Presidents Day
437
date(2024, 5, 27), # Memorial Day
438
date(2024, 7, 4), # Independence Day
439
date(2024, 9, 2), # Labor Day
440
date(2024, 11, 28) # Thanksgiving week
441
)
442
]
443
)
444
gc.add_event(weekly_with_exceptions)
445
```
446
447
### Adding Specific Dates to Recurrence
448
449
```python
450
from gcsa.recurrence import Recurrence, WEEKLY, FRIDAY
451
from gcsa.event import Event
452
from datetime import datetime, date
453
454
# Regular weekly meeting plus additional dates
455
meeting_with_extras = Event(
456
summary="Team Sync",
457
start=datetime(2024, 1, 5, 14, 0), # First Friday
458
end=datetime(2024, 1, 5, 15, 0),
459
recurrence=[
460
# Every Friday
461
Recurrence.rule(freq=WEEKLY, by_weekday=FRIDAY),
462
463
# Add extra meeting dates
464
Recurrence.dates(
465
date(2024, 2, 14), # Special Valentine's Day meeting
466
date(2024, 3, 17), # St. Patrick's Day meeting
467
date(2024, 4, 1) # April Fool's Day meeting
468
)
469
]
470
)
471
gc.add_event(meeting_with_extras)
472
```
473
474
### Time-Specific Recurring Patterns
475
476
```python
477
from gcsa.recurrence import Recurrence, DAILY
478
from gcsa.event import Event
479
from datetime import datetime, time
480
481
# Multiple daily occurrences
482
daily_medication = Event(
483
summary="Medication Reminder",
484
start=datetime(2024, 1, 15, 8, 0),
485
end=datetime(2024, 1, 15, 8, 5),
486
recurrence=[
487
Recurrence.rule(
488
freq=DAILY,
489
by_hour=[8, 14, 20], # 8 AM, 2 PM, 8 PM
490
count=90 # 30 days × 3 times daily
491
)
492
]
493
)
494
gc.add_event(daily_medication)
495
496
# Hourly reminders during work hours
497
hourly_standup = Event(
498
summary="Hourly Check-in",
499
start=datetime(2024, 1, 15, 9, 0),
500
end=datetime(2024, 1, 15, 9, 5),
501
recurrence=[
502
Recurrence.rule(
503
freq=HOURLY,
504
by_weekday=[MO, TU, WE, TH, FR], # Weekdays only
505
by_hour=list(range(9, 17)), # 9 AM to 4 PM
506
until=datetime(2024, 12, 31)
507
)
508
]
509
)
510
gc.add_event(hourly_standup)
511
```
512
513
### Working with Duration
514
515
```python
516
from gcsa.recurrence import Duration
517
from gcsa.event import Event
518
from datetime import datetime
519
520
# Event with duration-based recurrence (less common)
521
duration = Duration(h=2, m=30) # 2 hours 30 minutes
522
523
# Note: Duration is mainly used for period-based RDATE entries
524
workshop_series = Event(
525
summary="Workshop Series",
526
start=datetime(2024, 2, 1, 9, 0),
527
end=datetime(2024, 2, 1, 12, 0),
528
recurrence=[
529
# Include specific periods with durations
530
Recurrence.periods(
531
(datetime(2024, 2, 1, 9, 0), datetime(2024, 2, 1, 12, 0)),
532
(datetime(2024, 2, 8, 9, 0), datetime(2024, 2, 8, 12, 0)),
533
(datetime(2024, 2, 15, 9, 0), datetime(2024, 2, 15, 12, 0))
534
)
535
]
536
)
537
gc.add_event(workshop_series)
538
```
539
540
### Week Start Configuration
541
542
```python
543
from gcsa.recurrence import Recurrence, WEEKLY, MONDAY, FRIDAY
544
545
# Specify different week start (Monday instead of Sunday)
546
weekly_meeting = Event(
547
summary="Weekly Planning",
548
start=datetime(2024, 1, 15, 9, 0),
549
end=datetime(2024, 1, 15, 10, 0),
550
recurrence=[
551
Recurrence.rule(
552
freq=WEEKLY,
553
by_weekday=FRIDAY,
554
week_start=MONDAY, # Week starts on Monday
555
count=26
556
)
557
]
558
)
559
gc.add_event(weekly_meeting)
560
```
561
562
### Business Day Patterns
563
564
```python
565
from gcsa.recurrence import Recurrence, WEEKLY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
566
567
# Every business day (Monday through Friday)
568
daily_briefing = Event(
569
summary="Daily Team Briefing",
570
start=datetime(2024, 1, 15, 8, 30),
571
end=datetime(2024, 1, 15, 8, 45),
572
recurrence=[
573
Recurrence.rule(
574
freq=WEEKLY,
575
by_weekday=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY],
576
until=datetime(2024, 12, 31)
577
)
578
]
579
)
580
gc.add_event(daily_briefing)
581
582
# First business day of each month
583
monthly_report = Event(
584
summary="Monthly Report Due",
585
start=datetime(2024, 2, 1, 9, 0), # First business day of Feb
586
end=datetime(2024, 2, 1, 9, 30),
587
recurrence=[
588
Recurrence.rule(
589
freq=MONTHLY,
590
by_weekday=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY],
591
by_set_pos=1 # First weekday occurrence
592
)
593
]
594
)
595
gc.add_event(monthly_report)
596
```
597
598
### Error Handling for Recurrence
599
600
```python
601
from gcsa.recurrence import Recurrence, DAILY, WEEKLY
602
from gcsa.event import Event
603
from datetime import datetime
604
605
try:
606
# Invalid recurrence rule (count and until cannot both be specified)
607
invalid_event = Event(
608
summary="Invalid Recurrence",
609
start=datetime(2024, 1, 15, 10, 0),
610
end=datetime(2024, 1, 15, 11, 0),
611
recurrence=[
612
Recurrence.rule(
613
freq=DAILY,
614
count=30, # Count specified
615
until=datetime(2024, 6, 15) # Until also specified - invalid!
616
)
617
]
618
)
619
gc.add_event(invalid_event)
620
except Exception as e:
621
print(f"Recurrence error: {e}")
622
623
# Correct approach - use either count or until, not both
624
valid_event = Event(
625
summary="Valid Recurrence",
626
start=datetime(2024, 1, 15, 10, 0),
627
end=datetime(2024, 1, 15, 11, 0),
628
recurrence=[
629
Recurrence.rule(freq=DAILY, count=30) # Only count
630
]
631
)
632
gc.add_event(valid_event)
633
```
634
635
The Recurrence class provides comprehensive support for creating complex recurring event patterns using the standard RRULE format. It supports all common scheduling scenarios from simple daily meetings to complex business rules with exceptions and custom intervals.