【譯】你可能不需要Moment.js
Moment.js是一個很棒的時間和日期庫,具有許多牛X的方法,平時 npm install
了之後就是幹,但是如果您的Web應用程式對效能上有很高的要求,可能會由於其複雜的API和大小會導致巨大的效能上的不必要的開銷。

Moment存在的一些問題
- 它高度基於OOP API,這使得它無法使用Webpack 2 新引入的
Tree-shaking
程式碼優化技術 - 由於OOP API還有非純函式,這會導致一些bug github.com/moment/mome…
- 如果您沒有使用時區,而只使用了moment.js中的一些簡單函式,這會導致你的應用程式被引入了很多沒使用的方法,這是極其浪費效能和記憶體的。 在這裡推薦使用
dayjs
,dayjs
有一個較小的核心,並且具有非常相似的API,因此很容易從moment平滑過渡到day.js。date-fns可以使用Tree-shaking
程式碼優化技術和其他good api,因此它很適合與React,Sinon.js和webpack等好基友一起使用。
簡單比較
名字 | 大小(gzip) | 支援Tree-shaking | 名氣 | api方法數 | 模式 | 時區支援 | 支援的語言數 |
---|---|---|---|---|---|---|---|
Moment.js | 329K(69.6K) | No | 38k | 高 | OO | 非常好(moment-timezone) | 123 |
date-fns | 78.4k(13.4k) without tree-shaking | Yes | 13k | 高 | Functional | 還不支援 | 32 |
dayjs | 6.5k(2.6k) without plugins | No | 14k | 中 | OO | 還不支援 | 23 |
程式設計師吐槽
把了moment.js換成了date-fns - 構建輸出減少了40%
— Jared Farago from webnode project.
請使用JavaScript原生時間物件和陣列。 如果您因為某種原因想要用Moment.js,那麼這是一個很好的庫。 差不多。
— Dan Abramov, Author of Redux and co-author of Create React App . Building tools for humans.
我強烈建議在Moment.js上使用date-fns,它有一個更好的API,你只能包含你需要的部分!
— Matija Marohnić, a design-savvy frontend developer from Croatia.
就在昨天,在專案中將momentjs換了,我們專案體積減少了很多:scream:
— Sergey Petushkov, a javaScript developer from Moscow, Russia • Currently in Berlin, Germany.
ESLint外掛
如果你正在使用ESLint, 你可以安裝一個外掛plugin 來幫助你識別程式碼庫中你沒有(可能不需要)Moment.js的地方。
安裝這個外掛...
npm install --save-dev eslint-plugin-you-dont-need-momentjs 複製程式碼
...然後更新你的配置
"extends" : ["plugin:you-dont-need-momentjs/recommended"], 複製程式碼
使用對比
:warning:_注意提供的date-fns示例適用於[v2]( date-fns.org/v2.0.0-alph… [請參閱v1 docs]( date-fns.org/docs/Gettin…
解析
字串+日期格式化
返回從字串中解析的日期.
// Moment.js moment('12-25-1995', 'MM-DD-YYYY'); // => "1995-12-24T13:00:00.000Z" // date-fns import parse from 'date-fns/parse'; parse('12-25-1995', 'MM-dd-yyyy', new Date()); // => "1995-12-24T13:00:00.000Z" // dayjs dayjs('12-25-1995'); // => "1995-12-24T13:00:00.000Z" 複製程式碼
字串+時間格式化
返回從字串中解析的時間日期.
// Moment.js moment('2010-10-20 4:30', 'YYYY-MM-DD HH:mm'); // => "2010-10-19T17:30:00.000Z" // date-fns import parse from 'date-fns/parse'; parse('2010-10-20 4:30', 'yyyy-MM-dd H:mm', new Date()); // => "2010-10-19T17:30:00.000Z" // dayjs:x:不支援自定義格式解析 複製程式碼
字串+本地格式化
返回從字串中解析的本地化時間日期.
// Moment.js moment('2012 mars', 'YYYY MMM', 'fr'); // => "2012-02-29T13:00:00.000Z" // date-fns import parse from 'date-fns/parse'; import fr from 'date-fns/locale/fr'; parse('2012 mars', 'yyyy MMMM', new Date(), { locale: fr }); // => "2012-02-29T13:00:00.000Z" // dayjs:x:不支援自定義格式解析 複製程式碼
取值 + 賦值
毫秒 / 秒 / 分 / 時
獲取 毫秒 / 秒 / 分 / 時
。
// Moment.js moment().seconds(); // => 49 moment().hours(); // => 19 // 原生 new Date().getSeconds(); // => 49 new Date().getHours(); // => 19 // date-fns import getSeconds from 'date-fns/getSeconds'; import getHours from 'date-fns/getHours'; getSeconds(new Date()); // => 49 getHours(new Date()); // => 19 // dayjs dayjs().second(); // => 49 dayjs().hour(); // => 19 複製程式碼
設定 毫秒 / 秒 / 分 / 時
。
// Moment.js moment().seconds(30); // => "2018-09-09T09:12:30.695Z" moment().hours(13); // => "2018-09-09T03:12:49.695Z" // 原生 new Date(new Date().setSeconds(30)); // => "2018-09-09T09:12:30.695Z" new Date(new Date().setHours(13)); // => "2018-09-09T03:12:49.695Z" // date-fns import setSeconds from 'date-fns/setSeconds'; import setHours from 'date-fns/setHours'; setSeconds(new Date(), 30); // => "2018-09-09T09:12:30.695Z" setHours(new Date(), 13); // => "2018-09-09T03:12:49.695Z" // dayjs dayjs().set('second', 30); // => "2018-09-09T09:12:30.695Z" dayjs().set('hour', 13); // => "2018-09-09T03:12:49.695Z" 複製程式碼
月份日期
設定&獲取月份。
// Moment.js moment().date(); // => 9 moment().date(4); // => "2018-09-04T09:12:49.695Z" // 原生 new Date().getDate(); // => 9 new Date().setDate(4); // => "2018-09-04T09:12:49.695Z" // date-fns import getDate from 'date-fns/getDate'; import setDate from 'date-fns/setDate'; getDate(new Date()); // => 9 setDate(new Date(), 4); // => "2018-09-04T09:12:49.695Z" // dayjs dayjs().date(); // => 9 dayjs().set('date', 4); // => "2018-09-04T09:12:49.6 複製程式碼
星期幾
設定&獲取星期。
// Moment.js moment().day(); // => 0 (Sunday) moment().day(-14); // => "2018-08-26T09:12:49.695Z" // 原生 new Date().getDay(); // => 0 (Sunday) new Date().setDate(new Date().getDate() - 14); // => "2018-08-26T09:12:49.695Z" // date-fns import getDay from 'date-fns/getDay'; import setDay from 'date-fns/setDay'; getDay(new Date()); // => 0 (Sunday) setDay(new Date(), -14); // => "2018-08-26T09:12:49.695Z" // dayjs dayjs().day(); // => 0 (Sunday) dayjs().set('day', -14); // => "2018-08-26T09:12:49.695Z" 複製程式碼
一年的某一天
設定&獲取一年的某一天。
// Moment.js moment().dayOfYear(); // => 252 moment().dayOfYear(256); // => "2018-09-13T09:12:49.695Z" // date-fns import getDayOfYear from 'date-fns/getDayOfYear'; import setDayOfYear from 'date-fns/setDayOfYear'; getDayOfYear(new Date()); // => 252 setDayOfYear(new Date(), 256); // => "2018-09-13T09:12:49.695Z" // dayjs :x:不支援 複製程式碼
一年的某一週
設定&獲取一年的某一週。
// Moment.js moment().week(); // => 37 moment().week(24); // => "2018-06-10T09:12:49.695Z" // date-fns import getWeek from 'date-fns/getWeek'; import setWeek from 'date-fns/setWeek'; getWeek(new Date()); // => 37 setWeek(new Date(), 24); // => "2018-06-10T09:12:49.695Z" // dayjs :warning: requires weekOfYear plugin import weekOfYear from 'dayjs/plugin/weekOfYear'; dayjs.extend(weekOfYear); dayjs().week(); // => 37 // dayjs :x:不支援 複製程式碼
某月有多少天
獲取某月有多少天。
// Moment.js moment('2012-02', 'YYYY-MM').daysInMonth(); // => 29 // date-fns import getDaysInMonth from 'date-fns/getDaysInMonth'; getDaysInMonth(new Date(2012, 1)); // => 29 // dayjs dayjs('2012-02').daysInMonth(); // => 29 複製程式碼
一年有多少周
根據ISO周,獲取當年的週數。
// Moment.js moment().isoWeeksInYear(); // => 52 // date-fns import getISOWeeksInYear from 'date-fns/getISOWeeksInYear'; getISOWeeksInYear(new Date()); // => 52 // dayjs :x: does not support weeks in the year 複製程式碼
獲取日期最大值
返回給定日期的最大值。
const array = [ new Date(2017, 4, 13), new Date(2018, 2, 12), new Date(2016, 0, 10), new Date(2016, 0, 9), ]; // Moment.js moment.max(array.map(a => moment(a))); // => "2018-03-11T13:00:00.000Z" // 原生 new Date(Math.max.apply(null, array)).toISOString(); // => "2018-03-11T13:00:00.000Z" // date-fns import max from 'date-fns/max'; max(array); // => "2018-03-11T13:00:00.000Z" // dayjs :x:不支援 複製程式碼
獲取日期最小值
返回給定日期的最小值。
const array = [ new Date(2017, 4, 13), new Date(2018, 2, 12), new Date(2016, 0, 10), new Date(2016, 0, 9), ]; // Moment.js moment.min(array.map(a => moment(a))); // => "2016-01-08T13:00:00.000Z" // 原生 new Date(Math.min.apply(null, array)).toISOString(); // => "2016-01-08T13:00:00.000Z" // date-fns import min from 'date-fns/min'; min(array); // => "2016-01-08T13:00:00.000Z" // dayjs :x:不支援 複製程式碼
操作比較
新增天數
將指定的天數新增到給定日期。
// Moment.js moment().add(7, 'days'); // => "2018-09-16T09:12:49.695Z" // date-fns import addDays from 'date-fns/addDays'; addDays(new Date(), 7); // => "2018-09-16T09:12:49.695Z" // dayjs dayjs().add(7, 'day'); // => "2018-09-16T09:12:49.695Z" 複製程式碼
減去天數
從給定日期減去指定的天數。
// Moment.js moment().subtract(7, 'days'); // => "2018-09-02T09:12:49.695Z" // date-fns import subDays from 'date-fns/subDays'; subDays(new Date(), 7); // => "2018-09-02T09:12:49.695Z" // dayjs dayjs().subtract(7, 'day'); // => "2018-09-02T09:12:49.695Z" 複製程式碼
獲月初時間
獲取這個月初時間。
// Moment.js moment().startOf('month'); // => "2018-08-31T14:00:00.000Z" // date-fns import startOfMonth from 'date-fns/startOfMonth'; startOfMonth(new Date()); // => "2018-08-31T14:00:00.000Z" // dayjs dayjs().startOf('month'); // => "2018-08-31T14:00:00.000Z" 複製程式碼
獲取今天結束的時間
獲取今天結束的時間。
// Moment.js moment().endOf('day'); // => "2018-09-09T13:59:59.999Z" // date-fns import endOfDay from 'date-fns/endOfDay'; endOfDay(new Date()); // => "2018-09-09T13:59:59.999Z" // dayjs dayjs().endOf('day'); // => "2018-09-09T13:59:59.999Z" 複製程式碼
顯示
格式化
用給定的格式格式化給定的字串。
// Moment.js moment().format('dddd, MMMM Do YYYY, h:mm:ss A'); // => "Sunday, September 9th 2018, 7:12:49 PM" moment().format('ddd, hA'); // => "Sun, 7PM" // date-fns import format from 'date-fns/format'; format(new Date(), 'eeee, MMMM do YYYY, h:mm:ss aa'); // => "Sunday, September 9th 2018, 7:12:49 PM" format(new Date(), 'eee, ha'); // => "Sun, 7PM" // dayjs dayjs().format('dddd, MMMM D YYYY, h:mm:ss A'); // => "Sunday, September 9 2018, 7:12:49 PM" :warning:not support 9th dayjs().format('ddd, hA'); // => "Sun, 7PM" 複製程式碼
獲取到現在的年限
獲取到現在的年限
// Moment.js moment(1536484369695).fromNow(); // => "4 days ago" // date-fns import formatDistance from 'date-fns/formatDistance'; formatDistance(new Date(1536484369695), new Date(), { addSuffix: true }); // => "4 days ago" // dayjs :warning: requires relativeTime plugin import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(relativeTime); dayjs(1536484369695).fromNow(); // => "5 days ago" :warning:這個外掛的舍入方法與moment.js和date-fns不同,請謹慎使用。 複製程式碼
時差
返回兩個時間點的時差。
// Moment.js moment([2007, 0, 27]).to(moment([2007, 0, 29])); // => "in 2 days" // date-fns import formatDistance from 'date-fns/formatDistance'; formatDistance(new Date(2007, 0, 27), new Date(2007, 0, 29)); // => "2 days" // dayjs :warning: 需要relativeTime外掛 import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(relativeTime); dayjs('2007-01-27').to(dayjs('2007-01-29')); // => "in 2 days" 複製程式碼
時差(毫秒)
返回兩個時間點的毫秒級時差。
// Moment.js moment([2007, 0, 27]).diff(moment([2007, 0, 29])); // => -172800000 moment([2007, 0, 27]).diff(moment([2007, 0, 29]), 'days'); // => -2 // date-fns import differenceInMilliseconds from 'date-fns/differenceInMilliseconds'; differenceInMilliseconds(new Date(2007, 0, 27), new Date(2007, 0, 29)); // => -172800000 import differenceInDays from 'date-fns/differenceInDays'; differenceInDays(new Date(2007, 0, 27), new Date(2007, 0, 29)); // => -2 // dayjs dayjs('2007-01-27').diff(dayjs('2007-01-29'), 'milliseconds'); // => -172800000 dayjs('2007-01-27').diff(dayjs('2007-01-29'), 'days'); // => -2 複製程式碼
查詢
是否之前
檢查日期是否在另一個日期之前。
// Moment.js moment('2010-10-20').isBefore('2010-10-21'); // => true // date-fns import isBefore from 'date-fns/isBefore'; isBefore(new Date(2010, 9, 20), new Date(2010, 9, 21)); // => true // dayjs dayjs('2010-10-20').isBefore('2010-10-21'); // => true 複製程式碼
是否一樣
檢查日期是否與另一個日期相同。
// Moment.js moment('2010-10-20').isSame('2010-10-21'); // => false moment('2010-10-20').isSame('2010-10-20'); // => true moment('2010-10-20').isSame('2010-10-21', 'month'); // => true // date-fns import isSameDay from 'date-fns/isSameDay'; import isSameMonth from 'date-fns/isSameMonth'; isSameDay(new Date(2010, 9, 20), new Date(2010, 9, 21)); // => false isSameDay(new Date(2010, 9, 20), new Date(2010, 9, 20)); // => true isSameMonth(new Date(2010, 9, 20), new Date(2010, 9, 21)); // => true // dayjs dayjs('2010-10-20').isSame('2010-10-21'); // => false dayjs('2010-10-20').isSame('2010-10-20'); // => true // dayjs :x:不支援 複製程式碼
是否之後
檢查日期是否在另一個日期之後。
// Moment.js moment('2010-10-20').isAfter('2010-10-19'); // => true // date-fns import isAfter from 'date-fns/isAfter'; isAfter(new Date(2010, 9, 20), new Date(2010, 9, 19)); // => true // dayjs dayjs('2010-10-20').isAfter('2010-10-19'); // => true 複製程式碼
是否在兩個日期之前
檢查日期是否在兩個其他日期之間。
// Moment.js moment('2010-10-20').isBetween('2010-10-19', '2010-10-25'); // => true // date-fns import isWithinInterval from 'date-fns/isWithinInterval'; isWithinInterval(new Date(2010, 9, 20), { start: new Date(2010, 9, 19), end: new Date(2010, 9, 25), }); // => true // dayjs :warning: requires isBetween plugin import isBetween from 'dayjs/plugin/isBetween'; dayjs.extend(isBetween); dayjs('2010-10-20').isBetween('2010-10-19', '2010-10-25'); // => true 複製程式碼
是否是閏年
判斷是否是潤年。
// Moment.js moment([2000]).isLeapYear(); // => true // date-fns import isLeapYear from 'date-fns/isLeapYear'; isLeapYear(new Date(2000, 0, 1)); // => true // dayjs :warning: 要引入 isLeapYear 外掛 import isLeapYear from 'dayjs/plugin/isLeapYear'; dayjs.extend(isLeapYear); dayjs('2000').isLeapYear(); // => true 複製程式碼
是否是日期物件
檢查變數是否是js Date物件。
// Moment.js moment.isDate(new Date()); // => true // date-fns import isDate from 'date-fns/isDate'; isDate(new Date()); // => true // dayjs :x:不支援 複製程式碼
總結
如果你的專案不需要很複雜的時間操作 day.js
是你更好的選擇。如果較為複雜 date-fns
更適合你。