news 2026/10/6 1:48:51

JavaScript 中比较两个 Date 对象的相等性与大小

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript 中比较两个 Date 对象的相等性与大小
  • 文档
  • 教程
  • 知识库

【免费下载链接】til

:memo: Today I Learned

项目地址:https://gitcode.com/gh_mirrors/ti/til
点击查看免费下载

在 JavaScript 里判断两个Date对象是否相等并不是一个直观的操作——即使两个对象在概念上(甚至打印出来)完全相同,直接使用===比较也往往得到false。本篇技术指南以 TIL 仓库中的 compare-the-equality-of-two-date-objects.md 为主体,讲解为什么对象比较会"失灵"、如何借助getTime()把日期转换为数字来完成可靠判断,以及<、>、<=、>=运算符为何可以直接用于日期比较,并延伸介绍与之配套的日期解析、时区与毫秒/秒陷阱。

为什么两个"一样"的 Date 对象不相等

JavaScript 中的相等性判断对"对象"有一套与基本类型完全不同的规则。对于基本类型(数字、字符串等),===比较的是值;而对于对象(包括Date实例),===比较的是引用——即两个变量是否指向内存中的同一个对象。

所以,即使两个Date对象内部携带完全相同的时刻,只要它们是通过两次独立构造产生的,就会被视为"不相等"。这是理解日期相等性比较的第一块基石:

const now = Date.now(); const today1 = new Date(now); const today2 = new Date(now); today1 === today2 // false —— 两个独立对象,引用不同

用 getTime() 将日期转换为数字再比较

要判断两个Date对象是否代表同一时刻,正确思路是先把它们转换成一个可以用值比较的东西——数字。Date.prototype.getTime()正是为此而生的:它返回该日期相对于 Unix 纪元(1970-01-01 00:00:00 UTC)的毫秒数,是一个纯数字,天然适合相等性判断。

> now = Date.now() > today1 = new Date(now) > today2 = new Date(now) > today1 === today2 false > today1.getTime() === today2.getTime() true

由于getTime()返回的是 UTC 毫秒时间戳,这种比较方式天然不受本地时区影响:只要两个日期对象指向同一时刻,无论当前机器时区如何,它们的getTime()结果都完全一致。

其他等价写法

除了显式调用getTime(),下面几种写法也能得到同样的"数字化"效果,可在不同场景下选用:

// 一元加号运算符,等价于调用 valueOf() +date1 === +date2 // 显式调用 valueOf() date1.valueOf() === date2.valueOf() // 对象转数字的隐式触发 Number(date1) === Number(date2)

Date对象的valueOf()与getTime()语义相同,都返回毫秒时间戳。需要提醒的是,这类写法在代码可读性上不如getTime()直白,团队协作时优先推荐显式写法。

比较大小:Date 对象可以直接使用 <、>、<=、>=

与相等性判断不同,Date对象可以直接使用关系运算符<、>、<=、>=来比较先后顺序:

const earlier = new Date('2024-01-01T00:00:00Z'); const later = new Date('2024-06-01T00:00:00Z'); later > earlier // true earlier < later // true earlier <= later // true later >= earlier // true

原因在于:关系运算符在遇到对象时,会先通过内部的ToPrimitive转换把对象强制转换为原始值(对Date而言优先得到数字毫秒时间戳),然后再按数字大小进行比较。因此later > earlier实际等价于later.getTime() > earlier.getTime(),比较的是时间戳数值,结果可靠且符合直觉。

区分两种情况:相等用 getTime(),大小直接用运算符

把两种场景放在一起对比,结论非常清晰:

比较目标推荐写法说明
是否相等(同一时刻)a.getTime() === b.getTime()===比较引用,必须先转为数字
是否相等(宽松)a == b(不推荐)依赖隐式转换,可读性差,容易误用
先后/大小a < b、a > b、a <= b、a >= b运算符自动完成 ToPrimitive 转换,可直接使用

务必警惕a == b这类宽松相等写法:虽然Date对象在==下会触发隐式转换从而"碰巧"能工作,但这种写法语义晦涩,也容易在与其他类型的值混用时产生意外结果,实际项目中应避免。

封装一个可复用的日期相等性函数

为了把"先转数字再比较"的细节隔离在单个入口,可以封装一个小工具函数,方便在项目各处复用:

function isSameDate(a, b) { if (!(a instanceof Date) || !(b instanceof Date)) { throw new TypeError('isSameDate expects Date instances'); } return a.getTime() === b.getTime(); } isSameDate(new Date('2024-01-01T00:00:00Z'), new Date('2024-01-01T00:00:00Z')) // true

