资讯动态

JS Tips:在 JavaScript 中简单获取 Unix 时间戳(Date.now / getTime / 一元 `+` 全解析)

发布时间:2026/10/8 8:07:36 来源:尧图企业网站定制
教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载Unix 时间戳在日志记录、接口签名、缓存过期、埋点上报等场景中无处不在。本文以 JS Tips 仓库第 49 期中文文档_posts/zh_CN/javascript/2016-02-26-extract-unix-timestamp-easily.md为核心骨架系统讲解获取当前时刻与指定日期 Unix 时间戳的多种写法、底层运行原理、时区与精度陷阱以及实战选型建议。读完本文你将掌握一套可读、可维护、可复用的时间戳获取方案并理解Date.now()、getTime()、一元操作符之间的等价关系与细微差别。一、先明确概念Unix 时间戳与 JavaScript Date 的单位Unix 时间戳Unix timestamp / Epoch time定义为自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的秒数是一个整数或含小数的实数。而 JavaScript 的Date对象在底层以毫秒为单位存储时间——Date内部保存的是自同一纪元以来的毫秒数。因此从Date相关 API 拿到的原始数值是毫秒要得到 Unix 时间戳秒必须除以 1000。这一单位差异是整篇文章所有代码里Math.floor(dateTime / 1000)一行的由来。二、获取当前时刻的 Unix 时间戳三种写法原文档给出了一组等价的写法核心套路都是先拿到毫秒值再除以 1000 取整。1.Date.now()—— 最简单直接const dateTime Date.now(); const timestamp Math.floor(dateTime / 1000);Date.now()是 ES5 引入的静态方法直接返回当前时间的毫秒值无需先构造Date实例。从实现层面可以推断相比需要 new 对象的写法它省去了对象分配的开销因此原文档称之为最简单最快的方式fastest way是有依据的——它同时做到了写法最简与路径最短。2.new Date().getTime()—— 传统等价写法const dateTime new Date().getTime(); const timestamp Math.floor(dateTime / 1000);getTime()是Date.prototype上的实例方法返回与Date.now()完全相同的毫秒值。二者的返回值等价区别仅在于new Date()先创建了一个当前时刻的实例。若要追求极致的性能与更少的对象分配优先选Date.now()在必须持有Date对象例如后续还要调用其它Date方法的场景下再用getTime()。3.new Date()—— 一元加号技巧const dateTime new Date(); const timestamp Math.floor(dateTime / 1000);这是原文档强调的一个简洁技巧在new Date()前面加一个一元操作符直接把Date对象一元化为毫秒数值省去了显式调用.getTime()。一元也适用于指定日期const dateTime new Date(2012-06-08); const timestamp Math.floor(dateTime / 1000);4. 等价但更啰嗦的变体了解即可以下写法在语义上与上述等价但由于需要额外的方法调用或解析并不推荐日常使用// 显式调用 valueOf()一元 内部最终也是走到 valueOf const timestamp Math.floor(new Date().valueOf() / 1000); // Date.parse() 只解析字符串不构造对象 const timestamp Math.floor(Date.parse(new Date().toISOString()) / 1000);其中Date.parse()更适合解析已存在的日期字符串而不是取当前时间——拿当前时间再序列化再解析绕了一圈且存在精度损耗属于反模式。5. 统一换算为什么用Math.floordateTime是毫秒除以 1000 后可能产生小数例如当前毫秒数不是整秒时。Math.floor用于向零方向取整得到秒级整数Math.floor(Date.now() / 1000); // 秒级整数 Date.now(); // 毫秒级整数精度更高若你还需要亚秒精度可直接保留毫秒值或使用Date.now() % 1000获取毫秒余数无需经过除法取整。三、获取指定日期的 Unix 时间戳1. 用字符串解析YYYY-MM-DD与YYYY-MM-DDT00:00:00Z原文档指出将yyyy-mm-dd或YYYY-MM-DDT00:00:00Z形式的字符串传给Date构造函数即可解析指定日期const dateTime new Date(2012-06-08).getTime(); const timestamp Math.floor(dateTime / 1000);两种字符串形态的差异在于时区信息YYYY-MM-DD纯日期形式。按 ECMAScript 规范的日期-时间字符串格式ISO 8601 子集date-only 形式按UTC解释即视为 UTC 当天 00:00:00。YYYY-MM-DDT00:00:00Z带T分隔符并显式声明ZUTC 时区标记含义完全确定不存在解释歧义。由于各版本规范对无时区信息的字符串处理存在差异且历史上部分运行时实现并不完全一致最稳妥的做法是显式携带时区信息Z或08:00让解析结果与运行环境无关。2. 时区陷阱同样写2012-06-08结果可能不同new Date(2012-06-08)与new Date(2012-06-08T00:00:00)带时间但无时区标记的解析基准可能不同前者按 UTC后者按本地时区解释。在非 UTC 时区如东八区下运行二者会相差 8 小时换算成秒就是 28800 秒的偏差。如果你的业务要求某天在服务器时区下的零点请务必明确时区语义否则会出现时间戳偏移的隐性 bug。3. 更可控的写法数字参数构造函数与Date.UTC()字符串解析受规范版本与运行时实现影响若要完全确定可用数字参数构造// 本地时区2012-06-08 00:00:00本地 const local new Date(2012, 5, 8); // 注意月份从 0 开始6 月是 5 const timestampLocal Math.floor(local.getTime() / 1000); // UTC2012-06-08 00:00:00 UTC与 2012-06-08T00:00:00Z 等价 const timestampUTC Math.floor(Date.UTC(2012, 5, 8) / 1000);Date.UTC()是静态方法接受与Date构造函数相同的数字参数年、月从 0 计、日、时、分、秒但始终按 UTC 计算并直接返回毫秒值无需先构造实例——这是获取某具体时刻 UTC 时间戳最无歧义的方式。四、底层原理一元、valueOf()与toNumber()原文档专门解释了new Date()的底层机制运行时调用Date对象的valueOf()方法然后一元操作符对该返回值执行toNumber()即规范中的 ToNumber 抽象操作。拆解如下new Date()产生一个Date实例一元操作符要求把操作数转为数值触发ToNumber抽象操作对对象类型ToNumber会先执行ToPrimitivehint 为number此时Date对象优先调用valueOf()Date.prototype.valueOf返回该日期自纪元以来的毫秒数数值转换完成得到毫秒值。因此new Date()、new Date().valueOf()、new Date().getTime()三者最终殊途同归返回的都是同一个毫秒数。原文档引用了 ES5 规范中的Date.prototype.valueOf、一元操作符与toNumber()相关章节读者如有兴趣可进一步查阅 ECMAScript 规范对应条目这些外部规范链接在原文档 _posts/zh_CN/javascript/2016-02-26-extract-unix-timestamp-easily.md 中有列出。五、精度与边界毫秒换算、取整方式与 Y20381.Math.floor与一元的组合是安全的Math.floor(dateTime / 1000)对任意毫秒值都成立因为毫秒值恒为正数Math.floor等价于去掉小数。这一组合不存在负数方向的问题。2. 警惕~~位运算取整Y2038 隐患部分开发者为了更快会写成~~(new Date() / 1000)用双按位非替代Math.floor。仓库内另一篇 tip_posts/zh_CN/javascript/2016-01-18-rounding-the-fast-way.md专门警告过这条路的风险~操作符会先把操作数截断为32 位有符号整数因此~~对超出 ±2^31 范围的数值会溢出回绕。Unix 时间戳恰好会踩中这个雷区当时间超过2038 年 1 月 19 日 03:14:07 UTC即著名的 Y2038 limit32 位有符号秒数上限后~~会算出完全错误的负数。该文档给出了一个 2040 年的例子epoch new Date(2040-01-01) / 1000 0.123 // - 2208988800.123 epoch_int ~~epoch // - -2085978496回绕成负数 console.log(new Date(epoch_int * 1000)) // - Wed Nov 25 1903 17:31:44 UTC // 用 Math.floor 才是正确结果 epoch_flr Math.floor(epoch) // - 2208988800 console.log(new Date(epoch_flr * 1000)) // - Sun Jan 01 2040 00:00:00 UTC结论很明确获取 Unix 时间戳请坚持用Math.floor(dateTime / 1000)不要用~~。这既是原文档的写法也规避了 32 位截断与 Y2038 风险。3. 关于性能的理性态度Date.now()不构造对象、不触发额外抽象操作理论上开销最小原文档也将其描述为最简单最快的途径。但快的程度取决于具体运行时与调用频次若在极端性能敏感的循环中大量取时间戳应以实测如performance.now()对照基准为准而不是盲目迷信某一种写法。六、实战场景与选型建议日志与埋点打点用Date.now()配合new Date().toISOString()输出人类可读时间。缓存过期 / 会话有效期秒级时间戳足够用Math.floor(Date.now() / 1000)并注意与后端约定的单位保持一致秒 vs 毫秒是常见事故源。接口签名 / 防重放需要当前时刻与指定时刻两种能力分别用Date.now()与new Date(2024-01-01T00:00:00Z).getTime()。展示层格式化拿到毫秒值后不要急着转秒new Date(ms)可以继续用于getFullYear()、getMonth()等日期分解。跨时区确定性要求高优先Date.UTC(...)或带Z的 ISO 字符串避免隐式本地时区解析。七、小结获取 Unix 时间戳在 JavaScript 中有多条等价路径本文围绕 JS Tips 第 49 期文档英文原版见 _posts/en/javascript/2016-02-26-extract-unix-timestamp-easily.md另有 西班牙语版 与 繁体中文版总结出三条准则当前时刻首选Math.floor(Date.now() / 1000)其次Math.floor(new Date().getTime() / 1000)指定日期字符串用YYYY-MM-DD或显式带Z的YYYY-MM-DDT00:00:00Z追求绝对确定用Date.UTC()底层一致new Date()的魔法来自valueOf()与一元的ToNumber转换理解原理即可放心使用但取整务必用Math.floor而非~~以远离 Y2038 位溢出陷阱。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐Android 1.6中的Date.now支持Mars中的时间戳获取实现Android 1.6中的Date.now支持Mars中的时间戳获取实现 你是否在开发移动Web应用时遇到过Android 1.6设备上时间戳获取失败的问题前端移动开发Vite-Express 高级技巧如何实现无 Vite 模式与性能优化Vite Express 高级技巧如何实现无 Vite 模式与性能优化 Vite Express 是一个将 Vite 与 Express 框架无缝集成的工具ReClip视频下载器监控告警接入Uptime Kuma服务掉线秒级通知ReClip视频下载器监控告警接入Uptime Kuma服务掉线秒级通知 ReClip 是一款轻量级、可自托管的视频下载工具支持把 YouTube、Tik音视频后端上一篇5步掌握gInkWindows上最轻量的免费屏幕标注工具完整教程下一篇如何通过Qwerty Learner快速提升英语打字效率面向程序员的终极打字练习指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