Files
ewoooc/services/analysis_period_service.py
ogt 5f3e88c9ca
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
fix(analytics): link report data to selected period
2026-07-15 15:54:35 +08:00

90 lines
2.7 KiB
Python

"""Canonical period helpers shared by analytics report pages."""
from __future__ import annotations
from calendar import monthrange
from datetime import date, datetime
def parse_iso_date(value) -> date | None:
if not value:
return None
if isinstance(value, datetime):
return value.date()
if isinstance(value, date):
return value
try:
return datetime.strptime(str(value)[:10], "%Y-%m-%d").date()
except (TypeError, ValueError):
return None
def parse_month(value) -> date | None:
if not value:
return None
if isinstance(value, datetime):
return value.date().replace(day=1)
if isinstance(value, date):
return value.replace(day=1)
try:
return datetime.strptime(str(value)[:7], "%Y-%m").date()
except (TypeError, ValueError):
return None
def month_end(value) -> date | None:
month_start = parse_month(value)
if not month_start:
return None
return month_start.replace(day=monthrange(month_start.year, month_start.month)[1])
def make_analysis_period(start, end=None, *, mode="range", label=None) -> dict:
start_date = parse_iso_date(start)
end_date = parse_iso_date(end) if end else start_date
if not start_date and end_date:
start_date = end_date
if not start_date or not end_date:
return {
"mode": mode,
"label": label or "全部資料",
"start_date": "",
"end_date": "",
"start_month": "",
"end_month": "",
"is_single_day": False,
"is_single_month": False,
}
if start_date > end_date:
start_date, end_date = end_date, start_date
start_month = start_date.strftime("%Y-%m")
end_month_value = end_date.strftime("%Y-%m")
is_single_day = start_date == end_date
is_single_month = start_month == end_month_value
if not label:
if is_single_day:
label = start_date.strftime("%Y-%m-%d")
elif is_single_month and start_date.day == 1 and end_date == month_end(start_date):
label = start_date.strftime("%Y 年 %m 月")
else:
label = f"{start_date:%Y-%m-%d}{end_date:%Y-%m-%d}"
return {
"mode": mode,
"label": label,
"start_date": start_date.isoformat(),
"end_date": end_date.isoformat(),
"start_month": start_month,
"end_month": end_month_value,
"is_single_day": is_single_day,
"is_single_month": is_single_month,
}
def make_month_period(value, *, mode="month") -> dict:
start = parse_month(value)
if not start:
return make_analysis_period(None, mode=mode)
return make_analysis_period(start, month_end(start), mode=mode)