sansan0/TrendRadar · error · ValueError

检测到时间段重叠冲突: {', '.join(conflicting)} 在 {now_hhmm} 重叠。请调整时间段配

Error message

检测到时间段重叠冲突: {', '.join(conflicting)} 在 {now_hhmm} 重叠。请调整时间段配置,或将 overlap.policy 设为 'last_wins'

What it means

Raised at resolution time when the current HH:MM falls inside two or more periods of the same day plan and overlap.policy is 'error_on_overlap' (the default). The scheduler refuses to guess which period wins; the message names the conflicting periods and points to the 'last_wins' policy as the opt-in resolution.

Source

Thrown at trendradar/core/scheduler.py:220

        """
        candidates = []
        for idx, key in enumerate(day_plan.get("periods", [])):
            period = self.timeline["periods"].get(key)
            if period is None:
                continue
            if self._in_range(now_hhmm, period["start"], period["end"]):
                candidates.append((idx, key))

        if not candidates:
            return None

        # 检查冲突
        if len(candidates) > 1:
            policy = self.timeline.get("overlap", {}).get("policy", "error_on_overlap")
            conflicting = [c[1] for c in candidates]

            if policy == "error_on_overlap":
                raise ValueError(
                    f"检测到时间段重叠冲突: {', '.join(conflicting)} 在 {now_hhmm} 重叠。"
                    f"请调整时间段配置,或将 overlap.policy 设为 'last_wins'"
                )

            # last_wins:输出重叠警告,列表中后面的优先
            print(
                f"[调度] 检测到时间段重叠: {', '.join(conflicting)} 在 {now_hhmm} 重叠"
            )
            winner = candidates[-1]
            print(f"[调度] 冲突策略: last_wins,生效时间段: {winner[1]}")
            return winner[1]

        return candidates[0][1]

    @staticmethod
    def _in_range(now_hhmm: str, start: str, end: str) -> bool:
        """
        检查时间是否在范围内(支持跨日)

View on GitHub (pinned to 8ee26026ba)

Solutions

  1. Adjust start/end times so the periods do not overlap.
  2. If the overlap is intentional and the later-defined period should win, set overlap.policy: last_wins in the timeline (the scheduler then logs a warning and picks the last match).
  3. Move periods that belong to different schedules into separate day_plans.

Example fix

# timeline config
# before
periods:
  morning: {start: "08:00", end: "12:00"}
  late:    {start: "11:00", end: "13:00"}
# after
periods:
  morning: {start: "08:00", end: "11:00"}
  late:    {start: "11:00", end: "13:00"}
# or: overlap: {policy: last_wins}
Defensive patterns

Strategy: validation

Validate before calling

def ranges_overlap(s1, e1, s2, e2):
    m = lambda t: int(t[:2]) * 60 + int(t[3:])
    a, b, c, d = m(s1), m(e1), m(s2), m(e2)
    def ol(x, y):  # handles cross-midnight
        return x[0] < y[1] and y[0] < x[1] if x[0] < x[1] else not (b <= c or d <= a)
    # simpler: normalize both to minute intervals and test intersection per-day
for plan in timeline["day_plans"].values():
    ps = [timeline["periods"][k] for k in plan.get("periods", [])]
    for i in range(len(ps)):
        for j in range(i + 1, len(ps)):
            # reject overlaps unless policy is last_wins
            assert not overlaps(ps[i], ps[j]), f"{ps[i]} overlaps {ps[j]}"

Try / catch

try:
    cfg = scheduler.resolve()
except ValueError as e:
    if "时间段重叠冲突" in str(e):
        # config bug — either fix periods or set overlap.policy=last_wins, then rebuild
        raise SystemExit(f"schedule config error: {e}")
    raise

Prevention

When it happens

Trigger: Two periods like 08:00-12:00 and 11:00-13:00 in one day_plan, and the clock hits 11:30 during resolve(); policy unset or explicitly error_on_overlap.

Common situations: Hand-editing periods and forgetting the earlier boundary; periods intended for different day plans accidentally listed in the same one; cross-midnight periods (e.g. 22:00-02:00) unintentionally overlapping early-morning periods.

Related errors


AI-assisted analysis of sansan0/TrendRadar@8ee26026ba (2026-08-15). Data as JSON: /api/errors/31948c0344171f0d. Report an issue: GitHub.