or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

easter.mdindex.mdparser.mdrelativedelta.mdrrule.mdtz.mdutils.mdzoneinfo.md

rrule.mddocs/

0

# Recurrence Rules

1

2

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

3

4

## Capabilities

5

6

### rrule Class

7

8

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

9

10

```python { .api }

11

class rrule:

12

def __init__(self, freq, dtstart=None, interval=1, wkst=None, count=None,

13

until=None, bysetpos=None, bymonth=None, bymonthday=None,

14

byyearday=None, byweekno=None, byweekday=None, byhour=None,

15

byminute=None, bysecond=None, cache=False):

16

"""

17

Create a recurrence rule.

18

19

Parameters:

20

- freq (int): Frequency constant (YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY)

21

- dtstart (datetime, optional): Start date/time for recurrence

22

- interval (int): Interval between recurrences (default: 1)

23

- wkst (int, optional): Week start day (0=Monday, 6=Sunday)

24

- count (int, optional): Maximum number of occurrences

25

- until (datetime, optional): End date/time for recurrence

26

- bysetpos (int/list, optional): Position in set of occurrences

27

- bymonth (int/list, optional): Months (1-12)

28

- bymonthday (int/list, optional): Days of month (1-31, -31 to -1)

29

- byyearday (int/list, optional): Days of year (1-366, -366 to -1)

30

- byweekno (int/list, optional): Week numbers (1-53, -53 to -1)

31

- byweekday (int/weekday/list, optional): Weekdays

32

- byhour (int/list, optional): Hours (0-23)

33

- byminute (int/list, optional): Minutes (0-59)

34

- bysecond (int/list, optional): Seconds (0-59)

35

- cache (bool): Enable caching for performance

36

"""

37

38

def between(self, after, before, inc=False):

39

"""

40

Generate occurrences between two dates.

41

42

Parameters:

43

- after (datetime): Start date (exclusive)

44

- before (datetime): End date (exclusive)

45

- inc (bool): Include boundary dates if True

46

47

Returns:

48

list[datetime]: List of occurrences in range

49

"""

50

51

def before(self, dt, inc=False):

52

"""

53

Get occurrence before specified date.

54

55

Parameters:

56

- dt (datetime): Reference date

57

- inc (bool): Include dt if it's an occurrence

58

59

Returns:

60

datetime | None: Previous occurrence or None

61

"""

62

63

def after(self, dt, inc=False):

64

"""

65

Get occurrence after specified date.

66

67

Parameters:

68

- dt (datetime): Reference date

69

- inc (bool): Include dt if it's an occurrence

70

71

Returns:

72

datetime | None: Next occurrence or None

73

"""

74

75

def count(self):

76

"""

77

Get total number of occurrences.

78

79

Returns:

80

int: Total count (may be infinite)

81

"""

82

```

83

84

**Usage Examples:**

85

86

```python

87

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

88

from datetime import datetime

89

90

# Daily recurrence for 10 days

91

start = datetime(2023, 1, 1, 9, 0)

92

daily = rrule(DAILY, dtstart=start, count=10)

93

dates = list(daily)

94

95

# Weekly on Mondays and Wednesdays for 8 weeks

96

weekly = rrule(WEEKLY, dtstart=start, count=16, byweekday=(0, 2)) # Monday, Wednesday

97

98

# Monthly on 15th of each month for 1 year

99

monthly = rrule(MONTHLY, dtstart=start, count=12, bymonthday=15)

100

101

# Yearly on specific date until end date

102

until_date = datetime(2030, 12, 31)

103

yearly = rrule(YEARLY, dtstart=start, until=until_date, bymonth=12, bymonthday=25)

104

105

# Complex pattern: Every other Tuesday in January and July

106

complex_rule = rrule(WEEKLY, dtstart=start, interval=2,

107

byweekday=1, bymonth=(1, 7)) # Tuesday = 1

108

```

109

110

### Frequency Constants

111

112

Predefined constants for specifying recurrence frequency.

113

114

```python { .api }

115

YEARLY = 0 # Annual recurrence

116

MONTHLY = 1 # Monthly recurrence

117

WEEKLY = 2 # Weekly recurrence

118

DAILY = 3 # Daily recurrence

119

HOURLY = 4 # Hourly recurrence

120

MINUTELY = 5 # Per-minute recurrence

121

SECONDLY = 6 # Per-second recurrence

122

```

