timezone_fix_summary.md 6.7 KB

时区修正总结

修正目标

data_orders 表的三个 timestamp 字段(created_atupdated_atprocessed_at)以及其他相关表的时间字段,从使用 UTC 时间改为使用东八区(Asia/Shanghai)时间。

修改内容

1. 创建时区工具模块

文件: app/core/common/timezone_utils.py

创建了统一的时区处理工具模块,提供以下功能:

  • now_china(): 获取当前东八区时间(带时区信息)
  • now_china_naive(): 获取当前东八区时间(不带时区信息,用于数据库存储)
  • to_china_time(): 将任意时区的时间转换为东八区时间
  • utc_to_china_naive(): 将 UTC 时间转换为东八区时间(不带时区信息)

2. 修正数据模型

2.1 app/models/data_product.py

DataProduct 模型:

  • created_at: datetime.utcnownow_china_naive
  • updated_at: datetime.utcnownow_china_naive
  • mark_as_viewed(): 使用 now_china_naive()
  • update_data_stats(): 使用 now_china_naive()

DataOrder 模型:

  • created_at: datetime.utcnownow_china_naive
  • updated_at: datetime.utcnownow_china_naive
  • processed_at: 默认值保持 None,但在更新时使用 now_china_naive()
  • update_status(): 使用 now_china_naive()
  • set_extraction_result(): 使用 now_china_naive()
  • set_graph_analysis(): 使用 now_china_naive()
  • set_result(): 使用 now_china_naive()
  • reject(): 使用 now_china_naive()

2.2 app/models/metadata_review.py

MetadataReviewRecord 模型:

  • created_at: datetime.utcnownow_china_naive
  • updated_at: datetime.utcnownow_china_naive

MetadataVersionHistory 模型:

  • created_at: datetime.utcnownow_china_naive

update_review_record_resolution 函数:

  • resolved_at: 使用 now_china_naive()
  • updated_at: 使用 now_china_naive()

3. 修正服务层

3.1 app/core/data_service/data_product_service.py

修正了所有使用 datetime.utcnow() 的地方:

  • register_product(): 更新现有产品和创建新产品时使用 now_china_naive()
  • update_product_stats(): 使用 now_china_naive()
  • refresh_product_stats(): 使用 now_china_naive()
  • update_order(): 使用 now_china_naive()

3.2 app/core/meta_data/redundancy_check.py

修正了创建审核记录时的时间字段:

  • created_at: 使用 now_china_naive()
  • updated_at: 使用 now_china_naive()

3.3 app/core/business_domain/business_domain.py

修正了创建审核记录时的时间字段:

  • created_at: 使用 now_china_naive()
  • updated_at: 使用 now_china_naive()

技术实现

使用 zoneinfo 而非 pytz

本次修正使用了 zoneinfo 模块,而不是第三方库 pytz。理由如下:

  1. 标准库支持: Python 3.9+ 内置 zoneinfo,Python 3.8 使用 backports.zoneinfo
  2. 更简洁的 API: 相比 pytzzoneinfo 的 API 更符合 Python 的 datetime 使用习惯
  3. 自动更新: 使用系统的 IANA 时区数据库,自动获取最新的时区规则

Python 版本兼容性

代码已兼容 Python 3.8 和 3.9+:

try:
    # Python 3.9+
    from zoneinfo import ZoneInfo
except ImportError:
    # Python 3.8 使用 backports
    from backports.zoneinfo import ZoneInfo

依赖要求:

  • Python 3.8: 需要安装 backports.zoneinfo
  • Python 3.9+: 使用标准库,无需额外安装
  • 所有版本: 需要系统安装 tzdata

数据库存储策略

采用 naive datetime 存储策略:

  • 数据库中存储不带时区信息的 datetime(naive datetime)
  • 所有时间统一使用东八区时间
  • 在应用层确保时间的一致性

这种策略的优点:

  1. 数据库字段类型简单(TIMESTAMP 而非 TIMESTAMP WITH TIME ZONE)
  2. 避免时区转换的复杂性
  3. 符合项目现有的数据库设计

影响范围

直接影响的表

  1. data_orders: created_at, updated_at, processed_at
  2. data_products: created_at, updated_at, last_updated_at, last_viewed_at
  3. metadata_review_records: created_at, updated_at, resolved_at
  4. metadata_version_history: created_at

间接影响

所有依赖这些时间字段的业务逻辑都将使用东八区时间,包括:

  • 数据订单的创建、更新、处理流程
  • 数据产品的注册、更新、查看记录
  • 元数据审核记录的创建和解决

向后兼容性

已有数据

数据库中已存在的记录可能使用的是 UTC 时间。建议:

  1. 新旧数据混合期: 在一段时间内,数据库中会同时存在 UTC 时间和东八区时间的记录
  2. 数据迁移(可选): 如果需要统一历史数据,可以执行以下 SQL:
-- 将 UTC 时间转换为东八区时间(+8小时)
UPDATE data_orders 
SET created_at = created_at + INTERVAL '8 hours',
    updated_at = updated_at + INTERVAL '8 hours',
    processed_at = processed_at + INTERVAL '8 hours'
WHERE created_at < '2026-01-12 00:00:00';  -- 修正前的数据

UPDATE data_products
SET created_at = created_at + INTERVAL '8 hours',
    updated_at = updated_at + INTERVAL '8 hours',
    last_updated_at = last_updated_at + INTERVAL '8 hours',
    last_viewed_at = last_viewed_at + INTERVAL '8 hours'
WHERE created_at < '2026-01-12 00:00:00';

UPDATE metadata_review_records
SET created_at = created_at + INTERVAL '8 hours',
    updated_at = updated_at + INTERVAL '8 hours',
    resolved_at = resolved_at + INTERVAL '8 hours'
WHERE created_at < '2026-01-12 00:00:00';

UPDATE metadata_version_history
SET created_at = created_at + INTERVAL '8 hours'
WHERE created_at < '2026-01-12 00:00:00';

API 响应

所有 API 返回的时间字段(ISO 8601 格式)现在表示的是东八区时间,而不是 UTC 时间。

测试建议

  1. 创建新订单: 验证 created_at 字段是否为东八区当前时间
  2. 更新订单状态: 验证 updated_atprocessed_at 是否正确
  3. 注册数据产品: 验证时间字段是否正确
  4. 查看数据产品: 验证 last_viewed_at 是否更新为东八区时间
  5. 元数据审核: 验证审核记录的时间字段

符合业务规则

本次修正符合 BUSINESS_RULES.md 中的规定:

# Use East Asia timezone for all timestamps
from datetime import datetime
import pytz

虽然业务规则中提到了 pytz,但我们使用了更现代的 zoneinfo 标准库,功能等价且更优。

总结

✅ 所有相关的时间字段已统一使用东八区时间
✅ 创建了统一的时区工具模块,便于后续维护
✅ 修正了 6 个文件,涉及模型层和服务层
✅ 代码通过了 linter 检查,无语法错误
✅ 符合项目的业务规则要求


修正日期: 2026-01-12
修正人: AI Assistant