bx_date_range.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. """报销模块日期范围工具(从 bx-backend 迁移)。"""
  2. from __future__ import annotations
  3. from datetime import datetime, timedelta
  4. def current_month_bounds(now: datetime | None = None) -> tuple[datetime, datetime]:
  5. """当前自然月 [month_start, next_month_start)。"""
  6. if now is None:
  7. now = datetime.now()
  8. month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
  9. if now.month == 12:
  10. month_end = datetime(now.year + 1, 1, 1)
  11. else:
  12. month_end = datetime(now.year, now.month + 1, 1)
  13. return month_start, month_end
  14. def parse_create_time_day_bounds(apply_date: str | None) -> tuple[datetime, datetime] | None:
  15. if not apply_date or not str(apply_date).strip():
  16. return None
  17. try:
  18. day_start = datetime.strptime(str(apply_date).strip(), "%Y-%m-%d")
  19. return day_start, day_start + timedelta(days=1)
  20. except ValueError:
  21. return None
  22. def _parse_day_start(date_str: str | None) -> datetime | None:
  23. if not date_str or not str(date_str).strip():
  24. return None
  25. try:
  26. return datetime.strptime(str(date_str).strip(), "%Y-%m-%d")
  27. except ValueError:
  28. return None
  29. def resolve_create_time_bounds(
  30. apply_date: str | None = None,
  31. apply_date_from: str | None = None,
  32. apply_date_to: str | None = None,
  33. ) -> tuple[datetime | None, datetime | None]:
  34. """解析申请时间筛选边界,返回 (含起, 不含止)。"""
  35. if apply_date_from or apply_date_to:
  36. start = _parse_day_start(apply_date_from)
  37. end = None
  38. day_end = _parse_day_start(apply_date_to)
  39. if day_end is not None:
  40. end = day_end + timedelta(days=1)
  41. return start, end
  42. bounds = parse_create_time_day_bounds(apply_date)
  43. if bounds:
  44. return bounds[0], bounds[1]
  45. return None, None
  46. def append_create_time_filters(
  47. filters: list,
  48. model,
  49. *,
  50. apply_date: str | None = None,
  51. apply_date_from: str | None = None,
  52. apply_date_to: str | None = None,
  53. ) -> None:
  54. start, end = resolve_create_time_bounds(
  55. apply_date=apply_date,
  56. apply_date_from=apply_date_from,
  57. apply_date_to=apply_date_to,
  58. )
  59. if start is not None:
  60. filters.append(model.create_time >= start)
  61. if end is not None:
  62. filters.append(model.create_time < end)