顶栏新增时区选择器:加载时自动检测用户所在时区(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
2.7 KiB
2.7 KiB
时区选择
timeTableFix 顶栏提供时区选择器。加载时自动检测用户所在时区,检测不到则默认 澳大利亚墨尔本(Australia/Melbourne)。
检测逻辑
src/lib/timezone.js 的 detectTimezone():
- 读取
new Intl.DateTimeFormat().resolvedOptions().timeZone(浏览器/Node 标准 API)。 - 若抛错、返回空串或格式不合法,回退
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.jsround-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 桥接(与时区无关)。