Simple API for Google Calendar management
—
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.
from gcsa.recurrence import (
Recurrence, Duration,
SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY,
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
SU, MO, TU, WE, TH, FR, SA,
DEFAULT_WEEK_START
)class Recurrence:
@staticmethod
def rule(
freq,
until = None,
count = None,
interval = None,
by_month = None,
by_month_day = None,
by_year_day = None,
by_week_no = None,
by_weekday = None,
by_hour = None,
by_minute = None,
by_second = None,
by_set_pos = None,
week_start = None
):
"""
Create a recurrence rule (RRULE) string.
:param freq: Frequency of recurrence (SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY)
:param until: End date/time for recurrence (datetime object)
:param count: Number of occurrences (int)
:param interval: Interval between occurrences (int, default=1)
:param by_month: Month(s) for recurrence (1-12, list or int)
:param by_month_day: Day(s) of month for recurrence (1-31, -31 to -1, list or int)
:param by_year_day: Day(s) of year for recurrence (1-366, -366 to -1, list or int)
:param by_week_no: Week number(s) for recurrence (1-53, -53 to -1, list or int)
:param by_weekday: Weekday(s) for recurrence (SU-SA, list or string)
:param by_hour: Hour(s) for recurrence (0-23, list or int)
:param by_minute: Minute(s) for recurrence (0-59, list or int)
:param by_second: Second(s) for recurrence (0-59, list or int)
:param by_set_pos: Position(s) in set (1-366, -366 to -1, list or int)
:param week_start: First day of week (SU-SA, default=SU)
:return: RRULE string
"""@staticmethod
def exclude_rule(
freq,
until = None,
count = None,
interval = None,
by_month = None,
by_month_day = None,
by_year_day = None,
by_week_no = None,
by_weekday = None,
by_hour = None,
by_minute = None,
by_second = None,
by_set_pos = None,
week_start = None
):
"""
Create an exception rule (EXRULE) string to exclude occurrences.
Parameters same as rule() method.
:return: EXRULE string
"""
@staticmethod
def dates(*dates):
"""
Convert dates to RDATE format for including specific dates.
:param dates: Date objects to include
:return: RDATE string
"""
@staticmethod
def times(*datetimes):
"""
Convert datetimes to RDATE format for including specific times.
:param datetimes: Datetime objects to include
:return: RDATE string
"""
@staticmethod
def periods(*periods):
"""
Convert periods to RDATE format for including specific periods.
:param periods: Period tuples (start, end) to include
:return: RDATE string
"""
@staticmethod
def exclude_dates(*dates):
"""
Convert dates to EXDATE format for excluding specific dates.
:param dates: Date objects to exclude
:return: EXDATE string
"""
@staticmethod
def exclude_times(*datetimes):
"""
Convert datetimes to EXDATE format for excluding specific times.
:param datetimes: Datetime objects to exclude
:return: EXDATE string
"""
@staticmethod
def exclude_periods(*periods):
"""
Convert periods to EXDATE format for excluding specific periods.
:param periods: Period tuples (start, end) to exclude
:return: EXDATE string
"""class Duration:
def __init__(
self,
w = None, # weeks
d = None, # days
h = None, # hours
m = None, # minutes
s = None # seconds
):
"""
Create a duration for use in recurrence rules.
:param w: Number of weeks
:param d: Number of days
:param h: Number of hours
:param m: Number of minutes
:param s: Number of seconds
"""# Recurrence frequency options
SECONDLY = "SECONDLY" # Every second
MINUTELY = "MINUTELY" # Every minute
HOURLY = "HOURLY" # Every hour
DAILY = "DAILY" # Every day
WEEKLY = "WEEKLY" # Every week
MONTHLY = "MONTHLY" # Every month
YEARLY = "YEARLY" # Every year# Day constants for recurrence rules
SUNDAY = SU = "SU" # Sunday
MONDAY = MO = "MO" # Monday
TUESDAY = TU = "TU" # Tuesday
WEDNESDAY = WE = "WE" # Wednesday
THURSDAY = TH = "TH" # Thursday
FRIDAY = FR = "FR" # Friday
SATURDAY = SA = "SA" # Saturday
# Default week start
DEFAULT_WEEK_START = SUNDAYfrom gcsa.google_calendar import GoogleCalendar
from gcsa.event import Event
from gcsa.recurrence import Recurrence, DAILY, WEEKLY, MONTHLY
from datetime import datetime, date
gc = GoogleCalendar()
# Daily recurring event
daily_standup = Event(
summary="Daily Standup",
start=datetime(2024, 1, 15, 9, 0),
end=datetime(2024, 1, 15, 9, 15),
recurrence=[
Recurrence.rule(freq=DAILY, count=30) # 30 occurrences
]
)
gc.add_event(daily_standup)
# Weekly recurring event
weekly_meeting = Event(
summary="Team Meeting",
start=datetime(2024, 1, 15, 10, 0),
end=datetime(2024, 1, 15, 11, 0),
recurrence=[
Recurrence.rule(freq=WEEKLY, until=datetime(2024, 6, 15)) # Until June 15
]
)
gc.add_event(weekly_meeting)
# Monthly recurring event
monthly_review = Event(
summary="Monthly Review",
start=datetime(2024, 1, 1, 14, 0),
end=datetime(2024, 1, 1, 15, 0),
recurrence=[
Recurrence.rule(freq=MONTHLY, interval=1, count=12) # Monthly for 1 year
]
)
gc.add_event(monthly_review)from gcsa.recurrence import Recurrence, WEEKLY, MONDAY, WEDNESDAY, FRIDAY
from gcsa.event import Event
from datetime import datetime
# Every Monday, Wednesday, and Friday
mwf_workout = Event(
summary="Workout Session",
start=datetime(2024, 1, 15, 7, 0), # Start on a Monday
end=datetime(2024, 1, 15, 8, 0),
recurrence=[
Recurrence.rule(
freq=WEEKLY,
by_weekday=[MONDAY, WEDNESDAY, FRIDAY],
count=36 # 12 weeks × 3 days
)
]
)
gc.add_event(mwf_workout)
# Every Tuesday and Thursday
tt_meetings = Event(
summary="Client Check-in",
start=datetime(2024, 1, 16, 15, 0), # Start on a Tuesday
end=datetime(2024, 1, 16, 15, 30),
recurrence=[
Recurrence.rule(
freq=WEEKLY,
by_weekday=[TU, TH], # Can use short forms
until=datetime(2024, 12, 31)
)
]
)
gc.add_event(tt_meetings)from gcsa.recurrence import Recurrence, MONTHLY, FRIDAY
from gcsa.event import Event
from datetime import datetime
# First Friday of every month
first_friday = Event(
summary="First Friday Drinks",
start=datetime(2024, 2, 2, 17, 0), # First Friday in Feb
end=datetime(2024, 2, 2, 19, 0),
recurrence=[
Recurrence.rule(
freq=MONTHLY,
by_weekday=FRIDAY,
by_set_pos=1 # First occurrence
)
]
)
gc.add_event(first_friday)
# Last day of every month
month_end_report = Event(
summary="Month End Report Due",
start=datetime(2024, 1, 31, 17, 0),
end=datetime(2024, 1, 31, 17, 30),
recurrence=[
Recurrence.rule(
freq=MONTHLY,
by_month_day=-1 # Last day of month
)
]
)
gc.add_event(month_end_report)
# 15th of every month
mid_month_review = Event(
summary="Mid-Month Review",
start=datetime(2024, 1, 15, 10, 0),
end=datetime(2024, 1, 15, 11, 0),
recurrence=[
Recurrence.rule(
freq=MONTHLY,
by_month_day=15,
count=12
)
]
)
gc.add_event(mid_month_review)from gcsa.recurrence import Recurrence, YEARLY
from gcsa.event import Event
from datetime import datetime
# Annual company retreat
annual_retreat = Event(
summary="Annual Company Retreat",
start=datetime(2024, 6, 15, 9, 0),
end=datetime(2024, 6, 16, 17, 0), # 2-day event
recurrence=[
Recurrence.rule(
freq=YEARLY,
by_month=6, # June
by_month_day=15, # 15th
count=5 # Next 5 years
)
]
)
gc.add_event(annual_retreat)
# Birthday recurring event
birthday = Event(
summary="John's Birthday",
start=date(2024, 3, 10),
end=date(2024, 3, 11),
recurrence=[
Recurrence.rule(freq=YEARLY) # Every year forever
]
)
gc.add_event(birthday)from gcsa.recurrence import Recurrence, DAILY, WEEKLY, MONTHLY
from gcsa.event import Event
from datetime import datetime
# Every other day
every_other_day = Event(
summary="Alternate Day Workout",
start=datetime(2024, 1, 15, 6, 0),
end=datetime(2024, 1, 15, 7, 0),
recurrence=[
Recurrence.rule(
freq=DAILY,
interval=2, # Every 2 days
count=50
)
]
)
gc.add_event(every_other_day)
# Every 3 weeks
tri_weekly = Event(
summary="Tri-weekly Sprint Planning",
start=datetime(2024, 1, 15, 9, 0),
end=datetime(2024, 1, 15, 10, 30),
recurrence=[
Recurrence.rule(
freq=WEEKLY,
interval=3, # Every 3 weeks
by_weekday=MONDAY
)
]
)
gc.add_event(tri_weekly)
# Quarterly meetings (every 3 months)
quarterly = Event(
summary="Quarterly Business Review",
start=datetime(2024, 1, 31, 14, 0),
end=datetime(2024, 1, 31, 16, 0),
recurrence=[
Recurrence.rule(
freq=MONTHLY,
interval=3, # Every 3 months
by_month_day=-1 # Last day of quarter-ending month
)
]
)
gc.add_event(quarterly)from gcsa.recurrence import Recurrence, WEEKLY, MONDAY
from gcsa.event import Event
from datetime import datetime, date
# Weekly meeting with holiday exceptions
weekly_with_exceptions = Event(
summary="Weekly Staff Meeting",
start=datetime(2024, 1, 8, 10, 0),
end=datetime(2024, 1, 8, 11, 0),
recurrence=[
# Main rule: every Monday
Recurrence.rule(freq=WEEKLY, by_weekday=MONDAY, count=52),
# Exclude specific dates (holidays)
Recurrence.exclude_dates(
date(2024, 2, 19), # Presidents Day
date(2024, 5, 27), # Memorial Day
date(2024, 7, 4), # Independence Day
date(2024, 9, 2), # Labor Day
date(2024, 11, 28) # Thanksgiving week
)
]
)
gc.add_event(weekly_with_exceptions)from gcsa.recurrence import Recurrence, WEEKLY, FRIDAY
from gcsa.event import Event
from datetime import datetime, date
# Regular weekly meeting plus additional dates
meeting_with_extras = Event(
summary="Team Sync",
start=datetime(2024, 1, 5, 14, 0), # First Friday
end=datetime(2024, 1, 5, 15, 0),
recurrence=[
# Every Friday
Recurrence.rule(freq=WEEKLY, by_weekday=FRIDAY),
# Add extra meeting dates
Recurrence.dates(
date(2024, 2, 14), # Special Valentine's Day meeting
date(2024, 3, 17), # St. Patrick's Day meeting
date(2024, 4, 1) # April Fool's Day meeting
)
]
)
gc.add_event(meeting_with_extras)from gcsa.recurrence import Recurrence, DAILY
from gcsa.event import Event
from datetime import datetime, time
# Multiple daily occurrences
daily_medication = Event(
summary="Medication Reminder",
start=datetime(2024, 1, 15, 8, 0),
end=datetime(2024, 1, 15, 8, 5),
recurrence=[
Recurrence.rule(
freq=DAILY,
by_hour=[8, 14, 20], # 8 AM, 2 PM, 8 PM
count=90 # 30 days × 3 times daily
)
]
)
gc.add_event(daily_medication)
# Hourly reminders during work hours
hourly_standup = Event(
summary="Hourly Check-in",
start=datetime(2024, 1, 15, 9, 0),
end=datetime(2024, 1, 15, 9, 5),
recurrence=[
Recurrence.rule(
freq=HOURLY,
by_weekday=[MO, TU, WE, TH, FR], # Weekdays only
by_hour=list(range(9, 17)), # 9 AM to 4 PM
until=datetime(2024, 12, 31)
)
]
)
gc.add_event(hourly_standup)from gcsa.recurrence import Duration
from gcsa.event import Event
from datetime import datetime
# Event with duration-based recurrence (less common)
duration = Duration(h=2, m=30) # 2 hours 30 minutes
# Note: Duration is mainly used for period-based RDATE entries
workshop_series = Event(
summary="Workshop Series",
start=datetime(2024, 2, 1, 9, 0),
end=datetime(2024, 2, 1, 12, 0),
recurrence=[
# Include specific periods with durations
Recurrence.periods(
(datetime(2024, 2, 1, 9, 0), datetime(2024, 2, 1, 12, 0)),
(datetime(2024, 2, 8, 9, 0), datetime(2024, 2, 8, 12, 0)),
(datetime(2024, 2, 15, 9, 0), datetime(2024, 2, 15, 12, 0))
)
]
)
gc.add_event(workshop_series)from gcsa.recurrence import Recurrence, WEEKLY, MONDAY, FRIDAY
# Specify different week start (Monday instead of Sunday)
weekly_meeting = Event(
summary="Weekly Planning",
start=datetime(2024, 1, 15, 9, 0),
end=datetime(2024, 1, 15, 10, 0),
recurrence=[
Recurrence.rule(
freq=WEEKLY,
by_weekday=FRIDAY,
week_start=MONDAY, # Week starts on Monday
count=26
)
]
)
gc.add_event(weekly_meeting)from gcsa.recurrence import Recurrence, WEEKLY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
# Every business day (Monday through Friday)
daily_briefing = Event(
summary="Daily Team Briefing",
start=datetime(2024, 1, 15, 8, 30),
end=datetime(2024, 1, 15, 8, 45),
recurrence=[
Recurrence.rule(
freq=WEEKLY,
by_weekday=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY],
until=datetime(2024, 12, 31)
)
]
)
gc.add_event(daily_briefing)
# First business day of each month
monthly_report = Event(
summary="Monthly Report Due",
start=datetime(2024, 2, 1, 9, 0), # First business day of Feb
end=datetime(2024, 2, 1, 9, 30),
recurrence=[
Recurrence.rule(
freq=MONTHLY,
by_weekday=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY],
by_set_pos=1 # First weekday occurrence
)
]
)
gc.add_event(monthly_report)from gcsa.recurrence import Recurrence, DAILY, WEEKLY
from gcsa.event import Event
from datetime import datetime
try:
# Invalid recurrence rule (count and until cannot both be specified)
invalid_event = Event(
summary="Invalid Recurrence",
start=datetime(2024, 1, 15, 10, 0),
end=datetime(2024, 1, 15, 11, 0),
recurrence=[
Recurrence.rule(
freq=DAILY,
count=30, # Count specified
until=datetime(2024, 6, 15) # Until also specified - invalid!
)
]
)
gc.add_event(invalid_event)
except Exception as e:
print(f"Recurrence error: {e}")
# Correct approach - use either count or until, not both
valid_event = Event(
summary="Valid Recurrence",
start=datetime(2024, 1, 15, 10, 0),
end=datetime(2024, 1, 15, 11, 0),
recurrence=[
Recurrence.rule(freq=DAILY, count=30) # Only count
]
)
gc.add_event(valid_event)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.
Install with Tessl CLI
npx tessl i tessl/pypi-gcsa