# 时区修正总结 ## 修正目标 将 `data_orders` 表的三个 timestamp 字段(`created_at`、`updated_at`、`processed_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.utcnow` → `now_china_naive` - `updated_at`: `datetime.utcnow` → `now_china_naive` - `mark_as_viewed()`: 使用 `now_china_naive()` - `update_data_stats()`: 使用 `now_china_naive()` **DataOrder 模型**: - `created_at`: `datetime.utcnow` → `now_china_naive` - `updated_at`: `datetime.utcnow` → `now_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.utcnow` → `now_china_naive` - `updated_at`: `datetime.utcnow` → `now_china_naive` **MetadataVersionHistory 模型**: - `created_at`: `datetime.utcnow` → `now_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**: 相比 `pytz`,`zoneinfo` 的 API 更符合 Python 的 datetime 使用习惯 3. **自动更新**: 使用系统的 IANA 时区数据库,自动获取最新的时区规则 ### Python 版本兼容性 代码已兼容 Python 3.8 和 3.9+: ```python 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: ```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_at` 和 `processed_at` 是否正确 3. **注册数据产品**: 验证时间字段是否正确 4. **查看数据产品**: 验证 `last_viewed_at` 是否更新为东八区时间 5. **元数据审核**: 验证审核记录的时间字段 ## 符合业务规则 本次修正符合 `BUSINESS_RULES.md` 中的规定: ```python # Use East Asia timezone for all timestamps from datetime import datetime import pytz ``` 虽然业务规则中提到了 `pytz`,但我们使用了更现代的 `zoneinfo` 标准库,功能等价且更优。 ## 总结 ✅ 所有相关的时间字段已统一使用东八区时间 ✅ 创建了统一的时区工具模块,便于后续维护 ✅ 修正了 6 个文件,涉及模型层和服务层 ✅ 代码通过了 linter 检查,无语法错误 ✅ 符合项目的业务规则要求 --- **修正日期**: 2026-01-12 **修正人**: AI Assistant