From c39069b9bb700b42ac29c1698345629b21e517dd Mon Sep 17 00:00:00 2001 From: shrey kharbanda Date: Thu, 24 Sep 2026 19:27:55 +0000 Subject: [PATCH] fix(cost): parse override_dates strictly and ignore rules without valid hours override_dates entries are parsed as date objects with an exact YYYY-MM-DD shape, so week-date, ordinal, and whitespace-padded strings can never select a rule. An override rule also needs a parseable hours_utc, matching how ordinary rules without windows are skipped; previously a rule with broken hours won its date and billed peak all day. --- .../litellm_core_utils/llm_cost_calc/utils.py | 43 +++++++++++-------- .../llm_cost_calc/test_llm_cost_calc_utils.py | 26 ++++++++++- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/litellm/litellm_core_utils/llm_cost_calc/utils.py b/litellm/litellm_core_utils/llm_cost_calc/utils.py index 27ef9176c13..9f28fe2b6fb 100644 --- a/litellm/litellm_core_utils/llm_cost_calc/utils.py +++ b/litellm/litellm_core_utils/llm_cost_calc/utils.py @@ -466,8 +466,8 @@ def _weekday_calendar(weekday_timezone: object) -> tzinfo: return timezone.utc -def _calendar_date(reference_utc: datetime, weekday_timezone: object) -> str: - return reference_utc.astimezone(_weekday_calendar(weekday_timezone)).date().isoformat() +def _calendar_date(reference_utc: datetime, weekday_timezone: object) -> date: + return reference_utc.astimezone(_weekday_calendar(weekday_timezone)).date() def _matches_weekdays(reference_utc: datetime, weekdays: object, weekday_timezone: object) -> bool: @@ -492,23 +492,28 @@ def _as_window_strings(value: object) -> tuple[str, ...]: return () -def _is_iso_date(value: object) -> bool: - if not isinstance(value, str) or len(value) != 10: - return False +def _parse_iso_date(value: object) -> date | None: + if ( + not isinstance(value, str) + or len(value) != 10 + or value[4] != "-" + or value[7] != "-" + or not (value[:4] + value[5:7] + value[8:10]).isdigit() + ): + return None try: - date.fromisoformat(value) + return date(int(value[:4]), int(value[5:7]), int(value[8:10])) except ValueError: - return False - return True + return None -def _as_date_strings(value: object) -> tuple[str, ...]: +def _as_dates(value: object) -> frozenset[date]: if isinstance(value, str) or not isinstance(value, Sequence): - return () - entries: Final = tuple(value) - if not entries or not all(_is_iso_date(entry) for entry in entries): - return () - return entries + return frozenset() + parsed: Final = tuple(_parse_iso_date(entry) for entry in value) + if not parsed or any(entry is None for entry in parsed): + return frozenset() + return frozenset(entry for entry in parsed if entry is not None) def _is_off_peak(off_peak: Mapping[str, object], current_time: datetime | None = None) -> bool: @@ -517,8 +522,8 @@ def _is_off_peak(off_peak: Mapping[str, object], current_time: datetime | None = hours apply only on its weekdays. A rule carrying override_dates applies only on those dates, read on the weekday_timezone calendar: on a listed date the matching rules alone decide (their weekdays are ignored, and the flat hours_utc and every other rule are - skipped), and on any other date the rule never applies (a malformed override_dates - disables the rule entirely). + skipped), and on any other date the rule never applies (a malformed override_dates or + hours_utc disables the rule entirely). """ reference: Final = current_time if current_time is not None else current_billing_time() reference_utc: Final = ( @@ -532,7 +537,11 @@ def _is_off_peak(off_peak: Mapping[str, object], current_time: datetime | None = if isinstance(windows, str) or not isinstance(windows, Sequence) else tuple(rule for rule in windows if isinstance(rule, Mapping)) ) - override_rules: Final = tuple(rule for rule in rules if today in _as_date_strings(rule.get("override_dates"))) + override_rules: Final = tuple( + rule + for rule in rules + if _as_window_strings(rule.get("hours_utc")) and today in _as_dates(rule.get("override_dates")) + ) if override_rules: for rule in override_rules: if _is_within_off_peak_window(_as_window_strings(rule.get("hours_utc")), reference_utc): diff --git a/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py b/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py index 397b60190ad..385167e24fa 100644 --- a/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py +++ b/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py @@ -717,13 +717,34 @@ def test_is_off_peak_ignores_malformed_override_dates(): peak_instant = datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc) peak_windows = [{"hours_utc": "00:30-01:00", "weekdays": [1, 2, 3, 4, 5]}] - for bad in ("2026-01-01", [20260101, None], ["2026-1-1"]): + for bad in ( + "2026-01-01", + [20260101, None], + ["2026-1-1"], + ["2026-W01-4"], + ["2026-01-1 "], + ): block = {"windows": peak_windows + [{"hours_utc": "00:00-00:00", "override_dates": bad}]} assert _is_off_peak(block, peak_instant) is False, ( f"override_dates={bad!r} is malformed and must disable its rule" ) +def test_is_off_peak_override_rule_without_valid_hours_is_disabled(): + """An override rule whose hours_utc does not parse never applies, even on a listed + date: the flat hours_utc still decides instead of the broken rule billing peak all day.""" + from datetime import datetime, timezone + + block = { + "hours_utc": "00:00-00:00", + "windows": [ + {"override_dates": ["2026-03-03"], "hours_utc": 5}, + {"override_dates": ["2026-03-03"]}, + ], + } + assert _is_off_peak(block, datetime(2026, 3, 3, 12, 0, tzinfo=timezone.utc)) is True + + def test_is_off_peak_disables_rules_with_partially_malformed_override_dates(): """One bad entry disables the whole override_dates list: a rule whose dates do not all parse never applies on any date, so the flat hours decide alone.""" @@ -758,7 +779,8 @@ def test_override_dates_use_weekday_timezone_calendar_on_shipped_deepseek_rows() """Every shipped DeepSeek row with off_peak_pricing carries the same block as deepseek/deepseek-flash: the 2026 PRC holidays and make-up workdays, read on the Asia/Shanghai calendar. The make-up Sunday bills weekday hours and a holiday is - off-peak all day.""" + off-peak all day. Dates per the State Council 2026 notice, + https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm, read 2026-09-24.""" from datetime import datetime, timezone import litellm