
- Add enhanced due date filtering to get_todos function with support for "today", "this_week", "next_week" - Add overdue filtering parameter with timezone-aware comparisons - Add sorting by due_date with null values at end - Add get_overdue_todos function for retrieving overdue todos - Add get_todos_due_soon function for todos due within next N days (default 7) - Add get_todos_by_date_range function for custom date range filtering - Create comprehensive date utilities in app/utils/date_utils.py with timezone support - Add project_id and tag_ids support to TodoCreate and TodoUpdate schemas - Include efficient database indexing for due_date queries - Use SQLAlchemy timezone-aware datetime filtering throughout - Add proper overdue detection logic with timezone handling
87 lines
2.9 KiB
Python
87 lines
2.9 KiB
Python
"""Date utility functions for todo management."""
|
|
|
|
from datetime import datetime, timezone, timedelta
|
|
from typing import Tuple, Optional
|
|
|
|
|
|
def get_timezone_aware_now() -> datetime:
|
|
"""Get current time in UTC timezone."""
|
|
return datetime.now(timezone.utc)
|
|
|
|
|
|
def get_date_range_today() -> Tuple[datetime, datetime]:
|
|
"""Get start and end of today in UTC."""
|
|
now = get_timezone_aware_now()
|
|
start_of_day = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
end_of_day = now.replace(hour=23, minute=59, second=59, microsecond=999999)
|
|
return start_of_day, end_of_day
|
|
|
|
|
|
def get_date_range_this_week() -> Tuple[datetime, datetime]:
|
|
"""Get start and end of current week (Monday to Sunday) in UTC."""
|
|
now = get_timezone_aware_now()
|
|
start_of_week = now - timedelta(days=now.weekday())
|
|
start_of_week = start_of_week.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
end_of_week = start_of_week + timedelta(
|
|
days=6, hours=23, minutes=59, seconds=59, microseconds=999999
|
|
)
|
|
return start_of_week, end_of_week
|
|
|
|
|
|
def get_date_range_next_week() -> Tuple[datetime, datetime]:
|
|
"""Get start and end of next week (Monday to Sunday) in UTC."""
|
|
now = get_timezone_aware_now()
|
|
days_until_next_monday = 7 - now.weekday()
|
|
start_of_next_week = now + timedelta(days=days_until_next_monday)
|
|
start_of_next_week = start_of_next_week.replace(
|
|
hour=0, minute=0, second=0, microsecond=0
|
|
)
|
|
end_of_next_week = start_of_next_week + timedelta(
|
|
days=6, hours=23, minutes=59, seconds=59, microseconds=999999
|
|
)
|
|
return start_of_next_week, end_of_next_week
|
|
|
|
|
|
def get_date_range_next_days(days: int) -> Tuple[datetime, datetime]:
|
|
"""Get start and end of next N days in UTC."""
|
|
now = get_timezone_aware_now()
|
|
start_time = now
|
|
end_time = now + timedelta(days=days)
|
|
return start_time, end_time
|
|
|
|
|
|
def get_overdue_cutoff() -> datetime:
|
|
"""Get cutoff datetime for overdue todos (current time)."""
|
|
return get_timezone_aware_now()
|
|
|
|
|
|
def get_due_soon_cutoff(days: int = 7) -> datetime:
|
|
"""Get cutoff datetime for due soon todos (next N days)."""
|
|
return get_timezone_aware_now() + timedelta(days=days)
|
|
|
|
|
|
def is_overdue(due_date: Optional[datetime], completed: bool = False) -> bool:
|
|
"""Check if a todo is overdue."""
|
|
if due_date is None or completed:
|
|
return False
|
|
return get_timezone_aware_now() > due_date
|
|
|
|
|
|
def is_due_today(due_date: Optional[datetime]) -> bool:
|
|
"""Check if a todo is due today."""
|
|
if due_date is None:
|
|
return False
|
|
today_start, today_end = get_date_range_today()
|
|
return today_start <= due_date <= today_end
|
|
|
|
|
|
def is_due_soon(
|
|
due_date: Optional[datetime], days: int = 7, completed: bool = False
|
|
) -> bool:
|
|
"""Check if a todo is due within the next N days."""
|
|
if due_date is None or completed:
|
|
return False
|
|
cutoff = get_due_soon_cutoff(days)
|
|
now = get_timezone_aware_now()
|
|
return now <= due_date <= cutoff
|