CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-croniter

croniter provides iteration for datetime object with cron like format

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

range-operations.mddocs/

Range Operations

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.

Capabilities

Croniter Range Function

Generate all datetime matches within a specified range using a cron expression.

def croniter_range(
    start,
    stop,
    expr_format: str,
    ret_type=None,
    day_or=True,
    exclude_ends=False,
    _croniter=None,
    second_at_beginning=False,
    expand_from_start_time=False,
):
    """
    Generator that provides all times from start to stop matching the given cron expression.
    
    You can think of this function as sibling to the builtin range function for datetime objects.
    Like range(start,stop,step), except that here 'step' is a cron expression.
    
    Parameters:
    - start: Start datetime (datetime object or timestamp)
    - stop: End datetime (datetime object or timestamp)  
    - expr_format: Cron expression string
    - ret_type: Return type for yielded values (float, datetime, or None for auto-detect)
    - day_or: How to handle day and day_of_week fields (True=OR, False=AND)
    - exclude_ends: If True, exclude start/stop times even if they match (default False)
    - _croniter: Custom croniter class (for testing/customization)
    - second_at_beginning: Put seconds field at beginning instead of end
    - expand_from_start_time: Calculate intervals from start_time instead of calendar
    
    Yields:
    All matching datetimes between start and stop (inclusive by default)
    """

Usage Examples

Basic Range Operations

from croniter import croniter_range
from datetime import datetime

# Find all first Saturdays of each month in 2019
start = datetime(2019, 1, 1)
stop = datetime(2019, 12, 31)

for dt in croniter_range(start, stop, "0 0 * * sat#1"):
    print(dt)
# 2019-01-05 00:00:00
# 2019-02-02 00:00:00  
# 2019-03-02 00:00:00
# ... (continues for each month)

Working with Timestamps

import time
from datetime import datetime

# Use timestamps for input
start_ts = time.mktime(datetime(2019, 1, 1).timetuple())
stop_ts = time.mktime(datetime(2019, 1, 31).timetuple())

# Find all weekdays at 9 AM in January 2019
for dt in croniter_range(start_ts, stop_ts, "0 9 * * 1-5"):
    print(datetime.fromtimestamp(dt))

Excluding Endpoints

from datetime import datetime

start = datetime(2019, 1, 1, 0, 0, 0)  # Exactly midnight
stop = datetime(2019, 1, 2, 0, 0, 0)   # Exactly next midnight

# Without exclude_ends (default): includes both endpoints if they match
daily_matches = list(croniter_range(start, stop, "0 0 * * *"))
print(len(daily_matches))  # 2 (both midnight times)

# With exclude_ends: excludes endpoints even if they match
daily_matches = list(croniter_range(start, stop, "0 0 * * *", exclude_ends=True))
print(len(daily_matches))  # 0 (no matches between the endpoints)

Reverse Time Order

from datetime import datetime

# Croniter_range can work with reverse time order (stop before start)
start = datetime(2019, 1, 31)
stop = datetime(2019, 1, 1)

# This will work and yield dates in reverse chronological order
for dt in croniter_range(start, stop, "0 12 * * *"):  # Noon every day
    print(dt)
# 2019-01-31 12:00:00
# 2019-01-30 12:00:00
# ... (continues backward)
# 2019-01-01 12:00:00

Complex Cron Expressions

from datetime import datetime

start = datetime(2019, 1, 1)
stop = datetime(2019, 12, 31)

# Every weekday at 9:30 AM and 2:30 PM
for dt in croniter_range(start, stop, "30 9,14 * * 1-5"):
    print(dt)

# Last Friday of each month at 5 PM
for dt in croniter_range(start, stop, "0 17 * * L5"):
    print(dt)

# Every 15 minutes during business hours (9 AM - 5 PM) on weekdays
for dt in croniter_range(start, stop, "*/15 9-17 * * 1-5"):
    print(dt)

Return Type Control

from datetime import datetime

start = datetime(2019, 1, 1)
stop = datetime(2019, 1, 7)

# Return as datetime objects
datetime_results = list(croniter_range(start, stop, "0 0 * * *", ret_type=datetime))
print(type(datetime_results[0]))  # <class 'datetime.datetime'>

# Return as timestamps  
timestamp_results = list(croniter_range(start, stop, "0 0 * * *", ret_type=float))
print(type(timestamp_results[0]))  # <class 'float'>

# Auto-detect based on input types (default behavior)
auto_results = list(croniter_range(start, stop, "0 0 * * *"))
print(type(auto_results[0]))  # <class 'datetime.datetime'> (matches input type)

Second-Level Precision

from datetime import datetime

start = datetime(2019, 1, 1, 0, 0, 0)
stop = datetime(2019, 1, 1, 0, 1, 0)  # One minute range

# Every 15 seconds within the minute
for dt in croniter_range(start, stop, "*/15 * * * * *"):  # 6-field format with seconds
    print(dt)
# 2019-01-01 00:00:00
# 2019-01-01 00:00:15
# 2019-01-01 00:00:30
# 2019-01-01 00:00:45
# 2019-01-01 00:01:00

Day/Dayofweek Logic in Ranges

from datetime import datetime

start = datetime(2019, 6, 1)  
stop = datetime(2019, 6, 30)

# OR logic (default): 1st day of month OR any Wednesday
or_results = list(croniter_range(start, stop, "0 0 1 * wed", day_or=True))

# AND logic: 1st day of month IF it's a Wednesday
and_results = list(croniter_range(start, stop, "0 0 1 * wed", day_or=False))

print(f"OR results: {len(or_results)}")   # More matches
print(f"AND results: {len(and_results)}") # Fewer matches (only if 1st is Wednesday)

Performance Considerations

from datetime import datetime

# For very large date ranges or sparse expressions, 
# croniter_range inherits performance limits from croniter class
start = datetime(2000, 1, 1)
stop = datetime(2050, 12, 31)

# Very sparse expression - might hit performance limits
try:
    sparse_matches = list(croniter_range(
        start, stop, 
        "0 4 1 1 fri",  # 4 AM on January 1st if it's Friday
        day_or=False
    ))
    print(f"Found {len(sparse_matches)} matches")
except Exception as e:
    print(f"Performance limit reached: {e}")

Custom Expansion from Start Time

from datetime import datetime

start = datetime(2024, 7, 11)  # Start on July 11th
stop = datetime(2024, 10, 1)

# Default behavior: every 7 days from calendar start (1st, 8th, 15th, etc.)
calendar_matches = list(croniter_range(start, stop, "0 0 */7 * *"))

# Custom expansion: every 7 days from start_time (11th, 18th, 25th, etc.)
custom_matches = list(croniter_range(
    start, stop, 
    "0 0 */7 * *", 
    expand_from_start_time=True
))

print("Calendar-based:", [dt.day for dt in calendar_matches[:5]])
print("Start-time-based:", [dt.day for dt in custom_matches[:5]])

Install with Tessl CLI

npx tessl i tessl/pypi-croniter

docs

advanced-features.md

core-iteration.md

index.md

range-operations.md

validation-matching.md

tile.json