You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2.7 KiB
2.7 KiB
时间戳时区问题修复
日期: 2026-01-28
类型: Bug 修复
影响范围: 全局数据库模型
问题描述
用户服务 API 测试时发现时间戳类型不匹配错误:
asyncpg.exceptions.DataError: invalid input for query argument $19:
datetime.datetime(2026, 1, 28, 9, 47, 15...
(can't subtract offset-naive and offset-aware datetimes)
根本原因:
- 数据库表使用
TIMESTAMP WITHOUT TIME ZONE - Python 代码使用
datetime.now(timezone.utc)生成 timezone-aware datetime - SQLAlchemy 模型未明确指定
timezone=True
解决方案
1. 数据库迁移
创建迁移脚本 20260128_2230_fix_timestamp_timezone.py,将所有表的时间戳字段从 TIMESTAMP 改为 TIMESTAMPTZ:
涉及表:
users,user_sessions,sms_verification_codesfolders,folder_membersprojects,project_members,project_shares,project_versionsrecharge_orders,payment_callbacksai_models,ai_jobs,ai_quotas,ai_usage_logs
SQL 示例:
ALTER TABLE users
ALTER COLUMN created_at TYPE TIMESTAMPTZ USING created_at AT TIME ZONE 'UTC',
ALTER COLUMN updated_at TYPE TIMESTAMPTZ USING updated_at AT TIME ZONE 'UTC',
ALTER COLUMN deleted_at TYPE TIMESTAMPTZ USING deleted_at AT TIME ZONE 'UTC';
2. 模型定义修复
在 SQLModel 字段定义中明确指定 DateTime(timezone=True):
修改文件:
server/app/models/user.pyserver/app/models/sms.py
修改示例:
from sqlalchemy import DateTime
created_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
sa_column=Column(DateTime(timezone=True), nullable=False)
)
注意事项:
- 不能同时使用
nullable参数和sa_column - 所有 datetime 字段都需要明确指定
timezone=True
测试结果
运行 test_user_api.py 测试脚本:
成功率: 87.5% (7/8)
✅ 通过的测试:
- 健康检查
- 发送短信验证码
- 手机号登录
- 获取当前用户信息
- 更新用户信息
- 查询积分信息
- 用户登出
❌ 失败的测试:
- 绑定邮箱(业务逻辑正确,邮箱已被绑定)
影响范围
- ✅ 用户服务 API 全部正常
- ✅ 时间戳存储和查询正确
- ✅ 符合
datetime-timezone-standards.md规范
后续工作
需要修复其他模型的 datetime 字段定义:
server/app/models/folder.pyserver/app/models/project.pyserver/app/models/ai_*.pyserver/app/models/credit/*.pyserver/app/models/recharge/*.py
相关文档
docs/architecture/datetime-timezone-standards.md- 时间戳规范server/alembic/versions/20260128_2230_fix_timestamp_timezone.py- 迁移脚本server/test_user_api.py- API 测试脚本