杂记 › 技术笔记 › 相对时间的「一个月」写死 30 天:时间戳页六档除数、13 位毫秒输入与 UTC+8/UTC-5 两档截断实测

相对时间的「一个月」写死 30 天:时间戳页六档除数、13 位毫秒输入与 UTC+8/UTC-5 两档截断实测

时间戳页的相对时间只用两把写死的除数:30天算一个月、365天算一年;六档切换点、11位与12位被当毫秒、slice(0,16)两档截断的逐字实测。

一个月在这页只有 30 天那么长

起因是 29 天前的记录写「29 天前」、30 天前的写「1 个月前」,中间没有「一个月零几天」。为找切换点,我把这页脚本单独跑了一轮:模板 341 行 / 12362 字节,脚本块原样执行,DOM 只给按 id 建的桩,时区在命令行钉成两档(getTimezoneOffset 实测 -480 分钟与 +300 分钟)。

被测的是时间戳转换这一页,相对时间挂在第一个 tab 的结果区里。

六档除数是写死的常量

relativeTime(L285–L295)是一条 if 链,除数依次 1000 / 60000 / 3600000 / 86400000 / 2592000000 / 31536000000,没有日历参与:2592000000 除以 86400000 得 30,年档同理得 365,「一个月」在这页恒等于 30 天。交界读数:

diff(毫秒)读数
59999 / 6000059 秒前 / 1 分钟前
86399999 / 8640000023 小时前 / 1 天前
2591999999 / 259200000029 天前 / 1 个月前
31535999999 / 3153600000012 个月前 / 1 年前

两档时区各跑一遍,表的差值与读数逐字相同,只有起点 ts 差 46800000 毫秒。过去与未来只差后缀:数字出自 Math.abs,方向出自 sign 的 diff>=0,diff=0 落「0 秒前」。

跨月与跨闰年各读到什么

28 天(2419200000 毫秒)读「28 天前」,29 天读「29 天前」,30 天整才第一次见「1 个月前」,31 天(2678400000)仍只读「1 个月前」;跨闰的 366 天与平年 365 天同读「1 年前」。13 个 30 天(33696000000 毫秒)已落年档,字面「13 个月」不可达。按真实日历加月份是另一页:时间加减计算。

日历差值 → relativeTime 读数 2592000000 / 30 天 1 个月前 2678400000 / 31 天 1 个月前 2419200000 / 28 天 28 天前 31536000000 / 365 天 1 年前 31622400000 / 366 天 1 年前 31449600000 / 364 天 12 个月前 月档与年档只按常量除数取整。

图 1:跨月与跨闰的读数阶梯,30 天与 31 天落在同一格。

位数识别不是 10 与 13 两档

输入侧(L306–L309)先 parseInt(val,10),再判 String(ts).length<=10 才乘 1000:识别按位数走,却不是那两档。13 位「1717200000123」不乘,iso 出「2024-06-01T00:00:00.123Z」;11 位与 12 位同样被当毫秒,落 1970-07-18 与 1975-06-11。负数最别扭:「-1717200000」的负号占进 String 长度成 11,落 1969-12-12T03:00:00.000Z,9 位「-171720000」反而正确走秒档——分界在位数,不在正负。

早退只有三条:空串藏掉结果区,NaN 弹 toast「请输入有效的时间戳数字」,越界弹「无效的时间戳」,后两条只弹提示、六格残留上一轮读数。其余连提示都没有:「20240531」当秒乘 1000 落 1970-08-23T06:22:11.000Z。

「填入现在」丢掉的正好是秒

fillNowDt(L323–L328)先按 getTimezoneOffset()*60000 平移再 slice(0,16)。取 FIXED_NOW=1717214437500:UTC+8 档平移后是 24 字符「2024-06-01T12:00:37.500Z」,截成 16 字符、丢 8 字符,回跑得 1717214400,比真实秒 1717214437 低 37 秒;UTC-5 档同值截出「2024-05-31T23:00」,回跑同为 1717214400。同一日期框串「2024-06-01T00:00」两档给 1717171200 与 1717218000,差 46800 秒即 13 小时,全页没有时区控件(grep select 命中 0 处)。

一次 slice(0,16) 的字符账 UTC+8 档 UTC-5 档 24 字符 2024-06-01T12:00:37.500Z 24 字符 2024-05-31T23:00:37.500Z 截出 16 字符 2024-06-01T12:00 截出 16 字符 2024-05-31T23:00 回跑 1717214400,低 37 秒 回跑 1717214400

图 2:截断前后各剩几字符,与两档偏移的差。

取整方向与往返还差多少

Math.floor 向负无穷取整:FIXED_NOW=-500 时秒格读「-1」,-1500 读「-2」,-1717200000500 读「-1717200001」,比截绝对值少 1;这串回填后再喂回去,因长度 11 又被当毫秒,读「54 年后」。同档内往返干净:「1717200000」回填日期框再回跑差 0,「1717200000123」的毫秒只进 iso 不进本地框,回填后尾数归零、差 123。

多次行为与没测到的

计时器桩实测 setInterval 只注册 1 条、间隔 1000 毫秒(L270);NOW 推进 86400000 后,同一个 ts=1717200000000 从「0 秒前」变「1 天前」,这格每次现读、不缓存。真实跳字与渲染次数本轮纯 Node 无渲染器,标未实测。

文案与代码差在哪两条

config/tools.php 的 timestamp 条目(L102–L115)逐条判,10 条里 [一致] 6、[部分一致] 2、[冲突] 2。冲突两条:description(L111)的「多时区选择」——grep select 命中 0 处,日期框只是 type="datetime-local";intro(L112)连同模板 L51 的标签「北京时间(Asia/Shanghai)」——那格走本机 getter,UTC-5 档实测显示「2024-05-31 19:00:00」。部分一致是 summary「支持时区」与占位符位数口径;本页只读本机 Date。日期按月份加减落到哪一天,站内旧文写过一次,这里不复述。

常见问题

Q:为什么 31 天前的记录只写「1 个月前」?

月档除数写死为 2592000000 毫秒即 30 天,超出部分按常量取整。

Q:13 位毫秒要不要先自己换算?

不用换算,但它不只认 13 位:判据是不超过 10 位才乘 1000,11 位与 12 位一样被当毫秒。

Q:结果区的数一定是这一轮的吗?

不一定,非法输入只弹提示,六格残留上一轮读数。

📎 相关文章

星号段长写死:脱敏页五套掩码固定切出 4、3、11、12 枚星号,18 位串被手机档抢走、空框回落 * 2026-11-13 锁是单向的、百分比是两把尺:pct 50 得 619×430,PNG 四档 quality 全 6971 B 2026-11-13 两 tab 各算一遍同一个 C(n,r):n=20 写满 40 个因子、n=21 一格不剩,300 位大数与 r=0 的两种读法 2026-11-13 8 个元素算得出 40320 条却只列 5000 行:排列计算器的两道互不相干的上限、重复元素按 3! 计数与 n≤20 的过程断点 2026-11-12 投放链接的装配顺序与大小写折叠:UTM 生成器六态标注、两道硬上限与五栏各用一把尺实测 2026-11-12