🛡️ Error Handling

Eones defines a robust system of specific exceptions for different types of errors, all inheriting from a common base class EonesError.

Exception Hierarchy

from eones.errors import (
    EonesError,                    # Base exception
    InvalidTimezoneError,          # Invalid timezone
    InvalidDateFormatError,        # Invalid date format
    InvalidDurationFormatError     # Invalid duration format
)

EonesError - Base Exception

All custom Eones exceptions inherit from this base class:

class EonesError(Exception):
    pass

This allows catching any Eones-specific error:

try:
    date = Eones("invalid-date", tz="Nonexistent/Zone")
except EonesError as e:
    print(f"Eones error: {e}")

InvalidTimezoneError

Raised when an unrecognized timezone is provided:

try:
    date = Eones("2024-01-01", tz="Nonexistent/Zone")
except InvalidTimezoneError as e:
    print(f"Invalid timezone: {e}")
    # Use default timezone
    date = Eones("2024-01-01")  # UTC by default

InvalidDateFormatError

Raised when the date string cannot be parsed correctly:

try:
    date = Eones("completely-invalid-date")
except InvalidDateFormatError as e:
    print(f"Invalid date format: {e}")
    # Try with specific format
    date = Eones("2024-01-01", formats=["%Y-%m-%d"])

InvalidDurationFormatError

Raised when an ISO 8601 duration string is invalid:

from eones.delta import Delta

try:
    delta = Delta.from_iso("P1Y2M3D4H5M6S-INVALID")
except InvalidDurationFormatError as e:
    print(f"Invalid ISO duration format: {e}")
    # Create delta manually
    delta = Delta(years=1, months=2, days=3, hours=4, minutes=5, seconds=6)

Robust Error Handling

Safe Creation Function

def create_safe_date(date_str, tz_str=None):
    """Creates a date safely with error handling."""
    try:
        return Eones(date_str, tz=tz_str)
    except InvalidDateFormatError:
        print(f"Invalid date format: {date_str}")
        return None
    except InvalidTimezoneError:
        print(f"Invalid timezone: {tz_str}, using UTC")
        return Eones(date_str)  # UTC by default
    except EonesError as e:
        print(f"General Eones error: {e}")
        return None

# Usage
date = create_safe_date("2024-12-25", "Europe/Madrid")
if date:
    print(f"Date created: {date.format('%Y-%m-%d %Z')}")

Multiple Format Handling

def parse_flexible_date(date_str):
    """Attempts to parse a date with multiple strategies."""
    formats = [
        "%Y-%m-%d",
        "%d/%m/%Y",
        "%d-%m-%Y",
        "%Y-%m-%d %H:%M:%S"
    ]
    
    for format_str in formats:
        try:
            return Eones(date_str, formats=[format_str])
        except InvalidDateFormatError:
            continue
    
    # If no format works
    raise InvalidDateFormatError(f"Could not parse date: {date_str}")

# Usage
try:
    date = parse_flexible_date("25/12/2024")
    print(f"Parsed date: {date.format('%Y-%m-%d')}")
except InvalidDateFormatError as e:
    print(f"Error: {e}")

User Input Validation

def validate_user_input(date_input, tz_input=None):
    """Validates and processes user input with detailed feedback."""
    errors = []
    
    # Validate date
    date = None
    try:
        date = Eones(date_input, tz=tz_input)
    except InvalidDateFormatError:
        errors.append(f"Invalid date format: '{date_input}'")
        errors.append("Valid formats: YYYY-MM-DD, DD/MM/YYYY, DD-MM-YYYY")
    except InvalidTimezoneError:
        errors.append(f"Invalid timezone: '{tz_input}'")
        errors.append("Valid timezone example: 'Europe/Madrid', 'America/New_York'")
        # Try without timezone
        try:
            date = Eones(date_input)
            errors.append("Using UTC as default timezone")
        except InvalidDateFormatError:
            errors.append("Could not parse date without timezone either")
    except EonesError as e:
        errors.append(f"Unexpected error: {e}")
    
    return date, errors

# Usage
date, errors = validate_user_input("25/12/2024", "Europe/Madrid")
if errors:
    for error in errors:
        print(f"⚠️  {error}")
if date:
    print(f"✅ Valid date: {date.format('%Y-%m-%d %Z')}")

Error Logging

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def process_date_with_logging(date_str, tz_str=None):
    """Processes date with detailed error logging."""
    try:
        date = Eones(date_str, tz=tz_str)
        logger.info(f"Date processed successfully: {date.format('%Y-%m-%d %Z')}")
        return date
    except InvalidDateFormatError as e:
        logger.error(f"Date format error: {e}")
        logger.info(f"Input received: '{date_str}'")
        raise
    except InvalidTimezoneError as e:
        logger.warning(f"Invalid timezone: {e}")
        logger.info(f"Retrying with UTC...")
        return Eones(date_str)  # Fallback to UTC
    except EonesError as e:
        logger.error(f"Unexpected Eones error: {e}")
        raise

Exception Usage Contexts

These exceptions are used internally in:

  • parser.py: When parsing invalid dates or durations

  • Date and Delta: When initializing objects with incorrect data

  • interface.py: When validating user inputs

  • Conversion methods: When converting between formats

Best Practices

  1. Always catch specific exceptions before the base exception

  2. Provide helpful error messages to the user

  3. Implement sensible fallbacks when possible

  4. Log errors for debugging and monitoring

  5. Validate inputs before processing when critical