diff --git a/backend/scheduler.py b/backend/scheduler.py index 9aeeae4..2d1a9c0 100644 --- a/backend/scheduler.py +++ b/backend/scheduler.py @@ -26,7 +26,7 @@ import logging import os import threading import uuid -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path from typing import Any @@ -118,7 +118,7 @@ def _validate_schedule(schedule: dict[str, Any]) -> dict[str, Any]: try: parsed = datetime.fromisoformat(at) if parsed.tzinfo is None: - parsed = parsed.replace(tzinfo=timezone.utc) + parsed = parsed.replace(tzinfo=UTC) except ValueError: raise ValueError("at doit être une date ISO-8601 (ex. 2026-10-05T08:30:00)") from None return {"kind": kind, "at": parsed.isoformat()} @@ -138,7 +138,7 @@ def create_task( """Create a scheduled task. Raises ValueError on invalid action/schedule.""" validated_action = _validate_action(action) validated_schedule = _validate_schedule(schedule) - now = datetime.now(timezone.utc) + now = datetime.now(UTC) with _lock: tasks = _read_tasks() task = { @@ -200,9 +200,9 @@ def delete_task(task_id: str) -> bool: def compute_next_run(task: dict[str, Any], now: datetime | None = None) -> datetime: """Compute the next due datetime for *task*.""" - now = now or datetime.now(timezone.utc) + now = now or datetime.now(UTC) if now.tzinfo is None: - now = now.replace(tzinfo=timezone.utc) + now = now.replace(tzinfo=UTC) schedule = task.get("schedule", {}) kind = schedule.get("kind") last_run_at = task.get("last_run_at") @@ -211,7 +211,7 @@ def compute_next_run(task: dict[str, Any], now: datetime | None = None) -> datet try: last = datetime.fromisoformat(str(last_run_at)) if last.tzinfo is None: - last = last.replace(tzinfo=timezone.utc) + last = last.replace(tzinfo=UTC) except ValueError: last = None if kind == "interval_hours": @@ -233,11 +233,11 @@ def compute_next_run(task: dict[str, Any], now: datetime | None = None) -> datet try: at = datetime.fromisoformat(str(schedule.get("at"))) if at.tzinfo is None: - at = at.replace(tzinfo=timezone.utc) + at = at.replace(tzinfo=UTC) except ValueError: return now if task.get("last_run_at"): - return datetime.max.replace(tzinfo=timezone.utc) # déjà exécutée + return datetime.max.replace(tzinfo=UTC) # déjà exécutée return at return now + timedelta(hours=24) @@ -278,7 +278,7 @@ def run_task(task_id: str, *, manual: bool = False) -> dict[str, Any]: return {"task_id": task_id, "skipped": True, "reason": "disabled"} try: result = _execute_action(task) - task["last_run_at"] = datetime.now(timezone.utc).isoformat() + task["last_run_at"] = datetime.now(UTC).isoformat() task["last_status"] = "ok" task["last_error"] = None task["run_count"] = int(task.get("run_count", 0)) + 1 @@ -292,7 +292,7 @@ def run_task(task_id: str, *, manual: bool = False) -> dict[str, Any]: broadcast("schedule_success", f"Tâche « {task['name']} » OK", "Exécution manuelle réussie.") return {"task_id": task_id, "ok": True, "result": result} except Exception as e: - task["last_run_at"] = datetime.now(timezone.utc).isoformat() + task["last_run_at"] = datetime.now(UTC).isoformat() task["last_status"] = "error" task["last_error"] = str(e) task["run_count"] = int(task.get("run_count", 0)) + 1 @@ -315,7 +315,7 @@ def run_task(task_id: str, *, manual: bool = False) -> dict[str, Any]: def tick(now: datetime | None = None) -> list[dict[str, Any]]: """Run every due task. Returns per-task outcomes (empty when idle).""" - now = now or datetime.now(timezone.utc) + now = now or datetime.now(UTC) outcomes: list[dict[str, Any]] = [] for task in _read_tasks(): if not task.get("enabled", True): @@ -323,7 +323,7 @@ def tick(now: datetime | None = None) -> list[dict[str, Any]]: try: next_run = datetime.fromisoformat(str(task.get("next_run_at") or "")) if next_run.tzinfo is None: - next_run = next_run.replace(tzinfo=timezone.utc) + next_run = next_run.replace(tzinfo=UTC) except ValueError: next_run = compute_next_run(task, now) if next_run <= now: