CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-dateutil

Extensions to the standard Python datetime module

Pending
Overview
Eval results
Files

rrule.mddocs/

Recurrence Rules

Complete implementation of iCalendar recurrence rules (RFC 5545) for generating recurring dates. Supports complex patterns, exclusions, caching, and efficient iteration over large date ranges.

Capabilities

rrule Class

Core recurrence rule implementation supporting all iCalendar recurrence patterns with optional caching for performance.

class rrule:
    def __init__(self, freq, dtstart=None, interval=1, wkst=None, count=None,
                 until=None, bysetpos=None, bymonth=None, bymonthday=None,
                 byyearday=None, byweekno=None, byweekday=None, byhour=None,
                 byminute=None, bysecond=None, cache=False):
        """
        Create a recurrence rule.
        
        Parameters:
        - freq (int): Frequency constant (YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY)
        - dtstart (datetime, optional): Start date/time for recurrence
        - interval (int): Interval between recurrences (default: 1)
        - wkst (int, optional): Week start day (0=Monday, 6=Sunday)
        - count (int, optional): Maximum number of occurrences
        - until (datetime, optional): End date/time for recurrence
        - bysetpos (int/list, optional): Position in set of occurrences
        - bymonth (int/list, optional): Months (1-12)
        - bymonthday (int/list, optional): Days of month (1-31, -31 to -1)
        - byyearday (int/list, optional): Days of year (1-366, -366 to -1)
        - byweekno (int/list, optional): Week numbers (1-53, -53 to -1)
        - byweekday (int/weekday/list, optional): Weekdays
        - byhour (int/list, optional): Hours (0-23)
        - byminute (int/list, optional): Minutes (0-59)
        - bysecond (int/list, optional): Seconds (0-59)
        - cache (bool): Enable caching for performance
        """
        
    def between(self, after, before, inc=False):
        """
        Generate occurrences between two dates.
        
        Parameters:
        - after (datetime): Start date (exclusive)
        - before (datetime): End date (exclusive) 
        - inc (bool): Include boundary dates if True
        
        Returns:
        list[datetime]: List of occurrences in range
        """
        
    def before(self, dt, inc=False):
        """
        Get occurrence before specified date.
        
        Parameters:
        - dt (datetime): Reference date
        - inc (bool): Include dt if it's an occurrence
        
        Returns:
        datetime | None: Previous occurrence or None
        """
        
    def after(self, dt, inc=False):
        """
        Get occurrence after specified date.
        
        Parameters:
        - dt (datetime): Reference date  
        - inc (bool): Include dt if it's an occurrence
        
        Returns:
        datetime | None: Next occurrence or None
        """
        
    def count(self):
        """
        Get total number of occurrences.
        
        Returns:
        int: Total count (may be infinite)
        """

Usage Examples:

from dateutil.rrule import rrule, DAILY, WEEKLY, MONTHLY, YEARLY
from datetime import datetime

# Daily recurrence for 10 days
start = datetime(2023, 1, 1, 9, 0)
daily = rrule(DAILY, dtstart=start, count=10)
dates = list(daily)

# Weekly on Mondays and Wednesdays for 8 weeks
weekly = rrule(WEEKLY, dtstart=start, count=16, byweekday=(0, 2))  # Monday, Wednesday

# Monthly on 15th of each month for 1 year
monthly = rrule(MONTHLY, dtstart=start, count=12, bymonthday=15)

# Yearly on specific date until end date
until_date = datetime(2030, 12, 31)
yearly = rrule(YEARLY, dtstart=start, until=until_date, bymonth=12, bymonthday=25)

# Complex pattern: Every other Tuesday in January and July
complex_rule = rrule(WEEKLY, dtstart=start, interval=2, 
                    byweekday=1, bymonth=(1, 7))  # Tuesday = 1

Frequency Constants

Predefined constants for specifying recurrence frequency.

YEARLY = 0      # Annual recurrence
MONTHLY = 1     # Monthly recurrence  
WEEKLY = 2      # Weekly recurrence
DAILY = 3       # Daily recurrence
HOURLY = 4      # Hourly recurrence
MINUTELY = 5    # Per-minute recurrence
SECONDLY = 6    # Per-second recurrence

