告别moment.js!用dayjs轻松搞定日期差值计算(附完整代码示例)
告别Moment.js用Day.js重塑前端日期处理体验如果你在前端开发领域摸爬滚打超过三年那么你的项目依赖列表里大概率曾出现过Moment.js的身影。这个曾经统治JavaScript日期处理领域的“巨无霸”以其强大的功能和相对友好的API成为了无数项目的标配。然而随着现代前端工程对性能、包体积的极致追求以及ES6原生Date API的逐步完善Moment.js的“重”开始变得难以承受。一个动辄200KB的库在追求首屏加载速度的今天显得有些格格不入。正是在这种背景下一个轻量、API兼容的替代品——Day.js开始走进越来越多开发者的视野。它不仅仅是一个“缩小版”的Moment更代表了一种面向未来的、更现代化的日期处理思路。本文将带你深入Day.js的世界从技术选型、核心API到实战中的日期差值计算为你提供一套完整的迁移与优化方案。1. 技术选型为什么是Day.js当我们谈论替换Moment.js时市面上其实有不少选择比如Luxon、date-fns等。但Day.js之所以能脱颖而出成为最受欢迎的替代方案其核心优势在于一个精准的定位极致的轻量与无缝的迁移。1.1 核心优势对比首先让我们通过一个直观的表格看看Day.js与Moment.js在几个关键维度上的差异特性维度Moment.jsDay.js分析与影响包体积 (gzipped)~67 KB~2 KB决定性优势。Day.js的体积仅为Moment的3%对于追求极致性能的应用如移动端、低网速环境意义重大。API 兼容性自有完整API高度兼容Moment.js API这是Day.js的“杀手锏”。大部分Moment代码可以近乎零成本迁移极大降低了替换风险和心智负担。不可变性可变对象(Mutable)不可变对象(Immutable)Moment的方法会改变原实例容易引发难以追踪的副作用。Day.js每次操作都返回新实例符合函数式编程思想更安全、更可预测。Tree Shaking支持不支持原生支持现代构建工具如Webpack、Rollup可以轻松剔除未使用的Day.js代码进一步优化最终打包体积。国际化 (i18n)内置体积大按需插件引入Moment将所有语言包打包而Day.js将i18n作为独立插件。如果你的应用只需单一语言Day.js能避免无谓的负担。性能相对较慢更快更小的代码量和更现代的实现使得Day.js在解析、格式化等常见操作上拥有性能优势。注意不可变性是Day.js一个容易被忽视但极其重要的特性。它意味着dayjs(‘2023-01-01’).add(1, ‘day’)不会改变原始的dayjs实例而是返回一个全新的、增加了1天的实例。这避免了在复杂状态管理如Redux、Vuex或React组件中因意外修改日期对象而导致的bug。1.2 适用场景与决策点那么在什么情况下你应该毫不犹豫地选择Day.js呢新项目启动毫无疑问从零开始的项目应优先考虑Day.js。轻量、现代、无历史包袱是更优的技术选型。存量项目性能优化当你的应用Bundle分析报告显示Moment.js是体积大头且对加载速度有明确要求时迁移到Day.js是性价比极高的优化手段。对不可变性有要求的场景如果你在使用React、Vue 3 Composition API等强调不可变数据流的框架Day.js的不可变性将与你的开发模式更加契合。简单的日期格式化与计算对于绝大多数只需要进行日期解析、格式化、简单加减和差值计算的业务场景Day.js的核心功能完全够用。当然如果你的项目重度依赖Moment.js某些非常小众或复杂的特性某些特定的时区处理或插件在迁移前需要仔细检查Day.js的对应插件或评估替代方案。2. 从安装到上手Day.js快速入门将Day.js引入项目非常简单其设计哲学就是“开箱即用按需扩展”。2.1 安装与引入根据你的项目构建方式选择最合适的安装方法NPM/Yarn安装推荐用于现代前端工程这是模块化开发的标准方式能很好地与构建工具配合。# 使用 npm npm install dayjs --save # 使用 yarn yarn add dayjs安装后在需要的文件中使用ES Module语法引入即可// 在ES模块化环境中 import dayjs from dayjs; // 现在就可以使用了 const today dayjs(); console.log(today.format(YYYY-MM-DD)); // 输出类似2023-10-27CDN引入适用于传统项目或快速原型如果你在写一个简单的HTML页面或不想配置构建流程可以通过CDN直接引入。script srchttps://unpkg.com/dayjs1/dayjs.min.js/script script // 引入后dayjs 会作为全局变量可用 console.log(dayjs().format(YYYY-MM-DD HH:mm:ss)); /script提示建议始终使用最新稳定版本。你可以通过npm info dayjs version查看最新版本号。新版本通常会修复已知问题并可能引入更有用的API。2.2 核心概念解析与创建Day.js对象Day.js的核心是一个包装了JavaScriptDate对象的不可变容器。创建dayjs对象有多种方式// 1. 当前时间 const now dayjs(); // 2. 解析ISO 8601格式字符串最可靠 const date1 dayjs(2023-10-27); const date2 dayjs(2023-10-27T15:00:00.000Z); // 3. 解析自定义格式字符串需要customParseFormat插件 // import customParseFormat from dayjs/plugin/customParseFormat; // dayjs.extend(customParseFormat); // const date3 dayjs(27/10/2023, DD/MM/YYYY); // 4. 从Unix时间戳毫秒创建 const date4 dayjs(1698412800000); // 5. 复制一个已有的dayjs对象 const original dayjs(2023-10-27); const copy dayjs(original); // 6. 使用JavaScript原生Date对象创建 const jsDate new Date(2023, 9, 27); // 注意月份是0-11 const date5 dayjs(jsDate);关键点dayjs()不传参时返回的是本地时间。对于从字符串解析强烈推荐使用ISO 8601格式‘YYYY-MM-DD’这是最无歧义且被广泛支持的标准格式。如果后端返回的是其他格式通常建议在后端或接口层统一转换为ISO格式前端处理起来会省心很多。3. 深入核心日期差值计算全解析日期差值计算是业务开发中的高频需求例如计算会员剩余天数、活动倒计时、两个事件间隔等。Day.js的.diff()方法提供了强大而灵活的支持。3.1.diff()方法基础用法.diff()方法的语法非常直观dayjs(日期A).diff(日期B, 单位, 浮点数)日期A被比较的日期通常是较晚的日期。日期B作为基准的日期通常是较早的日期。单位指定差值计算的单位如‘day’,‘month’,‘year’,‘hour’,‘minute’,‘second’,‘millisecond’。浮点数可选一个布尔值默认为false。为false时返回整数向下取整为true时返回浮点数。让我们看一个最直接的例子计算两个日期之间相差的天数import dayjs from dayjs; const startDate dayjs(2023-10-01); const endDate dayjs(2023-10-27); const dayDifference endDate.diff(startDate, day); console.log(dayDifference); // 输出26 // 计算月份差 const monthDifference endDate.diff(startDate, month); console.log(monthDifference); // 输出0 (因为不足一个月)3.2 处理复杂场景与边界条件在实际业务中日期数据往往不会那么“干净”。后端可能返回带有时分秒的时间戳或者你需要处理跨月、跨年的计算。Day.js配合其插件和灵活的API可以优雅地处理这些情况。场景一处理带时间的日期字符串如果后端返回‘2023-10-27 14:30:00’而我们只想比较日期部分忽略时间常见的做法是先格式化到“天”的精度。const dateWithTime dayjs(2023-10-27 14:30:00); const anotherDate dayjs(2023-10-26 09:15:00); // 方法1格式化为仅包含日期的字符串再解析 const date1Formatted dateWithTime.format(YYYY-MM-DD); const date2Formatted anotherDate.format(YYYY-MM-DD); const diffByFormat dayjs(date1Formatted).diff(dayjs(date2Formatted), day); console.log(diffByFormat); // 输出1 // 方法2使用.startOf(day)方法更优雅 // 此方法将日期对象调整到当天的开始00:00:00 const diffByStartOf dateWithTime.startOf(day).diff(anotherDate.startOf(day), day); console.log(diffByStartOf); // 输出1注意startOf(‘day’)是一个非常有用的方法它不仅能用于差值计算在需要按天进行分组、比较或存储时也经常用到。场景二计算精确的时间差包括小数有时我们需要更精确的间隔比如计算工时、计算精确的年龄等。const time1 dayjs(2023-10-27 09:00); const time2 dayjs(2023-10-27 17:30); // 计算相差的小时数浮点数 const hoursDiffExact time2.diff(time1, hour, true); console.log(hoursDiffExact); // 输出8.5 // 计算相差的分钟数 const minutesDiff time2.diff(time1, minute); console.log(minutesDiff); // 输出510场景三处理相对时间如“几天前”对于社交动态、评论时间等场景显示“3天前”、“2小时内”比显示具体日期更友好。Dayjs的RelativeTime插件可以轻松实现。// 首先安装并引入插件 // npm install dayjs // import dayjs from dayjs; import relativeTime from dayjs/plugin/relativeTime; import dayjs/locale/zh-cn; // 如需中文 dayjs.extend(relativeTime); dayjs.locale(zh-cn); // 使用中文 locale const pastDate dayjs(2023-10-20); const now dayjs(); console.log(pastDate.from(now)); // 输出7天前 console.log(now.to(pastDate)); // 输出7天后4. 实战进阶构建健壮的日期差值工具函数理解了基础API后我们可以将这些知识封装成更健壮、更易用的工具函数以便在项目中复用。下面我将展示几个在生产环境中经过考验的实用函数。4.1 核心差值计算函数这个函数增加了参数校验和更灵活的配置选项。/** * 计算两个日期之间的差值 * param {string|Date|Dayjs} dateA - 日期A * param {string|Date|Dayjs} dateB - 日期B * param {string} unit - 差值单位 (day, month, year, hour, minute, second) * param {boolean} [floatfalse] - 是否返回浮点数 * param {boolean} [absfalse] - 是否返回绝对值总是正数 * returns {number} 日期差值 */ function getDateDiff(dateA, dateB, unit day, float false, abs false) { const dayjsA dayjs(dateA); const dayjsB dayjs(dateB); // 基础校验 if (!dayjsA.isValid() || !dayjsB.isValid()) { console.error(Invalid date provided to getDateDiff function.); return NaN; } let diff dayjsA.diff(dayjsB, unit, float); // 如果需要绝对值 if (abs) { diff Math.abs(diff); } return diff; } // 使用示例 console.log(getDateDiff(2023-12-01, 2023-10-27, day)); // 35 console.log(getDateDiff(2023-10-27, 2023-12-01, day, false, true)); // 35 (总是正数) console.log(getDateDiff(2023-10-27 18:00, 2023-10-27 09:00, hour, true)); // 9.04.2 计算工作日天数排除周末这是一个更复杂的业务场景需要自定义逻辑。/** * 计算两个日期之间的工作日天数默认排除周六、周日 * param {string|Date|Dayjs} startDate - 开始日期 * param {string|Date|Dayjs} endDate - 结束日期 * param {Arraynumber} [weekendDays[0, 6]] - 代表周末的星期数0为周日6为周六 * returns {number} 工作日天数 */ function getBusinessDays(startDate, endDate, weekendDays [0, 6]) { const start dayjs(startDate).startOf(day); const end dayjs(endDate).startOf(day); // 确保开始日期不晚于结束日期 if (start.isAfter(end)) { return 0; } let businessDays 0; let current start; // 循环每一天直到结束日期 while (current.isBefore(end) || current.isSame(end, day)) { const dayOfWeek current.day(); // 获取星期几0是周日 if (!weekendDays.includes(dayOfWeek)) { businessDays; } current current.add(1, day); } return businessDays; } // 使用示例计算2023-10-23周一到2023-10-29周日之间的工作日 const workDays getBusinessDays(2023-10-23, 2023-10-29); console.log(工作日天数: ${workDays}); // 输出工作日天数: 5 (周一到周五) // 如果需要自定义周末例如周五、周六是周末 const customWeekendDays getBusinessDays(2023-10-23, 2023-10-29, [5, 6]); console.log(自定义周末后的工作日: ${customWeekendDays}); // 输出4 (周一到周四)4.3 处理时区问题的注意事项在涉及跨时区的应用中如国际化产品日期计算需要格外小心。Day.js本身不处理时区但可以通过UTC和Timezone插件来实现。// 示例使用UTC插件确保基于标准时间计算 import utc from dayjs/plugin/utc; dayjs.extend(utc); const dateInUTC dayjs.utc(2023-10-27T12:00:00Z); // 明确表示一个UTC时间 const localDate dayjs(2023-10-27T12:00:00); // 本地时间解释 console.log(dateInUTC.format()); // 2023-10-27T12:00:00Z console.log(localDate.format()); // 取决于你的本地时区例如 2023-10-27T20:00:0008:00 // 在计算涉及不同时区的日期差值时最佳实践是统一转换为UTC后再计算 const diffInHoursUTC dateInUTC.diff(dayjs.utc(2023-10-26T12:00:00Z), hour); console.log(diffInHoursUTC); // 24关键建议对于后端接口尽量传递ISO 8601格式的日期字符串并包含时区信息如‘2023-10-27T12:00:00Z’。前端在计算和展示时根据UTC插件和用户本地locale进行转换和格式化可以最大程度避免时区混乱。迁移到Day.js的过程远比想象中平滑。我在多个中大型项目中主导了从Moment.js到Day.js的迁移最大的感受不是包体积减少了多少KB而是代码因不可变性而变得更可预测以及团队在面对日期处理时心智模型的一致性。那个曾经因为moment().add(1, ‘day’)意外修改了原始变量而调试半天的下午再也不会回来了。如果你还在犹豫不妨在一个非核心模块中尝试引入Day.js从一次简单的日期格式化或差值计算开始你会很快爱上它的简洁与高效。

