统一前后端时间时区请求

This commit is contained in:
2026-06-03 11:17:37 +08:00
parent 4982efba5e
commit b9410b0ff3
7 changed files with 147 additions and 62 deletions
+21 -29
View File
@@ -35,16 +35,22 @@ from app.services.simulation_ops import (
daily_scheduling_simulation,
)
from app.services.valve_isolation import analyze_valve_isolation
from pydantic import BaseModel, Field
from app.services.time_api import parse_aware_time, parse_utc_time
from pydantic import BaseModel, Field, field_validator
router = APIRouter()
class RunSimulationManuallyByDate(BaseModel):
name: str = Field(..., description="管网名称(或数据库名称)")
simulation_date: str = Field(..., description="模拟基准日期 (YYYY-MM-DD)")
start_time: str = Field(..., description="开始时间 (HH:MM 或 HH:MM:SS)")
duration: int = Field(..., description="持续时间 (分钟)")
start_time: str = Field(..., description="开始时间 (ISO 8601 / RFC3339,必须显式带时区)")
duration: int = Field(..., gt=0, description="持续时间 (分钟)")
@field_validator("start_time")
@classmethod
def validate_start_time_timezone(cls, value: str) -> str:
parse_aware_time(value, field_name="start_time")
return value
class BurstAnalysis(BaseModel):
@@ -109,28 +115,15 @@ class PressureSensorPlacement(BaseModel):
def run_simulation_manually_by_date(
network_name: str, base_date: datetime, start_time: str, duration: int
network_name: str, start_time: datetime, duration: int
) -> None:
time_parts = list(map(int, start_time.split(":")))
if len(time_parts) == 2:
start_hour, start_minute = time_parts
start_second = 0
elif len(time_parts) == 3:
start_hour, start_minute, start_second = time_parts
else:
raise ValueError("Invalid start_time format. Use HH:MM or HH:MM:SS")
start_datetime = base_date.replace(
hour=start_hour, minute=start_minute, second=start_second
)
end_datetime = start_datetime + timedelta(minutes=duration)
current_time = start_datetime
end_datetime = start_time + timedelta(minutes=duration)
current_time = start_time
while current_time < end_datetime:
iso_time = current_time.strftime("%Y-%m-%dT%H:%M:%S") + "+08:00"
simulation.run_simulation(
name=network_name,
simulation_type="realtime",
modify_pattern_start_time=iso_time,
modify_pattern_start_time=current_time.isoformat(timespec="seconds"),
)
current_time += timedelta(minutes=15)
@@ -767,7 +760,7 @@ async def fastapi_pressure_sensor_placement(
return "success"
@router.post("/runsimulationmanuallybydate/", summary="手动运行日期指定模拟", description="根据指定的日期、开始时间和持续时间,手动运行水力模拟。系统将自动查询管网参数并执行模拟")
@router.post("/runsimulationmanuallybydate/", summary="手动运行日期指定模拟", description="根据指定的开始时间和持续时间,手动运行水力模拟。开始时间必须是显式带时区的 ISO 8601 / RFC3339 时间")
async def fastapi_run_simulation_manually_by_date(
data: RunSimulationManuallyByDate = Body(..., description="模拟运行参数"),
) -> dict[str, str]:
@@ -776,14 +769,13 @@ async def fastapi_run_simulation_manually_by_date(
请求体参数:
- **name**: 管网名称(或数据库名称)
- **simulation_date**: 模拟基准日期(YYYY-MM-DD格式
- **start_time**: 开始时间(HH:MM或HH:MM:SS格式)
- **start_time**: 开始时间(ISO 8601 / RFC3339,必须显式带时区
- **duration**: 模拟持续时间(分钟)
系统将从指定日期和时间开始,按15分钟间隔多次运行模拟。
系统将从指定时间开始,按15分钟间隔多次运行模拟。
每次模拟间隔15分钟,直至达到指定的总持续时间。
"""
item = data.dict()
item = data.model_dump()
try:
simulation.query_corresponding_element_id_and_query_id(item["name"])
simulation.query_corresponding_pattern_id_and_query_id(item["name"])
@@ -810,10 +802,10 @@ async def fastapi_run_simulation_manually_by_date(
globals.source_outflow_region_id,
globals.realtime_region_pipe_flow_and_demand_id,
)
base_date = datetime.strptime(item["simulation_date"], "%Y-%m-%d")
start_time = parse_utc_time(item["start_time"], field_name="start_time")
run_simulation_manually_by_date(
item["name"], base_date, item["start_time"], item["duration"]
item["name"], start_time, item["duration"]
)
return {"status": "success"}
except Exception as exc:
return {"status": "error", "message": str(exc)}
raise HTTPException(status_code=500, detail=str(exc)) from exc