Weekday Constants and Class

Weekday specifications for use in recurrence rules, supporting nth occurrence patterns.

# Weekday constants (Monday=0 to Sunday=6)
MO = weekday(0)
TU = weekday(1) 
WE = weekday(2)
TH = weekday(3)
FR = weekday(4)
SA = weekday(5)
SU = weekday(6)

class weekday:
    def __init__(self, wkday, n=None):
        """
        Weekday specification for rrules.
        
        Parameters:
        - wkday (int): Weekday number (0=Monday, 6=Sunday)
        - n (int, optional): Nth occurrence (1 for first, -1 for last, etc.)
        
        Note: Unlike relativedelta.weekday, n=0 is not allowed
        
        Raises:
        ValueError: If n is 0
        """

Usage Examples:

from dateutil.rrule import rrule, MONTHLY, MO, FR
from datetime import datetime

start = datetime(2023, 1, 1)

# Every first Monday of each month
first_monday = rrule(MONTHLY, dtstart=start, byweekday=MO(1))

# Every last Friday of each month  
last_friday = rrule(MONTHLY, dtstart=start, byweekday=FR(-1))

# Every second and fourth Tuesday
second_fourth_tue = rrule(MONTHLY, dtstart=start, byweekday=(TU(2), TU(4)))

# All Mondays and Fridays (no nth specification)
mon_fri = rrule(WEEKLY, dtstart=start, byweekday=(MO, FR))

rruleset Class

Collection class for combining multiple rrules with inclusion and exclusion rules.

class rruleset:
    def __init__(self, cache=False):
        """
        Create a set of recurrence rules.
        
        Parameters:
        - cache (bool): Enable caching for performance
        """
        
    def rrule(self, rrule):
        """
        Add an rrule to the set.
        
        Parameters:
        - rrule (rrule): Recurrence rule to include
        """
        
    def rdate(self, rdate):
        """
        Add a single date to the set.
        
        Parameters:
        - rdate (datetime): Date to include
        """
        
    def exrule(self, exrule):
        """
        Add an exclusion rule to the set.
        
        Parameters:
        - exrule (rrule): Recurrence rule for dates to exclude
        """
        
    def exdate(self, exdate):
        """
        Add an exclusion date to the set.
        
        Parameters:
        - exdate (datetime): Date to exclude
        """
        
    # Same iteration methods as rrule
    def between(self, after, before, inc=False): ...
    def before(self, dt, inc=False): ...
    def after(self, dt, inc=False): ...
    def count(self): ...

Usage Examples:

from dateutil.rrule import rrule, rruleset, DAILY, WEEKLY, MO, FR
from datetime import datetime

# Create a complex schedule
schedule = rruleset()

# Add daily meetings Monday-Friday
start = datetime(2023, 1, 2, 9, 0)  # Monday
weekdays = rrule(DAILY, dtstart=start, byweekday=(MO, TU, WE, TH, FR))
schedule.rrule(weekdays)

# Add extra meeting on first Friday of each month
monthly_meeting = rrule(MONTHLY, dtstart=start, byweekday=FR(1))
schedule.rrule(monthly_meeting)

# Exclude holidays
holiday1 = datetime(2023, 7, 4, 9, 0)  # July 4th
holiday2 = datetime(2023, 12, 25, 9, 0)  # Christmas
schedule.exdate(holiday1)
schedule.exdate(holiday2)

# Exclude entire holiday week
holiday_week = rrule(DAILY, dtstart=datetime(2023, 12, 25, 9, 0), count=5)
schedule.exrule(holiday_week)

# Get all meetings in January 2023
jan_meetings = schedule.between(
    datetime(2023, 1, 1),
    datetime(2023, 2, 1)
)

String Parsing

Parse recurrence rules from iCalendar-style strings.

