[{"data":1,"prerenderedAt":176},["ShallowReactive",2],{"article-timestamp-10-vs-13-digit-year-bug":3},{"article":4,"relatedArticles":129},{"slug":5,"category":6,"date":7,"readingMinutes":8,"tags":9,"relatedTool":14,"cn":15,"en":64,"author":113,"reviewedBy":116,"reviewedDate":118,"updatedDate":118,"sources":119,"noIndex":128},"timestamp-10-vs-13-digit-year-bug","踩坑避坑","2026-07-28",7,[10,11,12,13],"Timestamp","10-digit","13-digit","Year 1970 Bug","/tools/dev/timestamp",{"title":16,"description":17,"intro":18,"sections":19},"10 位与 13 位时间戳误用导致的“1970年”或“55000年”Bug 排查","剖析秒级 (10位) 与毫秒级 (13位) Unix 时间戳在 JavaScript Date 转换中的物理单位差异，给出单位归一化防错函数与排坑指南。","在调用 `new Date(timestamp)` 时，前端经常碰到时间变为“1970-01-01”或后端接收到“55800年”的奇葩事故。造成这类 Bug 的根因在于混淆了秒 (10位) 与毫秒 (13位) 时间戳单位。本文针对这一问题给出单位校验、格式化与工程化防错规则。",[20,24,29,33,37,42,46,50,54,60],{"heading":21,"paragraphs":22},"一、问题概述：秒与毫秒物理单位混淆的渲染灾难",[23],"Unix 时间戳定义为自 1970-01-01 00:00:00 UTC 起经过的时间总量。C++、Python、PHP、Go 默认返回秒级 (10 位) 时间戳（如 `1700000000`）；而 JavaScript `Date.now()` 和 Java `System.currentTimeMillis()` 默认返回毫秒级 (13 位) 时间戳（如 `1700000000000`）。若将 10 位秒级时间戳直接传给 JS `new Date(1700000000)`，得到的其实是 1970 年 1 月的第 1,700,000 秒！",{"heading":25,"paragraphs":26,"code":28},"二、最小复现：相同数值在不同单位下解析结果对比",[27],"下面的对比展示了将 10 位秒级时间戳与 13 位毫秒级时间戳传入 JavaScript `Date` 产生的巨大物理偏差：","/* 示例原始秒级时间戳: 1700000000 (代表 2023-11-14 22:13:20 UTC) */\nconst timestamp10 = 1700000000;\n\n// 1. 错误用法：将 10 位时间戳直接传入 JS Date\nconst wrongDate = new Date(timestamp10);\nconsole.log(wrongDate.toISOString()); // \"1970-01-20T16:13:20.000Z\" (错退回 1970 年!)\n\n// 2. 正确用法：秒级乘以 1000 转换为毫秒\nconst correctDate = new Date(timestamp10 * 1000);\nconsole.log(correctDate.toISOString()); // \"2023-11-14T22:13:20.000Z\" (正确!)\n\n/* 反向错误：将 13 位毫秒时间戳传给期望秒级的后端 API，数值多乘 1000 会溢出到 55800 年！ */",{"heading":30,"paragraphs":31},"三、根因分析：运行时单位差异与位数启发式的局限",[32],"1. **运行时设计差异**：Unix API 常用秒，JavaScript `Date` 使用毫秒，日志系统还可能使用微秒或纳秒。2. **位数只适合诊断**：当前时期的秒与毫秒通常分别是 10 位和 13 位，但负数、历史日期、相对时长与远期日期都会破坏该规则。3. **单位属于数据契约**：生产代码不应靠 `1e11` 猜测；Schema、字段名或显式参数必须携带单位。",{"heading":34,"paragraphs":35},"四、推荐方案：显式时间戳单位与 BigInt 边界",[36],"1. API Schema 明确使用 `seconds`、`milliseconds`、`microseconds` 或 `nanoseconds`。2. 微秒和纳秒通过字符串或 BigInt 进入 JavaScript，避免先被 `Number` 四舍五入。3. 归一化时保留负数时间戳，并校验结果是否落在 JavaScript Date 的有效范围内。",{"heading":38,"paragraphs":39,"code":41},"五、完整代码：显式单位的时间戳归一化纯函数",[40],"下面的 TypeScript 代码不再猜测位数。调用方必须传入单位；所有整数先转为 BigInt，再安全缩放到毫秒。","type TimestampUnit =\n  | \"seconds\"\n  | \"milliseconds\"\n  | \"microseconds\"\n  | \"nanoseconds\";\n\nconst MAX_DATE_MS = 8_640_000_000_000_000n;\n\nfunction normalizeToMs(\n  input: string | number | bigint,\n  unit: TimestampUnit,\n): number {\n  if (typeof input === \"number\" && !Number.isSafeInteger(input)) {\n    throw new RangeError(\"Number 输入必须是安全整数；高精度时间戳请传字符串或 BigInt\");\n  }\n  if (typeof input === \"string\" && !/^-?\\d+$/.test(input)) {\n    throw new TypeError(\"时间戳字符串必须是十进制整数\");\n  }\n\n  const raw = BigInt(input);\n  const milliseconds = unit === \"seconds\" ? raw * 1_000n\n    : unit === \"milliseconds\" ? raw\n    : unit === \"microseconds\" ? raw / 1_000n\n    : raw / 1_000_000n;\n\n  if (milliseconds \u003C -MAX_DATE_MS || milliseconds > MAX_DATE_MS) {\n    throw new RangeError(\"时间戳超出 JavaScript Date 的有效范围\");\n  }\n  return Number(milliseconds);\n}\n\nfunction createDate(input: string | number | bigint, unit: TimestampUnit): Date {\n  return new Date(normalizeToMs(input, unit));\n}\n\nconsole.log(createDate(1_700_000_000, \"seconds\").toISOString());\nconsole.log(createDate(\"1700000000000000000\", \"nanoseconds\").toISOString());\nconsole.log(createDate(-3600, \"seconds\").toISOString());",{"heading":43,"paragraphs":44},"六、常见错误方案",[45],"盲目对所有输入做 `String(ts).length === 10` 校验（当处理小数值或包含浮点数时字符串长度判断不可靠）；在没有检查数据源单位的情况下直接在前端到处 `* 1000`。",{"heading":47,"paragraphs":48},"七、边界条件：负数、截断策略与无效日期",[49],"1970 年以前的时间戳是负数，不能一律拒绝。微秒或纳秒转毫秒时，整数除法会朝零截断；如果业务要求向下取整或保留亚毫秒精度，应在契约中另行定义，不能靠 `Date` 承载。",{"heading":51,"paragraphs":52},"八、如何验证时间戳解析正确性",[53],"为每一种单位建立相同时间点的对照向量，并覆盖 1969 年负值、纪元零点、微秒/纳秒字符串、非安全 Number 和 Date 上下界。测试应断言精确 ISO 输出与预期异常，而不是只检查年份处于宽泛区间。",{"heading":55,"paragraphs":56},"九、FAQ",[57,58,59],"问：为什么 Python `time.time()` 返回浮点数？答：Python 默认返回秒为单位的浮点数（如 `1700000000.123`），小数部分代表毫秒和微秒，前端处理时应先乘以 1000 再用 `Math.floor` 取整。","问：JavaScript `Date.now()` 会有精度丢失吗？答：不会，`Date.now()` 返回标准 Safe Integer 毫秒整数；若需要微秒级高精度计时应使用 `performance.now()`。","问：2038 年问题 (Year 2038 Problem) 对前端有影响吗？答：32 位有符号整型溢出会影响旧版 32 位 C/C++ 后端，而 JavaScript `Number` 采用 64 位 IEEE 754 双精度浮点数，可安全表示时间戳直至 275760 年。",{"heading":61,"paragraphs":62},"十、总结",[63],"弄清时间戳的物理单位（秒 vs 毫秒）是防止 1970 年与 55800 年渲染事故的关键。在 API 边界建立统一的归一化函数，能彻底消除跨语言调用的时间单位偏置 Bug。",{"title":65,"description":66,"intro":67,"sections":68},"10-Digit vs. 13-Digit Unix Timestamp Misuse: Fixing 1970 and Year 55000 Bugs","Explain second (10-digit) vs. millisecond (13-digit) Unix timestamp unit differences in JavaScript Date parsing, providing normalization helpers.","Passing Unix timestamps into `new Date(ts)` frequently produces unexpected '1970-01-01' dates or Year 55800 backend overflows. The root cause is confusing seconds (10-digit) with milliseconds (13-digit). This article details unit verification, formatting, and engineering safeguards.",[69,73,78,82,86,91,95,99,103,109],{"heading":70,"paragraphs":71},"1. Problem: rendering failures from second and millisecond unit confusion",[72],"Unix timestamps measure elapsed time since 1970-01-01 00:00:00 UTC. Systems like Python, PHP, and Go return 10-digit second timestamps (`1700000000`), whereas JavaScript `Date.now()` and Java `System.currentTimeMillis()` return 13-digit millisecond timestamps (`1700000000000`). Passing 10-digit seconds to `new Date(1700000000)` yields January 20th, 1970!",{"heading":74,"paragraphs":75,"code":77},"2. Minimal reproduction: parsing deviations across timestamp units",[76],"This comparison illustrates the physical difference between passing 10-digit seconds vs. 13-digit milliseconds into JavaScript `Date`:","/* Raw second timestamp: 1700000000 (represents 2023-11-14 22:13:20 UTC) */\nconst timestamp10 = 1700000000;\n\n// Incorrect: passing 10-digit seconds directly to JS Date\nconst wrongDate = new Date(timestamp10);\nconsole.log(wrongDate.toISOString()); // \"1970-01-20T16:13:20.000Z\" (Regresses to 1970!)\n\n// Correct: multiply seconds by 1000 to obtain milliseconds\nconst correctDate = new Date(timestamp10 * 1000);\nconsole.log(correctDate.toISOString()); // \"2023-11-14T22:13:20.000Z\" (Correct!)",{"heading":79,"paragraphs":80},"3. Root cause: runtime unit differences and fragile digit heuristics",[81],"1. **Runtime differences**: Unix APIs often use seconds, JavaScript Date uses milliseconds, and logs may use microseconds or nanoseconds. 2. **Digits are diagnostic only**: present-day seconds and milliseconds are commonly 10 and 13 digits, but negatives, historic values, durations, and far-future dates break that rule. 3. **Unit is schema data**: production code must receive the unit through the schema, field name, or an explicit parameter instead of guessing with `1e11`.",{"heading":83,"paragraphs":84},"4. Recommendation: explicit units and BigInt boundaries",[85],"1. Declare `seconds`, `milliseconds`, `microseconds`, or `nanoseconds` in the API schema. 2. Deliver microsecond and nanosecond values as strings or BigInt so they are not rounded through Number first. 3. Preserve negative timestamps and validate the normalized result against JavaScript Date's valid range.",{"heading":87,"paragraphs":88,"code":90},"5. Complete code: timestamp normalization with an explicit unit",[89],"This TypeScript code never guesses from digit count. The caller supplies a unit, and integer values are scaled through BigInt before conversion to milliseconds.","type TimestampUnit =\n  | \"seconds\"\n  | \"milliseconds\"\n  | \"microseconds\"\n  | \"nanoseconds\";\n\nconst MAX_DATE_MS = 8_640_000_000_000_000n;\n\nfunction normalizeToMs(\n  input: string | number | bigint,\n  unit: TimestampUnit,\n): number {\n  if (typeof input === \"number\" && !Number.isSafeInteger(input)) {\n    throw new RangeError(\"Number input must be a safe integer; use a string or BigInt for high precision\");\n  }\n  if (typeof input === \"string\" && !/^-?\\d+$/.test(input)) {\n    throw new TypeError(\"Timestamp strings must contain a decimal integer\");\n  }\n\n  const raw = BigInt(input);\n  const milliseconds = unit === \"seconds\" ? raw * 1_000n\n    : unit === \"milliseconds\" ? raw\n    : unit === \"microseconds\" ? raw / 1_000n\n    : raw / 1_000_000n;\n\n  if (milliseconds \u003C -MAX_DATE_MS || milliseconds > MAX_DATE_MS) {\n    throw new RangeError(\"Timestamp is outside the JavaScript Date range\");\n  }\n  return Number(milliseconds);\n}\n\nfunction createDate(input: string | number | bigint, unit: TimestampUnit): Date {\n  return new Date(normalizeToMs(input, unit));\n}\n\nconsole.log(createDate(1_700_000_000, \"seconds\").toISOString());\nconsole.log(createDate(\"1700000000000000000\", \"nanoseconds\").toISOString());\nconsole.log(createDate(-3600, \"seconds\").toISOString());",{"heading":92,"paragraphs":93},"6. Incorrect approaches",[94],"Relying naively on `String(ts).length === 10` (unreliable for floats or negative numbers). Blindly multiplying timestamps by 1000 without inspecting source schema units.",{"heading":96,"paragraphs":97},"7. Boundaries: negatives, truncation, and invalid dates",[98],"Pre-1970 timestamps are negative and must not be rejected wholesale. Integer division of microseconds or nanoseconds truncates toward zero; if the domain requires flooring or sub-millisecond precision, define that separately because Date cannot preserve it.",{"heading":100,"paragraphs":101},"8. Verification",[102],"Create equivalent vectors for every unit and cover negative 1969 values, the Unix epoch, micro/nanosecond strings, unsafe Number input, and Date boundaries. Assert exact ISO output and exact failures rather than checking only a broad year range.",{"heading":104,"paragraphs":105},"9. FAQ",[106,107,108],"Why does Python `time.time()` return floats? Python returns seconds as floating-point numbers (e.g., `1700000000.123`). Front-ends should multiply by 1000 and apply `Math.floor()`.","Does `Date.now()` suffer from precision loss? No, `Date.now()` returns standard Safe Integers; use `performance.now()` for microsecond timing.","Does the Year 2038 Problem affect JavaScript? 32-bit signed integer overflow impacts older C/C++ backends, but JS Numbers use 64-bit IEEE 754 floats, safely representing timestamps up to the year 275760.",{"heading":110,"paragraphs":111},"10. Summary",[112],"Understanding physical units (seconds vs. milliseconds) is vital to preventing 1970 and Year 55800 rendering bugs. Enforce normalization at API boundaries.",{"name":114,"url":115},"Tiny's Tool Editorial Team","https://tinystool.org/about",{"name":117,"url":115},"Tiny's Tool Technical Review","2026-08-08",[120,124],{"title":121,"url":122,"publisher":123},"RFC 3339 — Date and Time on the Internet","https://www.rfc-editor.org/rfc/rfc3339","RFC Editor",{"title":125,"url":126,"publisher":127},"ECMAScript Language Specification","https://tc39.es/ecma262/","Ecma International",false,[130,146,161],{"slug":131,"noIndex":132,"category":133,"date":7,"updatedDate":118,"reviewedDate":118,"readingMinutes":134,"tags":135,"relatedTool":14,"cn":140,"en":143},"timestamp-safari-iso-date-parsing-invalid",true,"错误排查",6,[136,137,138,139],"Safari","Date Parsing","Invalid Date","Cross-Browser",{"title":141,"description":142},"Safari 日期解析踩坑：不要把非标准 YYYY-MM-DD HH:mm:ss 交给 Date.parse","说明 JavaScript 对非标准日期字符串的解析结果由实现决定，给出带时区 ISO 输入与严格本地组件解析两条跨浏览器方案。",{"title":144,"description":145},"Safari Date Parsing: Do Not Pass Non-standard YYYY-MM-DD HH:mm:ss to Date.parse","Examine engine differences between Safari JavaScriptCore and Chrome V8 when parsing non-standard dates, providing cross-browser ISO 8601 date parsing.",{"slug":147,"noIndex":132,"category":148,"date":7,"updatedDate":118,"reviewedDate":118,"readingMinutes":134,"tags":149,"relatedTool":14,"cn":155,"en":158},"timestamp-timezone-utc-cst-dst","最佳实践",[150,151,152,153,154],"Timezone","UTC","CST","Daylight Saving","Best Practices",{"title":156,"description":157},"跨国业务中的时区难题：UTC 时间戳、CST 与夏令时 (DST) 的正确处理","厘清时间点物理存储与时区展示渲染的区别，剖析 CST 缩写多义性与夏令时 (DST) 切换陷阱，给出使用 IANA 时区名的前端格式化方案。",{"title":159,"description":160},"Timezone Realities: UTC Timestamps, CST Ambiguities, and Daylight Saving Time (DST)","Decouple physical timestamps from localized timezone rendering, addressing CST ambiguities and Daylight Saving Time shifts with IANA timezone names.",{"slug":162,"noIndex":132,"category":6,"date":7,"updatedDate":118,"reviewedDate":118,"readingMinutes":8,"tags":163,"relatedTool":169,"cn":170,"en":173},"code-diff-crlf-vs-lf-line-ending-diff",[164,165,166,167,168],"CRLF","LF","Line Endings","Git","Code Diff","/tools/dev/code-diff",{"title":171,"description":172},"CRLF 与 LF 换行符引发的全页假 Diff：原理、最小复现与 Git 配置防线","分析 Windows (CRLF, `\\r\\n`) 与 Linux/macOS (LF, `\\n`) 换行符混用引发整页文件被标记为已修改的假 Diff 原因，讲解 Git 行尾规范化方案。",{"title":174,"description":175},"CRLF vs LF Line Ending Diff: Root Causes, Minimal Reproduction, and Git Safeguards","Analyze how line ending mismatches between Windows (CRLF, `\\r\\n`) and Linux/macOS (LF, `\\n`) cause whole-file false diffs, and configure Git line ending normalization.",1786725508485]