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.
 

5.8 KiB

Folder Service 时间戳规范修正

日期:2026-01-29
类型:规范修正(重大)
影响范围folder-service.md 文档


修正背景

在 v3.5 版本中,错误地将所有事件时间字段从 TIMESTAMPTZ 改为 TIMESTAMP WITHOUT TIME ZONE,这违反了 PostgreSQL 最佳实践和项目架构决策(ADR 006)。

本次修正(v3.6)将时间戳规范改回正确的 TIMESTAMPTZ


修正内容

1. 时间戳类型修正(符合 ADR 006)

v3.5(错误)

-- ❌ 错误:使用 TIMESTAMP WITHOUT TIME ZONE 记录事件时间
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP WITHOUT TIME ZONE,

v3.6(正确)

-- ✅ 正确:使用 TIMESTAMPTZ 记录事件时间
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ,

涉及表

  • folders 表:created_at, updated_at, deleted_at
  • folder_members 表:joined_at, created_at
  • folder_shares 表:expires_at, created_at, revoked_at
  • folder_export_jobs 表:created_at, started_at, completed_at, expires_at

2. 默认值修正

v3.5(错误)

DEFAULT CURRENT_TIMESTAMP

v3.6(正确)

DEFAULT now()

原因

  • now() 是 PostgreSQL 推荐的函数
  • TIMESTAMPTZ 类型配合使用
  • 更简洁明确

3. 字段注释修正

v3.5(错误)

COMMENT ON COLUMN folders.created_at IS '创建时间(UTC)';

v3.6(正确)

COMMENT ON COLUMN folders.created_at IS '创建时间(自动记录时区)';

原因

  • TIMESTAMPTZ 自动记录时区信息
  • 不应标注"UTC",因为数据库会自动处理时区转换
  • 更准确地描述字段行为

修正理由

根据 ADR 006: 事件时间戳必须使用 TIMESTAMPTZ

1. 语义正确性

事件时间(created_at, updated_at, deleted_at 等)表示真实世界发生的时间点,必须包含时区信息。

错误理解:应用层使用 UTC,所以数据库不需要时区
正确理解:事件时间是绝对时间点,必须用 TIMESTAMPTZ 表示

2. PostgreSQL 官方推荐

PostgreSQL 官方文档明确推荐:

  • 使用 TIMESTAMPTZ 记录事件时间
  • 数据库自动处理时区转换
  • 避免应用层时区处理错误

3. 性能相同

TIMESTAMPTZTIMESTAMP WITHOUT TIME ZONE

  • 存储大小完全相同(8 字节)
  • 查询性能完全相同
  • 索引性能完全相同

4. 多时区支持

使用 TIMESTAMPTZ 的优势:

  • 支持全球化部署
  • 支持多时区用户
  • 数据库自动处理时区转换
  • 避免应用层时区错误

5. 数据一致性

-- TIMESTAMPTZ 自动处理时区
SET timezone = 'Asia/Shanghai';
SELECT created_at FROM folders WHERE id = '...';
-- 返回:2026-01-29 18:00:00+08

SET timezone = 'America/New_York';
SELECT created_at FROM folders WHERE id = '...';
-- 返回:2026-01-29 05:00:00-05
-- 同一时间点,不同时区显示

文档版本更新

v3.6 (2026-01-29) - 当前版本

  • 修正时间戳规范(符合 ADR 006)
    • 数据库层:所有事件时间字段使用 TIMESTAMPTZ
    • 默认值:统一使用 now() 而非 CURRENT_TIMESTAMP
    • 字段注释:改为"自动记录时区"而非"UTC"
    • 理由:事件时间表示真实世界时间点,必须包含时区信息

v3.5 (2026-01-29) - 已废弃

  • 错误的时间戳规范(已被 v3.6 修正):
    • 错误地使用 TIMESTAMP WITHOUT TIME ZONE 记录事件时间
    • 违反了 PostgreSQL 最佳实践和 ADR 006 决策

技术栈规范更新

同时更新了 jointo-tech-stack skill 的时区规范:

database.md 修正

-- ❌ v3.5 错误示例
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,

-- ✅ v3.6 正确示例
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),

backend.md 修正

核心原则

  • 数据库使用 TIMESTAMPTZ 记录事件时间
  • Python 应用层使用 datetime.now(timezone.utc) 生成 UTC 时间
  • PostgreSQL 自动处理时区转换

影响评估

文档层面

  • 文档符合 PostgreSQL 最佳实践
  • 文档符合 ADR 006 架构决策
  • 示例代码正确可用

实现层面

  • ⚠️ 如果已按 v3.5 实现,需要修正
  • ⚠️ 检查所有时间戳列类型
  • ⚠️ 检查默认值定义

数据库层面

  • ⚠️ 如果已创建表,需要检查列类型
  • ⚠️ 必要时创建迁移脚本修正

检查清单

  • 所有事件时间字段使用 TIMESTAMPTZ
  • 默认值使用 now() 而非 CURRENT_TIMESTAMP
  • 字段注释使用"自动记录时区"
  • 更新文档版本号(v3.4 → v3.6)
  • 更新变更记录
  • 创建 Changelog 记录修正过程
  • 更新 jointo-tech-stack skill 规范

相关文档


总结

本次修正纠正了 v3.5 版本的错误决策,将时间戳规范改回正确的 TIMESTAMPTZ。这符合:

  1. PostgreSQL 官方最佳实践
  2. ADR 006 架构决策
  3. 语义正确性(事件时间是绝对时间点)
  4. 多时区支持需求

重要提醒:所有记录"真实世界发生时间点"的字段,必须使用 TIMESTAMPTZ