33 lines
1.3 KiB
Python
33 lines
1.3 KiB
Python
"""Shared from/to date-range parsing (Chapter 11: consistent across every
|
|
chart/KPI endpoint; never defaults to "all time" per Chapter 03 rule 7).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import date, datetime, timedelta
|
|
|
|
from flask import Request
|
|
|
|
DEFAULT_RANGE_DAYS = 7 # within Ch11's stated "7 or 30 day" default allowance
|
|
|
|
|
|
def parse_date_range(request: Request) -> tuple[date, date]:
|
|
"""Parse `?from=&to=` (ISO 8601 dates), defaulting to the last 7 days."""
|
|
to_raw = request.args.get("to")
|
|
from_raw = request.args.get("from")
|
|
to_date = date.fromisoformat(to_raw) if to_raw else date.today()
|
|
from_date = date.fromisoformat(from_raw) if from_raw else to_date - timedelta(days=DEFAULT_RANGE_DAYS - 1)
|
|
if from_date > to_date:
|
|
from_date, to_date = to_date, from_date
|
|
return from_date, to_date
|
|
|
|
|
|
def day_bounds(from_date: date, to_date: date) -> tuple[datetime, datetime]:
|
|
"""Inclusive [from_date, to_date] -> half-open [start, end) datetime range.
|
|
|
|
Shared by overview/queries.py, seo/queries.py, and security/queries.py
|
|
(consolidated here rather than each keeping its own local copy).
|
|
"""
|
|
start = datetime.combine(from_date, datetime.min.time())
|
|
end = datetime.combine(to_date, datetime.min.time()) + timedelta(days=1)
|
|
return start, end
|