Files
timeTableFix/docs/timezone.md
zikai cf941c50bc feat: 增加时区选择(自动检测,回退墨尔本)
顶栏新增时区选择器:加载时自动检测用户所在时区(Intl.DateTimeFormat),
检测不到则默认澳大利亚墨尔本。选定时区作为新建事件的默认 tzid 与下载
ICS 的 X-WR-TIMEZONE,不做时间换算(应用内部为 wall-clock 字符串)。

- 新增 src/lib/timezone.js(detect/list/validate/默认值)
- useCalendar 持 state.timezone、setTimezone、addEvent 传 tzid、serialize 注入 X-WR-TIMEZONE
- HeaderBar 顶栏下拉选择器 + i18n 文案
- 新增 test/timezone.test.js(15 项),全量 57 项通过
- README 简述功能,细节移至 docs/timezone.md
2026-07-27 09:49:13 +08:00

50 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 时区选择
timeTableFix 顶栏提供时区选择器。加载时自动检测用户所在时区,检测不到则默认 **澳大利亚墨尔本(`Australia/Melbourne`**
## 检测逻辑
`src/lib/timezone.js``detectTimezone()`
1. 读取 `new Intl.DateTimeFormat().resolvedOptions().timeZone`(浏览器/Node 标准 API
2. 若抛错、返回空串或格式不合法,回退 `DEFAULT_TIMEZONE``Australia/Melbourne`)。
非安全上下文(无 `https`)或极旧环境可能拿不到时区,此时一律回退墨尔本。
## 下拉列表来源
`listTimezones()` = 精选常用 IANA 时区(`COMMON_TIMEZONES`,含墨尔本/上海/UTC 等)∪ 运行时 `Intl.supportedValuesOf('timeZone')`(若可用),去重后排序,`UTC` 置顶。旧浏览器不支持 `supportedValuesOf` 时静默降级为仅精选列表,保证下拉始终可用、无外部依赖。
## 作用范围(设计要点)
应用内部所有日期/时间均为 **wall-clock 字符串**`YYYY-MM-DD` + `HH:MM`,见 `date.js`**不做任何时区换算**。时区仅是一个挂在事件上的 IANA 标识(`tzid`),在 ICS 序列化/反序列化时作为 `DTSTART`/`DTEND``TZID` 参数读写。
因此选定时区的作用是**日历级默认值/标签**,而非时间换算层:
| 行为 | 是否受选定时区影响 |
|---|---|
| 新建事件(「新增日程」)的 `tzid` | ✅ 使用选定时区 |
| 下载 ICS 的 `X-WR-TIMEZONE` | ✅ 写入选定时区 |
| 已导入事件的 `tzid` | ❌ 保留原始 TZID不覆盖、不换算 |
| 日期/时间数值(编辑、预览、整理) | ❌ 始终 wall-clock不换算 |
| 间隔去重(`organize.js` | ❌ 不读 `tzid`,不受影响 |
### 为何不换算
- 应用面向「整理/编辑日程文本」而非「跨时区会议调度」wall-clock 直观且无歧义。
- `organize.js``[summary, location, 开始时间, 时长]` 合并重复,引入换算会改变合并键、破坏既有 round-trip 测试。
- 已导入事件保留原 TZID 保证 `parse(serialize(parse(x)))` 等价(见 `ical-io.test.js` round-trip 用例)。
## 实现位置
| 文件 | 改动 |
|---|---|
| `src/lib/timezone.js` | 新增:检测/列表/校验/默认值 |
| `src/composables/useCalendar.js` | `state.timezone`(初始 `detectTimezone()`)、`setTimezone()``addEvent` 传入 tzid、`serialize` 注入 `X-WR-TIMEZONE` |
| `src/components/HeaderBar.vue` | 顶栏 `<select>` 选择器 |
| `src/i18n/locales/{zh-CN,en}.js` | `header.timezone` 文案 |
## 嵌入 mainPage
时区状态属于 timeTableFix 自有单例 store嵌入 mainPage 时随子模块独立运作,不与父项目共享。语言切换仍经 `:locale` prop 桥接(与时区无关)。