如何在FastAPI中通过Pydantic强制UTC ISO格式时间戳输入
解决方案
要严格限制请求体中的timestamp必须为UTC ISO 8601格式(如2015-09-01T16:09:00.000Z),你可以通过Pydantic的字段验证器实现精确校验。以下是修改后的完整代码:
from typing import Optional from fastapi import FastAPI, Response from pydantic import BaseModel, field_validator from datetime import datetime, timezone import re app = FastAPI() # 注意:原示例中的timestamp格式存在笔误,毫秒部分应该用小数点而非冒号 measurements = [ { "timestamp": "2015-09-01T16:09:00.000Z", "temperature": 27.1 }, { "timestamp": "2016-09-01T16:09:00.000Z", "temperature": 21.3 } ] class MeasurementIn(BaseModel): timestamp: datetime temperature: Optional[float] @field_validator("timestamp") def enforce_utc_iso_format(cls, value): # 验证时间必须是UTC时区 if value.tzinfo is None or value.tzinfo != timezone.utc: raise ValueError("timestamp必须是UTC时区,格式需带'Z'后缀") # 将datetime转换为标准UTC ISO字符串,用于格式校验 utc_iso_str = value.isoformat().replace("+00:00", "Z") # 正则匹配严格格式:YYYY-MM-DDTHH:MM:SS.sssZ format_pattern = r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$" if not re.match(format_pattern, utc_iso_str): raise ValueError("timestamp格式必须为'YYYY-MM-DDTHH:MM:SS.sssZ'") return value @app.post("/measurements") async def create_measurement(m: MeasurementIn, response: Response): # 将datetime转换为标准UTC ISO字符串存入列表 measurements.append({ "timestamp": m.timestamp.isoformat().replace("+00:00", "Z"), "temperature": m.temperature }) response.status_code = 201 return {"message": "Measurement created", "data": m.dict()}
关键说明
- 时区校验:验证器会检查解析后的
datetime对象是否带有UTC时区信息,确保客户端发送的时间戳必须带Z后缀(表示UTC)。 - 格式严格匹配:通过正则表达式强制要求时间戳包含毫秒部分(
.sss),且整体符合YYYY-MM-DDTHH:MM:SS.sssZ格式。 - 错误反馈:如果客户端发送不符合要求的时间戳,FastAPI会自动返回422验证错误,包含具体的错误信息。
注意事项
- 如果你使用的是Pydantic v1版本,需要将
@field_validator替换为@validator,并导入from pydantic import validator。 - 原示例中的时间戳格式(
2015-09-01T16:09:00:000Z)是错误的,标准ISO 8601格式中毫秒部分应该用小数点分隔,而非冒号。
内容的提问来源于stack exchange,提问作者meallhour
相关产品推荐
相关产品推荐