instanceof Date的类型检查可以避免传入null、字符串等非日期值导致难以排查的NaN === NaN(恒为false)问题。

延伸:日期比较前必须绕开的三个陷阱

围绕"比较两个日期"这一主题,TIL 仓库中还记录了若干直接影响比较结果的关键细节,比较前务必核对:

1. 字符串日期可能被按 UTC 解释(ISO-8601 陷阱)

用字符串构造Date时,解析规则并不统一。仓库中的 iso-8601-formatted-dates-are-interpreted-as-utc.md 记录了这样一个事实:非 ISO-8601 格式(如'2017-12-4')按本地时区解释,而符合 ISO-8601 的格式(如'2017-12-04')按UTC解释,二者可能相差数小时、甚至"跨天"。因此在用字符串构造日期后再做比较时,要明确输入格式的时区语义。

2. 秒与毫秒:传入整数时差了一千倍

仓库中的 parse-a-date-from-a-timestamp.md 和 convert-seconds-to-date-object.md 都强调:new Date(1618499080)期望的是毫秒时间戳,而很多后端 API 返回的是秒。直接传入秒级时间戳会得到一个接近 1970 年的怪异日期,比较结果自然完全错误。正确做法是乘以1000:

new Date(1713350171 * 1000) // 2024-04-17T10:36:11.000Z

相应地,Date.now()和getTime()返回的也都是毫秒,注意保持单位一致。

3. 时间分量与日期运算的辅助函数

仓库中的 get-the-time-components-of-a-date.md 整理了getHours()、getMinutes()、getSeconds()、getMilliseconds()、getTimezoneOffset()等时间分量 API;create-future-and-past-dates-from-today.md 则演示了用setDate()/setFullYear()做日期加减运算。这些 API 常用于在比较前后对日期做归一化处理,例如把时间部分清零后再判断"是否同一天"。

替代方案:用 DayJS 等库简化比较

如果项目已经引入日期库,可以借助其封装好的比较方法省去手动转换。仓库中的 easy-date-comparison-with-dayjs.md 记录了用 DayJS 判断日期是否已过期的做法:

import dayjs from 'dayjs'; const today = dayjs(new Date()); const pastDate = dayjs("2018-10-22"); const futureDate = dayjs("2022-01-01"); console.log(pastDate.isBefore(today)); // => true console.log(futureDate.isBefore(today)); // => false

dayjs()可以从Date对象或字符串构造 DayJS 实例,再用isBefore()、isAfter()等函数直接比较。不过对于"两个日期是否相等"这种简单需求,原生getTime()已经足够,是否引入依赖可按项目实际情况权衡。

小结

  • 两个独立构造的Date对象永远不能用===判断相等,因为对象比较的是引用;
  • 判断"是否代表同一时刻"请用a.getTime() === b.getTime();
  • 判断"谁先谁后"可以直接使用<、>、<=、>=,运算符会自动把日期转换为数值时间戳;
  • 比较之前注意字符串解析的时区规则、秒/毫秒单位差异等陷阱,必要时参考 get-the-time-components-of-a-date.md、iso-8601-formatted-dates-are-interpreted-as-utc.md 与 convert-seconds-to-date-object.md 等笔记。

更多相关实践可继续阅读 TIL 仓库的 JavaScript 目录 下的日期主题笔记,例如 basic-date-formatting-without-a-library.md(用Intl.DateTimeFormat做格式化)与 easy-date-comparison-with-dayjs.md(DayJS 比较)。

  • 文档
  • 教程
  • 知识库

【免费下载链接】til

:memo: Today I Learned

项目地址:https://gitcode.com/gh_mirrors/ti/til
点击查看免费下载

相关推荐

上一篇:Grip部署实战指南:5个步骤在生产环境中搭建终极Markdown预览服务
下一篇:Symfony CLI 工具使用教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 1:45:15

Packet Tracer校园网实战:VLAN间路由与NAT出网全配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:45:01

I2C远距离通信实战:TCA9517缓冲器与双绞线布局详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:45:01

PCIe硬件设计实战:从差分信号到链路训练全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:43:41

嵌入式Linux功耗管理:PM QoS约束聚合机制与CPUIdle调优实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:41:50

Gazebo仿真中Livox雷达点云格式转换:从PointCloud2到CustomMsg实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:41:42

DP4630IY替代LTM4630IY:µModule电源模块功能级替换的工程实践与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华