123

124

### Weekday Constants and Class

125

126

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

127

128

```python { .api }

129

# Weekday constants (Monday=0 to Sunday=6)

130

MO = weekday(0)

131

TU = weekday(1)

132

WE = weekday(2)

133

TH = weekday(3)

134

FR = weekday(4)

135

SA = weekday(5)

136

SU = weekday(6)

137

138

class weekday:

139

def __init__(self, wkday, n=None):

140

"""

141

Weekday specification for rrules.

142

143

Parameters:

144

- wkday (int): Weekday number (0=Monday, 6=Sunday)

145

- n (int, optional): Nth occurrence (1 for first, -1 for last, etc.)

146

147

Note: Unlike relativedelta.weekday, n=0 is not allowed

148

149

Raises:

150

ValueError: If n is 0

151

"""

152

```

153

154

**Usage Examples:**

155

156

```python

157

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

158

from datetime import datetime

159

160

start = datetime(2023, 1, 1)

161

162

# Every first Monday of each month

163

first_monday = rrule(MONTHLY, dtstart=start, byweekday=MO(1))

164

165

# Every last Friday of each month

166

last_friday = rrule(MONTHLY, dtstart=start, byweekday=FR(-1))

167

168

# Every second and fourth Tuesday

169

second_fourth_tue = rrule(MONTHLY, dtstart=start, byweekday=(TU(2), TU(4)))

170

171

# All Mondays and Fridays (no nth specification)

172

mon_fri = rrule(WEEKLY, dtstart=start, byweekday=(MO, FR))

173

```

174

175

### rruleset Class

176

177

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

178

179

```python { .api }

180

class rruleset:

181

def __init__(self, cache=False):

182

"""

183

Create a set of recurrence rules.

184

185

Parameters:

186

- cache (bool): Enable caching for performance

187

"""

188

189

def rrule(self, rrule):

190

"""

191

Add an rrule to the set.

192

193

Parameters:

194

- rrule (rrule): Recurrence rule to include

195

"""

196

197

def rdate(self, rdate):

198

"""

199

Add a single date to the set.

200

201

Parameters:

202

- rdate (datetime): Date to include

203

"""

204

205

def exrule(self, exrule):

206

"""

207

Add an exclusion rule to the set.

208

209

Parameters:

210

- exrule (rrule): Recurrence rule for dates to exclude

211

"""

212

213

def exdate(self, exdate):

214

"""

215

Add an exclusion date to the set.

216

217

Parameters:

218

- exdate (datetime): Date to exclude

219

"""

220

221

# Same iteration methods as rrule

222

def between(self, after, before, inc=False): ...

223

def before(self, dt, inc=False): ...

224

def after(self, dt, inc=False): ...

225

def count(self): ...

226

```

227

228

**Usage Examples:**

229

230

```python

231

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

232

from datetime import datetime

233

234

# Create a complex schedule

235

schedule = rruleset()

236

237

# Add daily meetings Monday-Friday

238

start = datetime(2023, 1, 2, 9, 0) # Monday

239

weekdays = rrule(DAILY, dtstart=start, byweekday=(MO, TU, WE, TH, FR))

240

schedule.rrule(weekdays)

241

242

# Add extra meeting on first Friday of each month

243

monthly_meeting = rrule(MONTHLY, dtstart=start, byweekday=FR(1))

244

schedule.rrule(monthly_meeting)

245

246

# Exclude holidays

247

holiday1 = datetime(2023, 7, 4, 9, 0) # July 4th

248

holiday2 = datetime(2023, 12, 25, 9, 0) # Christmas

249

schedule.exdate(holiday1)

250

schedule.exdate(holiday2)

251

252

# Exclude entire holiday week

253

holiday_week = rrule(DAILY, dtstart=datetime(2023, 12, 25, 9, 0), count=5)

254

schedule.exrule(holiday_week)

255

256

# Get all meetings in January 2023

257

jan_meetings = schedule.between(

258

datetime(2023, 1, 1),

259

datetime(2023, 2, 1)

260

)

261

```

262

263

### String Parsing

264

265

Parse recurrence rules from iCalendar-style strings.

266

267

