CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-dateutil

Extensions to the standard Python datetime module

Pending
Overview
Eval results
Files

utils.mddocs/

Date Utilities

General convenience functions for common date and time operations including current day calculation, timezone defaulting, and date comparison within tolerance.

Capabilities

Today Function

def today(tzinfo=None):
    """
    Return current date at midnight with optional timezone.
    
    Parameters:
    - tzinfo (tzinfo, optional): Timezone to attach and use for current day determination
    
    Returns:
    datetime: Current date at midnight (00:00:00) in specified timezone
    """

Usage Examples:

from dateutil.utils import today
from dateutil.tz import gettz
from datetime import datetime

# Current day at midnight in local timezone
today_local = today()
print(f"Today (local): {today_local}")

# Current day at midnight in specific timezone
utc_tz = gettz('UTC')
today_utc = today(utc_tz)
print(f"Today (UTC): {today_utc}")

# Compare with datetime.now()
now = datetime.now(utc_tz)
today_utc_alt = today(utc_tz)
print(f"Now: {now}")
print(f"Today: {today_utc_alt}")  # Same date, but time is 00:00:00

Timezone Defaulting

def default_tzinfo(dt, tzinfo):
    """
    Set timezone on naive datetimes only, leaving aware datetimes unchanged.
    
    Useful when dealing with datetimes that may have implicit or explicit timezones,
    such as when parsing timezone strings or working with mixed timezone data.
    
    Parameters:
    - dt (datetime): Datetime object to potentially modify
    - tzinfo (tzinfo): Timezone to assign if dt is naive
    
    Returns:
    datetime: Aware datetime (either original if already aware, or with tzinfo applied)
    """

Usage Examples:

from dateutil.utils import default_tzinfo
from dateutil.tz import gettz
from dateutil.parser import parse
from datetime import datetime

eastern_tz = gettz('America/New_York')

# Apply timezone to naive datetime
naive_dt = datetime(2023, 12, 25, 14, 30)
aware_dt = default_tzinfo(naive_dt, eastern_tz)
print(f"Naive -> Aware: {aware_dt}")

# Aware datetime remains unchanged
already_aware = datetime(2023, 12, 25, 14, 30, tzinfo=gettz('UTC'))
still_aware = default_tzinfo(already_aware, eastern_tz)
print(f"Still UTC: {still_aware}")  # Keeps original UTC timezone

# Practical example with parsing
def parse_with_default_tz(date_str, default_tz):
    """Parse date string and apply default timezone if none specified."""
    parsed_dt = parse(date_str)
    return default_tzinfo(parsed_dt, default_tz)

# Apply default timezone only when needed
dt1 = parse_with_default_tz("2023-12-25 14:30", eastern_tz)      # Gets Eastern
dt2 = parse_with_default_tz("2023-12-25 14:30 UTC", eastern_tz)  # Stays UTC

Date Comparison with Tolerance

def within_delta(dt1, dt2, delta):
    """
    Check if two datetimes are within a specified tolerance of each other.
    
    Useful for comparing datetimes that may have negligible differences
    due to precision, network delays, or processing time.
    
    Parameters:
    - dt1 (datetime): First datetime
    - dt2 (datetime): Second datetime  
    - delta (timedelta): Maximum allowed difference (tolerance)
    
    Returns:
    bool: True if absolute difference between dt1 and dt2 is <= delta
    """

Usage Examples:

from dateutil.utils import within_delta
from datetime import datetime, timedelta

# Basic tolerance checking
dt1 = datetime(2023, 12, 25, 14, 30, 0, 0)      # Exactly 14:30:00.000
dt2 = datetime(2023, 12, 25, 14, 30, 0, 500000) # 14:30:00.500 (500ms later)

tolerance = timedelta(seconds=1)
are_close = within_delta(dt1, dt2, tolerance)
print(f"Within 1 second: {are_close}")  # True

# More strict tolerance
strict_tolerance = timedelta(milliseconds=100)
are_very_close = within_delta(dt1, dt2, strict_tolerance)
print(f"Within 100ms: {are_very_close}")  # False

# Practical application: Event synchronization
def events_are_simultaneous(event1_time, event2_time, tolerance_seconds=5):
    """Check if two events occurred within tolerance of each other."""
    tolerance = timedelta(seconds=tolerance_seconds)
    return within_delta(event1_time, event2_time, tolerance)

# Example usage
event_a = datetime(2023, 12, 25, 14, 30, 15)
event_b = datetime(2023, 12, 25, 14, 30, 18)

simultaneous = events_are_simultaneous(event_a, event_b)
print(f"Events are simultaneous: {simultaneous}")  # True (within 5 seconds)

Advanced Usage Patterns

Timezone-Aware Today Calculation

from dateutil.utils import today
from dateutil.tz import gettz
from datetime import datetime

