> 来源:2026-11-12 第五轮深挖审查。行号基于 767fc57 的 main,动手前请核对现场。 ## 位置 - `timex/boundary.go:42-53`(`wallHourStart`:回拨判据假设位移恰为 1 小时——`next := b.Add(time.Hour)` 后比较「同一墙钟小时」) - `timex/boundary.go:133-141`(`EndOfMinute`/`EndOfHour`:`wallXxxStart(t).Add(周期-1ns)`,起点对了、加的周期长度仍是绝对 1 小时/1 分钟) - 不变量出处:`timex/boundary.go:11-12`(「EndOfX = 下一周期起点 - 1ns,不与相邻周期重叠」)、`timex/boundary.go:19-22`(「两条不变量……**无论时区是否处于 DST 切换窗口**」) ## 证据 包内 DST 加固(`boundary_dst_test.go`)只覆盖**整小时位移**时区(America/New_York 等)。对**非整小时 DST 位移**时区(Australia/Lord_Howe、Antarctica/Macquarie:回拨 02:00 → 01:30,位移 30 分钟),`wallHourStart` 的「+1h 后仍是同一墙钟小时 ⇒ 重复」判据不成立,`EndOfHour` 直接把起点加满绝对 1 小时,越过墙钟小时边界。实测(`go test` 探针,Australia/Lord_Howe 2026-04-05 回拨日): ``` second hour: [01:30:00 +10:30, 02:29:59.999999999 +10:30] ← EndOfHour 落进 02 点 after hour start: 02:00:00 +10:30 ← 下一小时的 BeginningOfHour VIOLATION B: EndOfHour(second)=02:29:59.999999999 >= BeginningOfHour(next)=02:00:00 重叠 29m59.999999999s ``` 即 `EndOfHour(t) > t` 成立、但「EndOfX = 下一周期起点 - 1ns、不与相邻周期重叠」被打破:墙钟 02:00–02:30 这半小时**同时**落在 hour-01 桶与 hour-02 桶里。按小时分桶的统计/对账/计费逻辑在这些时区会重复计 30 分钟;`EndOfMinute` 同理(`wallMinuteStart` 的小时基准取错次)。 顺带:`wallHourStart` 对**第一次出现**的 01:45(+11 段)也会因同一判据给出 01:30 起点的错位(探针里 first 段恰好因 `b.Add(1h)` 落点不同而未触发,但判据本身按 1 小时位移推导,30 分钟位移下「重复小时」的检测方向是猜的)。 触发条件:进程时区为 30 分钟 DST 位移时区(Australia/Lord_Howe、Antarctica/Macquarie,及若干历史 30 分钟位移时区)+ 调用 `EndOfHour`/`EndOfMinute`(或依赖其分区语义的 `BeginningOfWeek/EndOfWeek` 组合)。CST(无 DST)的主消费场景不受影响——这也是前四轮没扫到的原因。 ## 建议 - `EndOfX` 不再用「起点 + 固定周期长度」,改为「求下一周期起点再 -1ns」:`next := wallHourStart(t.Add(time.Hour))`(或对位移场景专门探测),保证与 `BeginningOfX(next)` 精确衔接; - `wallHourStart` 的重复检测改为不假设位移幅度:`b.Add(1h)` 落在同一墙钟小时仅是 1 小时位移的特例,可直接以 `t` 是否早于「按 t 的 offset 重建的下一整点」判次; - 两条不变量的表述加一句适用域(若选择不修):「已知边界:非整小时 DST 位移时区(Lord Howe 等)下 EndOfX 可能越入下一墙钟小时」——现在的「无论时区是否处于 DST 切换窗口」是过承诺。 补一条 Lord Howe 用例进 `boundary_dst_test.go`(时区数据在任何完整 tzdata 下可用),断言 `EndOfHour(t) < BeginningOfHour(下一小时)`。
Activity
Merge pull request #429 from oekit/sweep/20261112-l1-b3
zy84338719 commentedon Nov 12, 2026
口径声明已随 PR #429 合入 main(merge commit
6ee91ff5,2026-11-12T18:18:08Z):boundary godoc「无论时区是否处于 DST 切换窗口」的过承诺改为如实适用域——整小时位移时区守两条不变量;Lord Howe/Macquarie(30 分钟回拨)下 EndOfHour/EndOfMinute 会越入下一墙钟周期,按墙钟分桶的统计请改按绝对时间分桶。本单保持 open:完全修复需分段模型重设计(重复段长度 30 分钟、墙钟小时三段占用,桶身份需语义拍板)+ 全 tzdata 测试矩阵,留给专门设计轮,不在本轮半吊子修复。
CI:
link✅ /Lint & Test / Test✅ /Lint & Test / Lint✅ /Zero Third-Party Deps✅zy84338719 commentedon Nov 12, 2026
已在
v0.47.1修复并发布 ✅变更内容
本条修复(在
v0.47.1的版本节里定位到):该版本 `v0.47.1` 的其余变更
关联问题单:pkg#418。
Release: https://github.com/oekit/pkg/releases/tag/v0.47.1