def rrulestr(s, **kwargs):
    """
    Parse rrule from RFC 5545 string format.
    
    Parameters:
    - s (str): RRULE string (e.g., "FREQ=DAILY;COUNT=10")
    - **kwargs: Additional parameters passed to rrule constructor
    
    Returns:
    rrule: Parsed recurrence rule
    
    Raises:
    ValueError: If string format is invalid
    """

Usage Examples:

from dateutil.rrule import rrulestr
from datetime import datetime

# Parse from iCalendar format
rule_str = "FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10"
rule = rrulestr(rule_str, dtstart=datetime(2023, 1, 2))

# More complex pattern
complex_str = "FREQ=MONTHLY;BYMONTHDAY=15;BYMONTH=3,6,9,12"
quarterly = rrulestr(complex_str, dtstart=datetime(2023, 1, 1))

# With until date
until_str = "FREQ=DAILY;INTERVAL=2;UNTIL=20231231T235959Z"
every_other_day = rrulestr(until_str, dtstart=datetime(2023, 1, 1))

Advanced Patterns

Caching for Performance

from dateutil.rrule import rrule, DAILY
from datetime import datetime

# Large recurrence with caching
start = datetime(2020, 1, 1)
large_rule = rrule(DAILY, dtstart=start, count=10000, cache=True)

# First iteration builds cache
dates = list(large_rule)  # Slower first time

# Subsequent operations use cache
more_dates = list(large_rule)  # Much faster
count = large_rule.count()    # Instant

Complex Business Rules

from dateutil.rrule import rrule, rruleset, MONTHLY, WEEKLY, MO, TU, WE, TH, FR
from datetime import datetime

def create_business_schedule():
    """Create complex business meeting schedule."""
    schedule = rruleset()
    start = datetime(2023, 1, 1, 14, 0)  # 2 PM meetings
    
    # Weekly team meetings on Tuesdays
    team_meetings = rrule(WEEKLY, dtstart=start, byweekday=TU)
    schedule.rrule(team_meetings)
    
    # Monthly all-hands on first Thursday
    all_hands = rrule(MONTHLY, dtstart=start, byweekday=TH(1))
    schedule.rrule(all_hands)
    
    # Quarterly board meetings on 15th
    board_meetings = rrule(MONTHLY, dtstart=start, interval=3, bymonthday=15)
    schedule.rrule(board_meetings)
    
    # Exclude summer vacation period
    vacation_start = datetime(2023, 7, 1, 14, 0)
    vacation_rule = rrule(DAILY, dtstart=vacation_start, count=14)
    schedule.exrule(vacation_rule)
    
    return schedule

schedule = create_business_schedule()
meetings_2023 = schedule.between(
    datetime(2023, 1, 1),
    datetime(2024, 1, 1)
)

Timezone-Aware Recurrences

from dateutil.rrule import rrule, DAILY
from dateutil.tz import gettz
from datetime import datetime

# Timezone-aware recurrence
eastern = gettz('America/New_York')
start = datetime(2023, 1, 1, 9, 0, tzinfo=eastern)

daily_meetings = rrule(DAILY, dtstart=start, count=30, byweekday=(MO, TU, WE, TH, FR))

# All generated dates will be timezone-aware
for meeting in daily_meetings:
    print(f"{meeting} ({meeting.tzinfo})")

Types

from datetime import datetime

class rrule:
    # Iteration protocol
    def __iter__(self): ...
    def __getitem__(self, item): ...
    def __contains__(self, item): ...
    def __len__(self): ...

class rruleset:
    # Same iteration protocol as rrule
    def __iter__(self): ...
    def __getitem__(self, item): ...
    def __contains__(self, item): ...
    def __len__(self): ...

class weekday:
    weekday: int      # 0-6 (Monday-Sunday)
    n: int | None     # Nth occurrence (cannot be 0)

# Frequency constants
FrequencyType = int  # One of YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY

# Common parameter types
DateTimeList = list[datetime] | datetime
IntList = list[int] | int
WeekdayList = list[weekday | int] | weekday | int

Install with Tessl CLI

npx tessl i tessl/pypi-python-dateutil

docs

easter.md

index.md

parser.md

relativedelta.md

rrule.md

tz.md

utils.md

zoneinfo.md

tile.json