我构建了一个 Unix 时间戳转换器,却踩到了 3 个 JavaScript Date API 陷阱
Source: Dev.to
请提供您希望翻译的具体文本内容,我将为您翻译成简体中文。
概述
一个 API 响应返回 1709654400。
你能一眼看出那是什么日期吗?我做不到。每次需要转换 Unix 时间戳时,我都会在 Google 上搜索 “Unix Timestamp converter”,然后粘贴到在线工具中。这样的小摩擦累积起来,于是我构建了一个零点击转换器,直接在浏览器中运行。
在构建过程中,我遇到了 JavaScript 的 Date API 中的三个常见陷阱。
陷阱 1:new Date(1709654400) 返回 1970
问题
const date = new Date(1709654400);
console.log(date.toISOString());
// => "1970-01-20T21:34:14.400Z"
JavaScript 的 Date 构造函数期望的是 毫秒,而 Unix 时间戳是 秒,因此结果会偏差 1,000 倍。
解决方案
const date = new Date(1709654400 * 1000);
console.log(date.toISOString());
// => "2024-03-05T00:00:00.000Z"
为了让 UI 更加容错,我们可以通过位数自动检测单位:
function toMillis(input) {
if (/^\d{10}$/.test(input)) return Number(input) * 1000; // seconds
if (/^\d{13}$/.test(input)) return Number(input); // milliseconds
return NaN;
}
陷阱 2:连字符和斜杠的解析方式不同
问题
console.log(new Date('2024-03-05').toISOString());
// => "2024-03-05T00:00:00.000Z" (interpreted as UTC)
console.log(new Date('2024/03/05').toISOString());
// => "2024-03-04T15:00:00.000Z" (interpreted as local time, e.g., JST)
使用连字符会生成 ISO‑8601 字符串,解析时被视为 UTC;而使用斜杠会触发与地区相关的解析,将输入当作本地时间。MDN 警告说,强烈不建议使用 Date 构造函数解析非 ISO‑8601 字符串,因为会出现这种不一致。
解决方案
只接受符合 ISO‑8601 的字符串(例如 YYYY‑MM‑DD),或手动拆分各部分并使用 Date.UTC 构造日期:
function parseISODate(str) {
const [year, month, day] = str.split('-').map(Number);
return new Date(Date.UTC(year, month - 1, day));
}
Source: …
Landmine 3:时区显示迷宫
问题
const offset = new Date().getTimezoneOffset();
console.log(offset); // e.g., JST: -540
getTimezoneOffset() 返回的是相对于 UTC 的分钟数,并且符号是相反的(JST +9 小时 → ‑540 分钟)。它只能报告用户本地的时区,因此无法显示任意时区的时间。
解决方案 – Intl.DateTimeFormat
const date = new Date('2024-03-05T10:00:00Z');
const formatted = date.toLocaleString('en-US', {
timeZone: 'Asia/Tokyo',
hour12: false,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
console.log(formatted); // "03/05/2024, 19:00:00"
通过在 timeZone 选项中提供 IANA 时区标识符,你可以在不使用外部库的情况下,将同一瞬间渲染为任意地区的时间。该应用利用此方法展示了一个包含 10 个城市(UTC、JST、EST、PST、CET、GMT、IST、CST、AEST、BRT)的对比表。
前 / 后
| 功能 | 之前 | 之后 |
|---|---|---|
| 检查时间戳 | Google → 复制粘贴到在线工具 | 打开浏览器标签页;自动读取剪贴板 |
| 秒 与 毫秒 | 手动计数位数 | 自动检测;无需心算 |
| 日期字符串解析 | 信任 new Date() → 结果不一致 | 仅接受 ISO‑8601 或手动解析 |
| 时区 | 被 getTimezoneOffset() 的符号弄糊涂 | 使用带 IANA 标识符的 Intl.DateTimeFormat |
这三大坑“一旦了解就显而易见”,但如果不知情会浪费数小时。希望这能为你节省一些时间。
尝试转换器: