import importlib.util from datetime import date, datetime, timedelta, timezone from pathlib import Path import pytest def _load_time_api_module(): module_path = ( Path(__file__).resolve().parents[2] / "app" / "services" / "time_api.py" ) spec = importlib.util.spec_from_file_location("tests_time_api_under_test", module_path) module = importlib.util.module_from_spec(spec) assert spec and spec.loader spec.loader.exec_module(module) return module def test_parse_utc_time_rejects_naive_datetimes(): module = _load_time_api_module() with pytest.raises(ValueError, match="timezone information"): module.parse_utc_time("2025-01-01T08:00:00") def test_parse_utc_time_normalizes_offset_datetime_to_utc(): module = _load_time_api_module() result = module.parse_utc_time("2025-01-01T08:00:00+08:00") assert result == datetime(2025, 1, 1, 0, 0, tzinfo=timezone.utc) def test_extract_date_keeps_original_offset_calendar_day(): module = _load_time_api_module() result = module.extract_date("2025-01-01T00:30:00+08:00") assert result == date(2025, 1, 1) def test_utc_now_returns_timezone_aware_utc_datetime(): module = _load_time_api_module() result = module.utc_now() assert result.tzinfo == timezone.utc assert result.utcoffset() == timedelta(0) @pytest.mark.parametrize( ("clock", "expected_seconds"), [ ("1:00", 3600), ("01:00", 3600), ("0:05", 300), ("0:05:00", 300), ("24:00", 86400), ], ) def test_parse_clock_duration_seconds_accepts_epanet_clock_formats( clock, expected_seconds ): module = _load_time_api_module() assert module.parse_clock_duration_seconds(clock) == expected_seconds @pytest.mark.parametrize("clock", ["bad", "1:60", "1:00:60", "-1:00"]) def test_parse_clock_duration_seconds_rejects_invalid_clock_formats(clock): module = _load_time_api_module() with pytest.raises(ValueError): module.parse_clock_duration_seconds(clock)