|
|
@@ -1755,3 +1755,53 @@ target MIN(start_time) 折平 ⇒ 60 + 60 = 120.00,两行都核完,不报
|
|
|
⇒ **割接验收不能只比数字**:数值一致在这里恰恰是"错的理由碰巧撞对了数"。
|
|
|
要判"合并还是丢弃",必须同时核**该活动的 signed 行数 / `activity_money` 合计**
|
|
|
(合并 ⇒ 2000,丢弃 ⇒ 1000)。处置口径需迁移 owner 定,本文件只给数。
|
|
|
+
|
|
|
+### `to` 的格式敏感性:一次只读测量(RS-5 之后追加)
|
|
|
+
|
|
|
+**问题**:RS-5 里那句注释(dump 的 `create_time` 是 VARCHAR、`BETWEEN` 是字符串比较)会不会意味着
|
|
|
+「右端语义」其实只是**入参格式**的副产品?同一份种子,**只改 `to` 的写法**,两侧实测:
|
|
|
+
|
|
|
+**legacy**(`from='2026-03-01'`,种子同上:A −10 / B +100(03-01 00:00)/ C −30 / D +50(03-31 00:00)):
|
|
|
+
|
|
|
+| `to` | prev | income | spend | **end** | 其余 5 列 |
|
|
|
+| --- | --- | --- | --- | --- | --- |
|
|
|
+| `'2026-03-31'` | −10.000 | 100.000 | −30.000 | **60.000** | 0.000 |
|
|
|
+| `'2026-03-31 00:00:00'` | −10.000 | 100.000 | −30.000 | **60.000** | 0.000 |
|
|
|
+| `'2026-03-31 23:59:59'` | −10.000 | 100.000 | −30.000 | **110.000** | 0.000 |
|
|
|
+
|
|
|
+⇒ 三种写法里 `'2026-03-31'` 与 `'2026-03-31 00:00:00'` **对结余列完全同效**(`<` 是严格比较,
|
|
|
+`'…31 00:00:00' < '2026-03-31'` 与 `< '2026-03-31 00:00:00'` 都为 false);
|
|
|
+只有 `23:59:59` 会把 D 计入期末。**"右端开"这个说法在 legacy 侧只对 `<` 成立,与格式无关。**
|
|
|
+
|
|
|
+⚠ 但**当期发生额**用的是 `BETWEEN`(含等号):`'…00:00:00' <= '2026-03-31'` 为 false、
|
|
|
+`<= '2026-03-31 00:00:00'` 为 true ⇒ 若 `t=to` 那笔落在**消费/充值类型**上,两种写法会差一笔。
|
|
|
+本测的 D 取 type=200(不在 IN 列表),所以这一列**没被观察到** —— 这是本测量的已知盲区。
|
|
|
+
|
|
|
+**target**(同一份种子,直接调 `BillService.GetBill`,本地时区 +08:00):
|
|
|
+
|
|
|
+| `to` 来源 | prev | end | exclusive | inclusive |
|
|
|
+| --- | --- | --- | --- | --- |
|
|
|
+| handler 解析裸日期 `2026-03-31`(**UTC 00:00**) | −10.00 | **110.00** | **120.00** | 120.00 |
|
|
|
+| 本地 `2026-03-31 00:00:00` | −10.00 | 60.00 | 70.00 | 120.00 |
|
|
|
+| 本地 `2026-03-31 23:59:59` | −10.00 | 110.00 | 120.00 | 120.00 |
|
|
|
+
|
|
|
+### 由此发现的**真分歧**(未修,需定责)
|
|
|
+
|
|
|
+`handler.parseTimeParam` 用 `time.Parse("2006-01-02", …)` ⇒ **UTC 当日 00:00**,
|
|
|
+而 DB 的 `create_time` 以 `loc=Local` 读出(本机 +08:00)⇒ 同一个裸日期,target 的边界比本地口径**晚 8 小时**。
|
|
|
+legacy 是字符串比较(无时区),等价于本地零点。实测一个整月窗口(`from=2026-03-01 & to=2026-04-01`,
|
|
|
+即文档推荐的"含当日"写法):
|
|
|
+
|
|
|
+| 口径 | prev | end | recharge | exclusive | total |
|
|
|
+| --- | --- | --- | --- | --- | --- |
|
|
|
+| handler(UTC,裸日期) | **90.00** | 110.00 | **0.00** | **20.00** | **2** |
|
|
|
+| 本地(= legacy 的字符串口径) | −10.00 | 110.00 | 100.00 | 120.00 | 3 |
|
|
|
+
|
|
|
+差异机制:`from` 被解析成 03-01 **08:00 本地** ⇒ B(03-01 00:00)被挤进 `PrevBalance`、不计当期充值;
|
|
|
+`to` 被解析成 04-01 08:00 本地 ⇒ 多算 04-01 凌晨的流水。**不报错,只是数不同。**
|
|
|
+
|
|
|
+这一条**没有做成 case**(本轮边界:只测量 + 文档):它落在 handler 层(`parseTimeParam`),
|
|
|
+不是 SP/service 语义;要修得先定口径——三种可能:
|
|
|
+① handler 把裸日期解释为本地零点;② 契约只允许 RFC3339;③ service 侧统一归一。
|
|
|
+责任与处置需另定(候选缺陷,未入本文件结论)。RS-5 用的是**直接调 service + 本地 `to`**,
|
|
|
+所以 RS-5 覆盖的是 service 语义,**不覆盖 handler 的 UTC 解析**。
|