相关新闻

Windows 10/11下TeXLive 2021安装全攻略:从下载到第一个中文文档编译

Windows 10/11下TeXLive 2021安装全攻略:从下载到第一个中文文档编译

Windows 10/11下TeXLive 2021安装全攻略:从下载到第一个中文文档编译 每次看到别人排版精美的论文、报告或者书籍,心里是不是痒痒的?那些规整的公式、优雅的引用、自动生成的目录,背后往往站着一个强大的工具——LaTeX。对于Windo…

2026/7/4 7:24:46 阅读更多 →
GRPOConfig中num_generations参数详解:如何优化你的RLHF训练效率

GRPOConfig中num_generations参数详解:如何优化你的RLHF训练效率

GRPOConfig中num_generations参数详解:如何优化你的RLHF训练效率 最近在和一些做RLHF(基于人类反馈的强化学习)的朋友交流时,发现大家普遍对一个参数感到困惑:num_generations。这个参数在GRPOConfig里看似不起眼&…

2026/5/17 12:13:18 阅读更多 →
图解QBE语言:用Excel式界面理解数据库域演算中的示例元素(含对比SQL)

图解QBE语言:用Excel式界面理解数据库域演算中的示例元素(含对比SQL)

图解QBE语言:用Excel式界面理解数据库域演算中的示例元素(含对比SQL) 如果你用过Excel的高级筛选,或者在一个表单里通过填写几个示例值来查找数据,那么恭喜你,你已经触摸到了数据库查询语言中一个非常有趣的…