```python { .api }

268

def rrulestr(s, **kwargs):

269

"""

270

Parse rrule from RFC 5545 string format.

271

272

Parameters:

273

- s (str): RRULE string (e.g., "FREQ=DAILY;COUNT=10")

274

- **kwargs: Additional parameters passed to rrule constructor

275

276

Returns:

277

rrule: Parsed recurrence rule

278

279

Raises:

280

ValueError: If string format is invalid

281

"""

282

```

283

284

**Usage Examples:**

285

286

```python

287

from dateutil.rrule import rrulestr

288

from datetime import datetime

289

290

# Parse from iCalendar format

291

rule_str = "FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10"

292

rule = rrulestr(rule_str, dtstart=datetime(2023, 1, 2))

293

294

# More complex pattern

295

complex_str = "FREQ=MONTHLY;BYMONTHDAY=15;BYMONTH=3,6,9,12"

296

quarterly = rrulestr(complex_str, dtstart=datetime(2023, 1, 1))

297

298

# With until date

299

until_str = "FREQ=DAILY;INTERVAL=2;UNTIL=20231231T235959Z"

300

every_other_day = rrulestr(until_str, dtstart=datetime(2023, 1, 1))

301

```

302

303

## Advanced Patterns

304

305

### Caching for Performance

306

307

```python

308

from dateutil.rrule import rrule, DAILY

309

from datetime import datetime

310

311

# Large recurrence with caching

312

start = datetime(2020, 1, 1)

313

large_rule = rrule(DAILY, dtstart=start, count=10000, cache=True)

314

315

# First iteration builds cache

316

dates = list(large_rule) # Slower first time

317

318

# Subsequent operations use cache

319

more_dates = list(large_rule) # Much faster

320

count = large_rule.count() # Instant

321

```

322

323

### Complex Business Rules

324

325

```python

326

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

327

from datetime import datetime

328

329

def create_business_schedule():

330

"""Create complex business meeting schedule."""

331

schedule = rruleset()

332

start = datetime(2023, 1, 1, 14, 0) # 2 PM meetings

333

334

# Weekly team meetings on Tuesdays

335

team_meetings = rrule(WEEKLY, dtstart=start, byweekday=TU)

336

schedule.rrule(team_meetings)

337

338

# Monthly all-hands on first Thursday

339

all_hands = rrule(MONTHLY, dtstart=start, byweekday=TH(1))

340

schedule.rrule(all_hands)

341

342

# Quarterly board meetings on 15th

343

board_meetings = rrule(MONTHLY, dtstart=start, interval=3, bymonthday=15)

344

schedule.rrule(board_meetings)

345

346

# Exclude summer vacation period

347

vacation_start = datetime(2023, 7, 1, 14, 0)

348

vacation_rule = rrule(DAILY, dtstart=vacation_start, count=14)

349

schedule.exrule(vacation_rule)

350

351

return schedule

352

353

schedule = create_business_schedule()

354

meetings_2023 = schedule.between(

355

datetime(2023, 1, 1),

356

datetime(2024, 1, 1)

357

)

358

```

359

360

### Timezone-Aware Recurrences

361

362

```python

363

from dateutil.rrule import rrule, DAILY

364

from dateutil.tz import gettz

365

from datetime import datetime

366

367

# Timezone-aware recurrence

368

eastern = gettz('America/New_York')

369

start = datetime(2023, 1, 1, 9, 0, tzinfo=eastern)

370

371

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

372

373

# All generated dates will be timezone-aware

374

for meeting in daily_meetings:

375

print(f"{meeting} ({meeting.tzinfo})")

376

```

377

378

## Types

379

380

```python { .api }

381

from datetime import datetime

382

383

class rrule:

384

# Iteration protocol

385

def __iter__(self): ...

386

def __getitem__(self, item): ...

387

def __contains__(self, item): ...

388

def __len__(self): ...

389

390

class rruleset:

391

# Same iteration protocol as rrule

392

def __iter__(self): ...

393

def __getitem__(self, item): ...

394

def __contains__(self, item): ...

395

def __len__(self): ...

396

397

class weekday:

398

weekday: int # 0-6 (Monday-Sunday)

399

n: int | None # Nth occurrence (cannot be 0)

400

401

# Frequency constants

402

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

403

404

# Common parameter types

405

DateTimeList = list[datetime] | datetime

406

IntList = list[int] | int

407

WeekdayList = list[weekday | int] | weekday | int

408

```