再见了,Moment.js!
2020 年 9 月 15 日,Moment.js 维护团队宣布,世界上最流行的 JavaScript 日期库之一已经停止维护。
它无需过多介绍:根据NPM 的数据,截至 2020 年 9 月,Moment.js 每周下载量超过1400 万次,并拥有超过 46000 个依赖的开源软件包。Moment.js 自 2011 年以来一直存在,但其开发者出于自身原因决定停止对其的积极支持,这些原因也包括不可变性和对“摇树优化”(tree shaking)的支持。
虽然没必要抱怨,但这的确是一个值得关注其替代方案的好理由。当然,我必须告诉你,你无需立即将所有项目都替换掉 Moment.js;如果你使用它的地方不多,可以升级,但既然现在你开始开发的项目都不应该再使用它了。
这里对几个推荐作为可行替代方案的日期库进行了概述比较。我们将重点介绍 TypeScript,因为它是一种越来越流行的语言,被很多项目所使用(我的意思是,真的有很多项目都在使用 TypeScript)。
首先,让我们创建一个非常基础的 React 应用,这样我们就可以快速启动这个项目并立即看到成果:yarn create react-app play-date --template typescript
Moment.js
让我们来看看Moment.js,看看开始使用它有多么简单(或者我应该说“曾经”有多么简单?)。
在任何项目中使用 Moment.js 之前,首先需要安装它:npm i moment或者yarn add moment
然后将其导入组件,就大功告成了:import moment from 'moment';
日期对象const test1 = new Date('2018-01-16'); // Date
首先,我们需要进行转换:const obj1 = moment(test1); // Moment
就是这样——简单明了!Moment.js 直接接收 Date 对象并将其转换为自己的对象,以便我们可以对其进行操作。
如果我们需要知道里面装的是哪一年的,那也很容易查到:obj1.year(); // number
或者计算一下从那时到现在已经过去了多少天:moment().diff(obj1, 'days'); // number
日期字符串const test2 = '2016-07-20'; // string
转换字符串:moment(test2); // Moment
Moment.js 接受字符串“原样”接收,因此您只需关注其格式即可。
虽然 Moment 没有限制字符串格式,但它可能无法识别某些乱码。
Day.js
接下来我们来看看 Moment 最接近的替代品——Day.js 。如果你曾经使用过 Moment.js,那么用 Day.js 替换它应该非常容易,虽然两者并不完全相同,但仍然值得一试。
开始使用 Day.js,只需将其添加到您的项目中即可:npm i dayjs或者yarn add dayjs
然后导入:import dayjs from 'dayjs';
即使是那些之前从未听说过 Moment 的人,前面两行文字也应该会让你觉得似曾相识。没错,它的安装和导入过程看起来确实和 Moment 一模一样。
日期对象const test1 = new Date('2018-01-16'); // Date
Day.js 可能无法完全替代 Moment.js,但它提供了非常相似的 API,并且使用了相同的概念,即将所有内容都转换为一个对象。
将其转换为:const obj1 = dayjs(test1); // Dayjs
如果我们需要知道里面装的是哪一年的,那就直接查一下:obj1.year(); // number
或者简单地计算一下从那时到现在已经过了多少天:dayjs().diff(obj1, 'day'); // number
使用 Moment.js 的好处在于,你可以计算天数或年数,也可以只计算日或年数——这完全没问题。Day.js 就做不到这一点,但另一方面,这也是拥有一个真正轻量级库所必须付出的代价。
日期字符串const test2 = '2016-07-20'; // string
我们还需要进行转换。Day.js 和 Moment.js 都能解析任何符合 ISO 8601 格式的字符串。但如果要解析其他格式的字符串,则必须提供所需的格式:dayjs(test2, 'YYYY-MM-DD'); // Dayjs
卢克森
下一位参赛者给我们一个微妙的暗示,它的核心维护者几乎与 Moment 的核心维护者相同。
按照常规步骤将Luxon添加到您的项目中:npm i luxon或者yarn add luxon
先退后一步。还记得我们决定使用 TypeScript 吗?与其他库不同,Luxon 没有自带类型定义,所以当你尝试导入它时,你的现代 IDE 应该会报错。以下是添加 TypeScript 支持的方法:npm i @types/luxon或者yarn add @types/luxon
然后您可以继续执行下一个常规步骤:import { DateTime } from 'luxon';
日期对象const test1 = new Date('2018-01-16'); // Date
如果您认为我们需要对日期进行封装(或转换)才能使用,那么您是对的:const obj1 = DateTime.fromJSDate(test1); // DateTime
与 Moment.js 不同,Luxon 不会为您提供单一的“入口点”来完成此操作。请参考其指南或使用代码自动补全功能来解析您的日期。
获取年份值:obj1.toFormat('yyyy'); // string
这里我们得到的是字符串结果,因为toFormat() 函数可以使用 token 参数返回几乎任何格式的结果。
计算自那时以来经过了多少天:DateTime.fromJSDate(new Date()).diff(obj1, 'days').as('days'); // number
语法非常努力地想要模仿 Moment.js,但它比我个人喜欢的要长得多,而且它给出的结果非常不精确。
日期字符串const test2 = '2016-07-20'; // string
我们还需要使用相应的方法进行转换。虽然如果这个字符串不是 ISO 8601 格式,我们也可以使用fromFormat() 函数,但现在我们先用fromISO() 函数:DateTime.fromISO(test2); // DateTime
日期函数
要继续添加下一个库,我们需要像往常一样添加date-fnsnpm i date-fns :或者yarn add date-fns
这里就出现了它的第一个缺点——你不能像导入 Moment.js 或 Luxon 那样导入 date-fns,date-fns 的每个函数都需要单独添加到 import 语句中,因此你无法使用代码自动补全功能。
你需要知道你需要哪个函数,或者参考它的指南来找到正确的函数:import { differenceInDays, getYear } from 'date-fns';
日期对象const test1 = new Date('2018-01-16'); // Date
这个库基于所谓的“辅助函数”,这些函数依赖于对原生 Date 对象的操作,这非常棒。因此,我们无需任何转换即可立即使用它!
让我们再花一年时间:getYear(test1); // number
然后计算一下从那时起过了多少天:differenceInDays(new Date(), test1); // number
日期字符串const test2 = '2016-07-20'; // string
遗憾的是,date-fns 无法识别字符串格式,因此要解析它,我们必须显式地提供字符串格式,但如果你的项目文档齐全且一致,这就不重要了:parse(test2, 'yyyy-MM-dd', new Date()); // Date
这里的所有代码示例都可以在 GitHub 上的 React 应用中找到。
我必须说明,这篇关于 Moment 可能替代方案的简要概述并非这些库的完整指南,也不是“我应该用什么来替代 Moment.js?”的完整列表。
如果您知道更好的工具,请在评论区分享给大家。