0
# Range Operations
1
2
Range-based iteration functionality similar to Python's built-in `range()` function, but for datetime objects using cron expressions as the "step" parameter. This allows you to find all datetime matches within a specific time range.
3
4
## Capabilities
5
6
### Croniter Range Function
7
8
Generate all datetime matches within a specified range using a cron expression.
9
10
```python { .api }
11
def croniter_range(
12
start,
13
stop,
14
expr_format: str,
15
ret_type=None,
16
day_or=True,
17
exclude_ends=False,
18
_croniter=None,
19
second_at_beginning=False,
20
expand_from_start_time=False,
21
):
22
"""
23
Generator that provides all times from start to stop matching the given cron expression.
24
25
You can think of this function as sibling to the builtin range function for datetime objects.
26
Like range(start,stop,step), except that here 'step' is a cron expression.
27
28
Parameters:
29
- start: Start datetime (datetime object or timestamp)
30
- stop: End datetime (datetime object or timestamp)
31
- expr_format: Cron expression string
32
- ret_type: Return type for yielded values (float, datetime, or None for auto-detect)
33
- day_or: How to handle day and day_of_week fields (True=OR, False=AND)
34
- exclude_ends: If True, exclude start/stop times even if they match (default False)
35
- _croniter: Custom croniter class (for testing/customization)
36
- second_at_beginning: Put seconds field at beginning instead of end
37
- expand_from_start_time: Calculate intervals from start_time instead of calendar
38
39
Yields:
40
All matching datetimes between start and stop (inclusive by default)
41
"""
42
```
43
44
## Usage Examples
45
46
### Basic Range Operations
47
48
```python
49
from croniter import croniter_range
50
from datetime import datetime
51
52
# Find all first Saturdays of each month in 2019
53
start = datetime(2019, 1, 1)
54
stop = datetime(2019, 12, 31)
55
56
for dt in croniter_range(start, stop, "0 0 * * sat#1"):
57
print(dt)
58
# 2019-01-05 00:00:00
59
# 2019-02-02 00:00:00
60
# 2019-03-02 00:00:00
61
# ... (continues for each month)
62
```
63
64
### Working with Timestamps
65
66
```python
67
import time
68
from datetime import datetime
69
70
# Use timestamps for input
71
start_ts = time.mktime(datetime(2019, 1, 1).timetuple())
72
stop_ts = time.mktime(datetime(2019, 1, 31).timetuple())
73
74
# Find all weekdays at 9 AM in January 2019
75
for dt in croniter_range(start_ts, stop_ts, "0 9 * * 1-5"):
76
print(datetime.fromtimestamp(dt))
77
```
78
79
### Excluding Endpoints
80
81
```python
82
from datetime import datetime
83
84
start = datetime(2019, 1, 1, 0, 0, 0) # Exactly midnight
85
stop = datetime(2019, 1, 2, 0, 0, 0) # Exactly next midnight
86
87
# Without exclude_ends (default): includes both endpoints if they match
88
daily_matches = list(croniter_range(start, stop, "0 0 * * *"))
89
print(len(daily_matches)) # 2 (both midnight times)
90
91
# With exclude_ends: excludes endpoints even if they match
92
daily_matches = list(croniter_range(start, stop, "0 0 * * *", exclude_ends=True))
93
print(len(daily_matches)) # 0 (no matches between the endpoints)
94
```
95
96
### Reverse Time Order
97
98
```python
99
from datetime import datetime
100
101
# Croniter_range can work with reverse time order (stop before start)
102
start = datetime(2019, 1, 31)
103
stop = datetime(2019, 1, 1)
104
105
# This will work and yield dates in reverse chronological order
106
for dt in croniter_range(start, stop, "0 12 * * *"): # Noon every day
107
print(dt)
108
# 2019-01-31 12:00:00
109
# 2019-01-30 12:00:00
110
# ... (continues backward)
111
# 2019-01-01 12:00:00
112
```
113
114
### Complex Cron Expressions
115
116
```python
117
from datetime import datetime
118
119
start = datetime(2019, 1, 1)
120
stop = datetime(2019, 12, 31)
121
122
# Every weekday at 9:30 AM and 2:30 PM
123
for dt in croniter_range(start, stop, "30 9,14 * * 1-5"):
124
print(dt)
125
126
# Last Friday of each month at 5 PM
127
for dt in croniter_range(start, stop, "0 17 * * L5"):
128
print(dt)
129
130
# Every 15 minutes during business hours (9 AM - 5 PM) on weekdays
131
for dt in croniter_range(start, stop, "*/15 9-17 * * 1-5"):
132
print(dt)
133
```
134
135
### Return Type Control
136
137
```python
138
from datetime import datetime
139
140
start = datetime(2019, 1, 1)
141
stop = datetime(2019, 1, 7)
142
143
# Return as datetime objects
144
datetime_results = list(croniter_range(start, stop, "0 0 * * *", ret_type=datetime))
145
print(type(datetime_results[0])) # <class 'datetime.datetime'>
146
147
# Return as timestamps
148
timestamp_results = list(croniter_range(start, stop, "0 0 * * *", ret_type=float))
149
print(type(timestamp_results[0])) # <class 'float'>
150
151
# Auto-detect based on input types (default behavior)
152
auto_results = list(croniter_range(start, stop, "0 0 * * *"))
153
print(type(auto_results[0])) # <class 'datetime.datetime'> (matches input type)
154
```
155
156
### Second-Level Precision
157
158
```python
159
from datetime import datetime
160
161
start = datetime(2019, 1, 1, 0, 0, 0)
162
stop = datetime(2019, 1, 1, 0, 1, 0) # One minute range
163
164
# Every 15 seconds within the minute
165
for dt in croniter_range(start, stop, "*/15 * * * * *"): # 6-field format with seconds
166
print(dt)
167
# 2019-01-01 00:00:00
168
# 2019-01-01 00:00:15
169
# 2019-01-01 00:00:30
170
# 2019-01-01 00:00:45
171
# 2019-01-01 00:01:00
172
```
173
174
### Day/Dayofweek Logic in Ranges
175
176
```python
177
from datetime import datetime
178
179
start = datetime(2019, 6, 1)
180
stop = datetime(2019, 6, 30)
181
182
# OR logic (default): 1st day of month OR any Wednesday
183
or_results = list(croniter_range(start, stop, "0 0 1 * wed", day_or=True))
184
185
# AND logic: 1st day of month IF it's a Wednesday
186
and_results = list(croniter_range(start, stop, "0 0 1 * wed", day_or=False))
187
188
print(f"OR results: {len(or_results)}") # More matches
189
print(f"AND results: {len(and_results)}") # Fewer matches (only if 1st is Wednesday)
190
```
191
192
### Performance Considerations
193
194
```python
195
from datetime import datetime
196
197
# For very large date ranges or sparse expressions,
198
# croniter_range inherits performance limits from croniter class
199
start = datetime(2000, 1, 1)
200
stop = datetime(2050, 12, 31)
201
202
# Very sparse expression - might hit performance limits
203
try:
204
sparse_matches = list(croniter_range(
205
start, stop,
206
"0 4 1 1 fri", # 4 AM on January 1st if it's Friday
207
day_or=False
208
))
209
print(f"Found {len(sparse_matches)} matches")
210
except Exception as e:
211
print(f"Performance limit reached: {e}")
212
```
213
214
### Custom Expansion from Start Time
215
216
```python
217
from datetime import datetime
218
219
start = datetime(2024, 7, 11) # Start on July 11th
220
stop = datetime(2024, 10, 1)
221
222
# Default behavior: every 7 days from calendar start (1st, 8th, 15th, etc.)
223
calendar_matches = list(croniter_range(start, stop, "0 0 */7 * *"))
224
225
# Custom expansion: every 7 days from start_time (11th, 18th, 25th, etc.)
226
custom_matches = list(croniter_range(
227
start, stop,
228
"0 0 */7 * *",
229
expand_from_start_time=True
230
))
231
232
print("Calendar-based:", [dt.day for dt in calendar_matches[:5]])
233
print("Start-time-based:", [dt.day for dt in custom_matches[:5]])
234
```