fix: 统一数据库时间为北京时间(UTC+8)
- 新增 app/utils/timezone.py 提供 beijing_now() 工具函数 - models.py 所有表的 created_at/updated_at 默认值从 UTC 改为北京时间 - 解决 event_time(边缘端北京时间)与 handled_at(服务端UTC)差8小时的问题 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
# ==================== 数据库管理 ====================
|
||||
|
||||
20
app/utils/timezone.py
Normal file
20
app/utils/timezone.py
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user