diff --git a/app/models.py b/app/models.py index 06d7467..820ad87 100644 --- a/app/models.py +++ b/app/models.py @@ -4,6 +4,8 @@ import enum import os from datetime import datetime, timezone + +from app.utils.timezone import beijing_now from typing import Optional from sqlalchemy import ( Column, String, Integer, SmallInteger, BigInteger, Boolean, Float, DateTime, Text, Enum, JSON, @@ -102,9 +104,9 @@ class Alert(Base): work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=True) # 时间戳 - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) - updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), - onupdate=lambda: datetime.now(timezone.utc)) + created_at = Column(DateTime, default=lambda: beijing_now()) + updated_at = Column(DateTime, default=lambda: beijing_now(), + onupdate=lambda: beijing_now()) # 关系 work_order = relationship("WorkOrder", back_populates="alerts", foreign_keys=[work_order_id]) @@ -175,9 +177,9 @@ class WorkOrder(Base): assigned_at = Column(DateTime, nullable=True) started_at = Column(DateTime, nullable=True) completed_at = Column(DateTime, nullable=True) - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) - updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), - onupdate=lambda: datetime.now(timezone.utc)) + created_at = Column(DateTime, default=lambda: beijing_now()) + updated_at = Column(DateTime, default=lambda: beijing_now(), + onupdate=lambda: beijing_now()) # 关系 alerts = relationship("Alert", back_populates="work_order", foreign_keys=[Alert.work_order_id]) @@ -231,9 +233,9 @@ class EdgeDevice(Base): # 扩展 extra_info = Column(JSON, nullable=True) - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) - updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), - onupdate=lambda: datetime.now(timezone.utc)) + created_at = Column(DateTime, default=lambda: beijing_now()) + updated_at = Column(DateTime, default=lambda: beijing_now(), + onupdate=lambda: beijing_now()) def to_dict(self) -> dict: return { @@ -279,9 +281,9 @@ class AlarmEvent(Base): handler = Column(String(64), comment="处理人") handle_remark = Column(Text, comment="处理备注") handled_at = Column(DateTime, comment="处理时间") - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) - updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), - onupdate=lambda: datetime.now(timezone.utc)) + created_at = Column(DateTime, default=lambda: beijing_now()) + updated_at = Column(DateTime, default=lambda: beijing_now(), + onupdate=lambda: beijing_now()) __table_args__ = ( Index('idx_alarm_event_time', 'event_time'), @@ -323,7 +325,7 @@ class AlarmEventExt(Base): ext_type = Column(String(32), comment="扩展类型: EDGE/POST/MANUAL") ext_data = Column(JSON, comment="扩展数据") roi_config = Column(JSON, comment="ROI配置快照") - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) + created_at = Column(DateTime, default=lambda: beijing_now()) def to_dict(self) -> dict: return { @@ -349,7 +351,7 @@ class AlarmLlmAnalysis(Base): risk_score = Column(Integer, comment="风险评分 0-100") confidence_score = Column(Float, comment="分析置信度") suggestion = Column(Text, comment="处置建议") - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) + created_at = Column(DateTime, default=lambda: beijing_now()) def to_dict(self) -> dict: return { @@ -413,8 +415,8 @@ class NotifyArea(Base): area_name = Column(String(100), nullable=False) description = Column(String(200), nullable=True) enabled = Column(SmallInteger, default=1) - created_at = Column(DateTime, default=datetime.now) - updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) + created_at = Column(DateTime, default=beijing_now) + updated_at = Column(DateTime, default=beijing_now, onupdate=beijing_now) class CameraAreaBinding(Base): @@ -424,7 +426,7 @@ class CameraAreaBinding(Base): id = Column(Integer, primary_key=True, autoincrement=True) camera_id = Column(String(64), unique=True, nullable=False, index=True) area_id = Column(String(36), nullable=False, index=True) - created_at = Column(DateTime, default=datetime.now) + created_at = Column(DateTime, default=beijing_now) class AreaPersonBinding(Base): @@ -438,8 +440,8 @@ class AreaPersonBinding(Base): role = Column(String(20), default="SECURITY") notify_level = Column(Integer, default=1) enabled = Column(SmallInteger, default=1) - created_at = Column(DateTime, default=datetime.now) - updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) + created_at = Column(DateTime, default=beijing_now) + updated_at = Column(DateTime, default=beijing_now, onupdate=beijing_now) # ==================== 数据库管理 ==================== diff --git a/app/utils/timezone.py b/app/utils/timezone.py new file mode 100644 index 0000000..b8654fc --- /dev/null +++ b/app/utils/timezone.py @@ -0,0 +1,20 @@ +""" +时区工具 + +本系统所有时间统一使用北京时间(UTC+8)。 +边缘端上报的 event_time 是北京时间,服务端生成的时间也使用北京时间, +确保数据库中所有时间字段语义一致。 +""" + +from datetime import datetime, timezone, timedelta + +# 北京时区 UTC+8 +BEIJING_TZ = timezone(timedelta(hours=8)) + + +def beijing_now() -> datetime: + """返回当前北京时间(naive datetime,无时区信息) + + 用于数据库存储,与边缘端上报的 event_time 格式一致。 + """ + return datetime.now(BEIJING_TZ).replace(tzinfo=None)