## [ERR-20260427-009] ADP floating-time `-00:00` 不是 UTC 而是"unknown local"

**日期**: 2026-04-27
**类别**: ADP API / 时区
**严重度**: 高（PTO 时段全部偏 7-8 小时，会议重叠判定全失效）

### 问题描述
ADP `time-off-requests` 返回的 `dateTimePeriod.startDateTime` / `endDateTime` 长这样：
```
2026-04-20T08:00:00-00:00
2026-04-20T16:00:00-00:00
```
看起来像 UTC 8AM-4PM。但实际 Aaron 是 LA 员工，正常工作日 PT 时间 8-16，对应 UTC 15:00-23:00。我们 `new Date(startStr)` 直接当 UTC 解析，**整体偏 7-8 小时**。

UI 表现：所有"会议自动标 PTO"功能完全失效，因为 SQL 重叠检查永远不命中。

### 根因
ISO 8601 `-00:00` 在标准里是「**unknown local offset**」语义（ICANN/RFC 3339），跟 `+00:00`（UTC）**不等价**。ADP 用它表示"员工本地时间，但没附时区信息"——客户端必须知道该员工的时区才能正确解析。

JavaScript 的 `new Date("...-00:00")` 把它当 UTC 处理，破坏 ADP 的语义。

### 修复
```ts
import { fromZonedTime } from 'date-fns-tz';

const ADP_DEFAULT_TZ = 'America/Los_Angeles';

function parseAdpFloatingTime(s: string): Date {
  const stripped = s.replace(/(?:Z|[+-]\d{2}:?\d{2})$/, '');
  return fromZonedTime(stripped, ADP_DEFAULT_TZ);
}
```
现在 FF 全员都按 LA 时区。如未来有海外员工，需要改成"按员工 ADP 时区偏好"。

### 数据迁移
旧数据全部时区错，必须 `DELETE FROM adp_pto_schedules` + 重跑 PTO sync。

### 启示
- **永远不要假设带 `-00:00` 的 ISO 字符串是 UTC**。看到 `-00:00` 第一反应应该是"这个 API 没说时区"，要查文档
- HR/工时类 API 的"日期时间"几乎都是员工本地时间。设计内部存储一律用 UTC，但 parsing 端必须知道源数据时区
- 上线前要有跨时区测试用例：员工 PT 8AM PTO，会议 PT 2PM —— 期望被标 PTO

---
