# Calendar Timezone Policy Protocol ## Version - Current: `1.0` - Status: Active --- ## Goal 统一日历事件在 App、Agent、工具、数据库之间的时间语义,消除时区不一致导致的显示和落库偏差。 --- ## Canonical Rules 1. 数据库存储基准为 UTC。 2. 事件语义时区使用 IANA 时区字符串(`event_timezone` / `timezone`)。 3. 禁止无时区时间(naive datetime)进入日历写入链路。 4. 日历写入必须显式确定事件时区,不允许工具层硬编码默认时区。 --- ## Timezone Resolution Priority 运行时事件时区解析顺序固定如下: 1. `event_timezone`(工具调用显式传参) 2. `forwardedProps.client_time.device_timezone` 3. `users.profile.settings.timezone` 4. `UTC` --- ## Write Contract ### Required fields - `start_at`: RFC3339 且必须包含时区偏移 - `timezone`: IANA 时区 ### Optional fields - `end_at`: RFC3339 且必须包含时区偏移(若提供) ### Validation - `timezone` 非法 -> 拒绝请求 - `start_at`/`end_at` 无时区 -> 拒绝请求 - `end_at < start_at` -> 拒绝请求 --- ## Read Contract 读接口最小语义要求: - 返回 UTC 时间字段(`start_at`, `end_at`) - 返回事件时区字段(`timezone`) - 前端展示必须以 `timezone` 作为事件本地时间转换基准,不允许直接按设备本地时区隐式渲染 --- ## Error Codes 推荐错误码(由后端映射为 4xx): - `INVALID_DATETIME_FORMAT` - `NAIVE_DATETIME_FORBIDDEN` - `INVALID_TIMEZONE` - `TIMEZONE_REQUIRED` - `INVALID_TIME_RANGE` --- ## DST Rule - 夏令时切换期间,时间解释以 IANA 时区数据库为准。 - 对于歧义本地时间(例如回拨重复小时),由后端统一按标准库解析策略处理并返回确定 UTC 结果。 --- ## Non-Goals - 本协议不引入新的数据库时间列。 - 本协议不改变 `schedule_items` 现有 `TIMESTAMPTZ + timezone` 存储结构。