def business_day_start(timezone_name):
    """Get start of business day in specified timezone."""
    tz = gettz(timezone_name)
    return today(tz).replace(hour=9)  # 9 AM start

def is_same_business_day(dt1, dt2, timezone_name):
    """Check if two datetimes fall on same business day."""
    tz = gettz(timezone_name)
    
    # Convert both to same timezone and compare dates
    dt1_local = dt1.astimezone(tz) if dt1.tzinfo else dt1.replace(tzinfo=tz)
    dt2_local = dt2.astimezone(tz) if dt2.tzinfo else dt2.replace(tzinfo=tz)
    
    return dt1_local.date() == dt2_local.date()

# Example usage
ny_start = business_day_start('America/New_York')
london_start = business_day_start('Europe/London')
print(f"NY business day starts: {ny_start}")
print(f"London business day starts: {london_start}")

Robust DateTime Processing Pipeline

from dateutil.utils import default_tzinfo, within_delta
from dateutil.tz import gettz
from dateutil.parser import parse
from datetime import datetime, timedelta

class DateTimeProcessor:
    """Robust datetime processing with defaults and validation."""
    
    def __init__(self, default_timezone='UTC', tolerance_seconds=1):
        self.default_tz = gettz(default_timezone)
        self.tolerance = timedelta(seconds=tolerance_seconds)
    
    def normalize_datetime(self, dt_input):
        """Convert various datetime inputs to standardized format."""
        if isinstance(dt_input, str):
            dt = parse(dt_input)
        else:
            dt = dt_input
            
        # Apply default timezone if naive
        return default_tzinfo(dt, self.default_tz)
    
    def are_equivalent(self, dt1, dt2):
        """Check if two datetime inputs represent equivalent times."""
        norm_dt1 = self.normalize_datetime(dt1)
        norm_dt2 = self.normalize_datetime(dt2)
        
        return within_delta(norm_dt1, norm_dt2, self.tolerance)

# Usage example
processor = DateTimeProcessor('America/New_York', tolerance_seconds=5)

# Various input formats
inputs = [
    "2023-12-25 14:30:00",
    datetime(2023, 12, 25, 19, 30, 3, tzinfo=gettz('UTC')),  # Same time in UTC
    "Dec 25, 2023 2:30:02 PM EST"
]

# Normalize all inputs
normalized = [processor.normalize_datetime(inp) for inp in inputs]
for i, norm_dt in enumerate(normalized):
    print(f"Input {i+1}: {norm_dt}")

# Check equivalence
print(f"All equivalent: {all(processor.are_equivalent(normalized[0], dt) for dt in normalized[1:])}")

Data Quality Validation

from dateutil.utils import within_delta
from datetime import datetime, timedelta

def validate_timestamp_sequence(timestamps, max_gap_minutes=60):
    """
    Validate that timestamps form a reasonable sequence.
    
    Parameters:
    - timestamps: List of datetime objects
    - max_gap_minutes: Maximum allowed gap between consecutive timestamps
    
    Returns:
    dict: Validation results with issues found
    """
    issues = {
        'out_of_order': [],
        'large_gaps': [],
        'duplicates': []
    }
    
    max_gap = timedelta(minutes=max_gap_minutes)
    duplicate_tolerance = timedelta(seconds=1)
    
    for i in range(len(timestamps) - 1):
        current = timestamps[i]
        next_ts = timestamps[i + 1]
        
        # Check ordering
        if current > next_ts:
            issues['out_of_order'].append((i, i+1))
        
        # Check for large gaps
        gap = next_ts - current
        if gap > max_gap:
            issues['large_gaps'].append((i, i+1, gap))
        
        # Check for duplicates (within tolerance)
        if within_delta(current, next_ts, duplicate_tolerance):
            issues['duplicates'].append((i, i+1))
    
    return issues

# Example usage
test_timestamps = [
    datetime(2023, 12, 25, 10, 0),
    datetime(2023, 12, 25, 10, 15),
    datetime(2023, 12, 25, 10, 15, 1),  # Near duplicate
    datetime(2023, 12, 25, 12, 0),      # Large gap
    datetime(2023, 12, 25, 11, 30),     # Out of order
]

validation_results = validate_timestamp_sequence(test_timestamps)
print("Validation results:", validation_results)

Types

from datetime import datetime, timedelta, tzinfo

# Function signatures
def today(tzinfo: tzinfo | None = None) -> datetime: ...
def default_tzinfo(dt: datetime, tzinfo: tzinfo) -> datetime: ...
def within_delta(dt1: datetime, dt2: datetime, delta: timedelta) -> bool: ...

# Parameter types
DateTimeInput = datetime | str  # For functions that accept multiple datetime formats
TimezoneInput = tzinfo | str | None  # Timezone specifications
ToleranceInput = timedelta  # Time tolerance specifications

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