2026/7/3 3:37:17 阅读更多 →

最新新闻

5分钟掌握CSS变体管理神器:CVA终极指南

5分钟掌握CSS变体管理神器:CVA终极指南

5分钟掌握CSS变体管理神器:CVA终极指南 【免费下载链接】cva Class Variance Authority 项目地址: https://gitcode.com/gh_mirrors/cv/cva 你是否曾为UI组件的CSS类名管理而头疼?😫 面对不同尺寸、颜色、状态的按钮变体,手…

2026/7/4 8:05:14 阅读更多 →
wiliwili:专为手柄用户打造的跨平台B站客户端完全指南

wiliwili:专为手柄用户打造的跨平台B站客户端完全指南

wiliwili:专为手柄用户打造的跨平台B站客户端完全指南 【免费下载链接】wiliwili 第三方B站客户端,目前可以运行在PC全平台、PSVita、PS4 、Xbox 和 Nintendo Switch上 项目地址: https://gitcode.com/GitHub_Trending/wi/wiliwili 你是否厌倦了在…

2026/7/4 8:05:14 阅读更多 →
豆包与元宝深度对比:AI工具背后的生态能力拆解

豆包与元宝深度对比:AI工具背后的生态能力拆解

1. 这不是“选APP”,而是一场生态级能力的现场拆解你刷到这条内容时,大概率正躺在沙发上,左手握着手机,右手刚点开豆包准备扒拉一段抖音口播文案;或者刚在视频号看完一篇深度长文,顺手把链接甩进元宝&#…

2026/7/4 8:05:14 阅读更多 →
Optimus钩子(Hooks)机制详解:实现数据转换后处理的完整教程

Optimus钩子(Hooks)机制详解:实现数据转换后处理的完整教程

Optimus钩子(Hooks)机制详解:实现数据转换后处理的完整教程 【免费下载链接】optimus Optimus is an easy-to-use, reliable, and performant workflow orchestrator for data transformation, data modeling, pipelines, and data quality m…

2026/7/4 8:01:13 阅读更多 →
CANN/ge LLM集群连接API

CANN/ge LLM集群连接API

# link_clusters 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorc…

2026/7/4 8:01:13 阅读更多 →
计算机毕业设计之springboot营养配餐管理系统

计算机毕业设计之springboot营养配餐管理系统

随着当今网络的发展,时代的进步,各行各业也在发生着变化,于是网络已经逐步进入人们的生活,给我们生活或者工作提供了新的方向新的可能。 本毕业设计的内容是设计实现一个基于springboot框架的营养配餐管理系统。它是以java语言&am…

2026/7/4 7:59:12 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