Repository: you-dont-need/You-Dont-Need-Momentjs Branch: master Commit: 43977cf990a4 Files: 19 Total size: 78.0 KB Directory structure: gitextract_bpmimwnu/ ├── .gitignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── __tests__/ │ ├── index.js │ └── performance.js ├── docs/ │ ├── .nojekyll │ ├── README.md │ └── index.html ├── lib/ │ ├── __tests__/ │ │ └── index.js │ ├── index.js │ └── rules/ │ ├── methods.json │ ├── no-dynamic-import-moment.js │ ├── no-import-moment.js │ ├── no-moment-constructor.js │ ├── no-moment-methods.js │ └── no-require-moment.js └── package.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ node_modules .DS_Store npm-debug.log* yarn-debug.log* yarn-error.log* .vscode coverage yarn.lock .history ================================================ FILE: .prettierrc ================================================ { "singleQuote": true, "trailingComma": "es5" } ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - 12 - 13 - 14 after_success: - npm run coveralls ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 You-Dont-Need Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # [You don't (may not) need Moment.js](https://you-dont-need.github.io/You-Dont-Need-Momentjs/#/) [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://dev.to/t/momentjs) [Moment.js](https://momentjs.com/) is a fantastic time & date library with lots of great features and utilities. However, if you are working on a performance sensitive web application, it might cause a huge performance overhead because of its complex APIs and large bundle size. ![Large bundle size](./screenshot.png) Problems with Moment.js: - It is highly based on OOP APIs, which makes it fail to work with tree-shaking, thus leading to a huge bundle size and performance issues. - It is mutable and it causes bugs: - [clone](https://momentjs.com/docs/#/parsing/moment-clone/) - [How do I work around mutability in moment.js?](https://stackoverflow.com/questions/30979178/how-do-i-work-around-mutability-in-moment-js) - Complex OOP API (which doubles mutability problem). Here is an example: https://github.com/moment/moment/blob/develop/src/test/moment/add_subtract.js#L244-L286 Moment.js allows to use `a.subtract('ms', 50)`, `a.subtract(50, 'ms')` and even `a.subtract('s', '50')`. If you are not using timezone but only a few simple functions from moment.js, this might bloat your app, and therefore is considered overkill. [dayjs](https://github.com/iamkun/dayjs) has a smaller core and has very similar APIs so it makes it very easy to migrate. [date-fns](https://github.com/date-fns/date-fns) enables [tree-shaking and other benefits](https://github.com/date-fns/date-fns/issues/275#issuecomment-264934189) so that it works great with React, Sinon.js, and webpack, etc. See https://github.com/moment/moment/issues/2373 for more ideas on why and how people switch from moment.js to other solutions. ## Brief Comparison | Name | Tree-shaking | Methods richness | Pattern | Locale | Timezone Support | Popularity (stars) | Sizes | | --------- | ------------ | ---------------- | ---------- | ------ | ---------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | Moment.js | No | High | OO | 123 | Good (moment-timezone) | ![stars](https://flat.badgen.net/github/stars/moment/moment) | ![raw](https://flat.badgen.net/bundlephobia/min/moment?label=min) ![size](https://flat.badgen.net/bundlephobia/minzip/moment?label=zip&color=purple) | | Luxon | No | High | OO | - | Good (Intl) | ![stars](https://flat.badgen.net/github/stars/moment/luxon) | ![raw](https://flat.badgen.net/bundlephobia/min/luxon?label=min) ![size](https://flat.badgen.net/bundlephobia/minzip/luxon?label=zip&color=purple) | | date-fns | Yes | High | Functional | 64 | Good (date-fns-tz) | ![stars](https://flat.badgen.net/github/stars/date-fns/date-fns) | ![raw](https://flat.badgen.net/bundlephobia/min/date-fns?label=min) ![size](https://flat.badgen.net/bundlephobia/minzip/date-fns?label=zip&color=purple) | | dayjs | No | High | OO | 138 | Good (Intl) | ![stars](https://flat.badgen.net/github/stars/iamkun/dayjs) | ![raw](https://flat.badgen.net/bundlephobia/min/dayjs?label=min) ![size](https://flat.badgen.net/bundlephobia/minzip/dayjs?label=zip&color=purple) | ## Voice of Developers > [Removed moment.js to replace with date-fns - build output reduced by 40%](https://github.com/oysterprotocol/webnode/pull/116) > —Jared Farago from [webnode](https://github.com/oysterprotocol/webnode/pull/116) project. > [Good library if you’re looking to replace Moment.js for one reason or another. Immutable too.](https://twitter.com/dan_abramov/status/805030922785525760) > —Dan Abramov, Author of [Redux](https://github.com/reduxjs/redux) and co-author of [Create React App](https://github.com/facebook/create-react-app). Building tools for humans. > [I strongly recommend using date-fns over Moment.js, it's has a nicer API and you can include only parts you need!](https://twitter.com/silvenon/status/804946772690923520) > —Matija Marohnić, a design-savvy frontend developer from Croatia. ## ESLint Plugin

NPM Version Downloads Build Status Coverage Status

If you're using [ESLint](http://eslint.org/), you can install a [plugin](http://eslint.org/docs/user-guide/configuring#using-the-configuration-from-a-plugin) that will help you identify places in your codebase where you don't (may not) need Moment.js. Install the plugin... ```sh npm install --save-dev eslint-plugin-you-dont-need-momentjs ``` ...then update your config ```js "extends" : ["plugin:you-dont-need-momentjs/recommended"], ``` ## Quick Links **[Parse](#parse)** 1. [String + Date Format](#string--date-format) 1. [String + Time Format](#string--time-format) 1. [String + Format + locale](#string--format--locale) **[Get + Set](#get--set)** 1. [Millisecond/Second/Minute/Hour](#millisecond--second--minute--hour) 1. [Date of Month](#date-of-month) 1. [Day of Week](#day-of-week) 1. [Day of Year](#day-of-year) 1. [Week of Year](#week-of-year) 1. [Days in Month](#days-in-month) 1. [Weeks in Year](#weeks-in-year) 1. [Maximum of the given dates](#maximum-of-the-given-dates) 1. [Minimum of the given dates](#minimum-of-the-given-dates) **[Manipulate](#manipulate)** 1. [Add](#add) 1. [Subtract](#subtract) 1. [Start of Time](#start-of-time) 1. [End of Time](#end-of-time) **[Display](#display)** 1. [Format](#format) 1. [Time from now](#time-from-now) 1. [Time from X](#time-from-x) 1. [Difference](#difference) **[Query](#query)** 1. [Is Before](#is-before) 1. [Is Same](#is-same) 1. [Is After](#is-after) 1. [Is Between](#is-between) 1. [Is Leap Year](#is-leap-year) 1. [Is a Date](#is-a-date) # Feature Parity ⚠️ Indicates other packages or work are needed. See individual functions [above](#quick-links). | | Native | Luxon | date-fns | dayjs | Temporal | | ------------------------------ | ------ | ----- | -------- | ----- | -------- | | **Parse** | | | | | | | String + Date Format | ✅ | ✅ | ✅ | ✅ | ✅ | | String + Time Format | ✅ | ✅ | ✅ | ⚠️ | ✅ | | String + Format + locale | ❌ | ⚠️ | ✅ | ⚠️ | ❌ | | | | | | | | | **Get + Set** | | | | | | | Millisecond/Second/Minute/Hour | ✅ | ✅ | ✅ | ✅ | ✅ | | Date of Month | ✅ | ✅ | ✅ | ✅ | ✅ | | Day of Week | ✅ | ✅ | ✅ | ✅ | ✅ | | Day of Year | ✅ | ✅ | ✅ | ✅ | ✅ | | Week of Year | ✅ | ✅ | ✅ | ⚠️ | ✅ | | Days in Month | ✅ | ✅ | ✅ | ✅ | ✅ | | Weeks in Year | ❌ | ❌ | ✅ | ⚠️ | ✅ | | Maximum of the given dates | ✅ | ✅ | ✅ | ⚠️ | ✅ | | Minimum of the given dates | ✅ | ✅ | ✅ | ⚠️ | ✅ | | | | | | | | | **Manipulate** | | | | | | | Add | ✅ | ✅ | ✅ | ✅ | ✅ | | Subtract | ✅ | ✅ | ✅ | ✅ | ✅ | | Start of Time | ❌ | ✅ | ✅ | ✅ | ✅ | | End of Time | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | | | | | **Display** | | | | | | | Format | ✅ | ✅ | ✅ | ✅ | ✅ | | Time from now | ✅ | ❌ | ✅ | ⚠️ | ✅ | | Time from X | ❌ | ❌ | ✅ | ⚠️ | ✅ | | Difference | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | | | | | **Query** | | | | | | | Is Before | ✅ | ✅ | ✅ | ✅ | ✅ | | Is Same | ✅ | ✅ | ✅ | ✅ | ✅ | | Is After | ✅ | ✅ | ✅ | ✅ | ✅ | | Is Between | ❌ | ✅ | ✅ | ⚠️ | ❌ | | Is Leap Year | ✅ | ✅ | ✅ | ⚠️ | ✅ | | Is a Date | ✅ | ✅ | ✅ | ✅ | ✅ | ## Parse ### String + Date Format Return the date parsed from date string using the given format string. ```js // Moment.js moment('12-25-1995', 'MM-DD-YYYY'); // => "1995-12-24T13:00:00.000Z" // Native const datePattern = /^(\d{2})-(\d{2})-(\d{4})$/; const [, month, day, year] = datePattern.exec('12-25-1995'); new Date(`${month}, ${day} ${year}`); // => "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" // luxon DateTime.fromFormat('12-25-1995', 'MM-dd-yyyy').toJSDate(); // => "1995-12-24T13:00:00.000Z" // Temporal const datePattern = /^(\d{2})-(\d{2})-(\d{4})$/; const [, month, day, year] = datePattern.exec('12-25-1995'); new Temporal.ZonedDateTime.from({year, month, day, timeZone: Temporal.Now.timeZone()}); // => "1995-12-24T13:00:00.000Z" ``` **[⬆ back to top](#quick-links)** ### String + Time Format Return the date parsed from time string using the given format string. ```js // Moment.js moment('2010-10-20 4:30', 'YYYY-MM-DD HH:mm'); // => "2010-10-19T17:30:00.000Z" // Native const datePattern = /^(\d{4})-(\d{2})-(\d{2})\s(\d{1,2}):(\d{2})$/; const [, year, month, day, rawHour, min] = datePattern.exec('2010-10-20 4:30'); new Date(`${year}-${month}-${day}T${('0' + rawHour).slice(-2)}:${min}:00`); // => "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 ⚠️ requires customParseFormat plugin import customParseFormat from 'dayjs/plugin/customParseFormat'; dayjs.extend(customParseFormat); dayjs('2010-10-20 4:30', 'YYYY-MM-DD HH:mm'); // => "2010-10-19T17:30:00.000Z" // luxon DateTime.fromFormat('2010-10-20 4:30', 'yyyy-MM-dd H:mm').toJSDate(); // => "2010-10-19T17:30:00.000Z" // Temporal const datePattern = /^(\d{4})-(\d{2})-(\d{2})\s(\d{1,2}):(\d{2})$/; const [, year, month, day, hour, minute] = datePattern.exec('2010-10-20 4:30'); new Temporal.ZonedDateTime.from({year, month, day, hour, minute, timeZone: Temporal.Now.timeZone()}); // => "2010-10-19T17:30:00.000Z" ``` **[⬆ back to top](#quick-links)** ### String + Format + locale Return the date parsed from string using the given format string and locale. ```js // 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 ⚠️ requires customParseFormat plugin import customParseFormat from 'dayjs/plugin/customParseFormat'; import 'dayjs/locale/fr'; dayjs.extend(customParseFormat); dayjs('2012 mars', 'YYYY MMM', 'fr'); // => "2012-02-29T13:00:00.000Z" // Luxon ❌ does not support Locale for node unless https://moment.github.io/luxon/docs/manual/install.html#node DateTime.fromFormat('2012 mars', 'yyyy MMMM', { locale: 'fr' }); // => "2012-02-29T13:00:00.000Z" ``` **[⬆ back to top](#quick-links)** ## Get + Set ### Millisecond / Second / Minute / Hour Get the `Millisecond/Second/Minute/Hour` of the given date. ```js // Moment.js moment().seconds(); // => 49 moment().hours(); // => 19 // Native 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 // Luxon DateTime.local().second; // => 49 DateTime.local().hour; // => 19 // Temporal Temporal.Now.zonedDateTimeISO().second; // => 49 Temporal.Now.zonedDateTimeISO().hour; // => 19 ``` ### Performance tests | Library | Time | | -------- | ---------- | | Moment | 1500.703ms | | Native | 348.411ms | | DateFns | 520.670ms | | DayJs | 494.234ms | | Luxon | 1208.368ms | | Temporal | - | Set the `Millisecond/Second/Minute/Hour` of the given date. ```js // Moment.js moment().seconds(30); // => "2018-09-09T09:12:30.695Z" moment().hours(13); // => "2018-09-09T03:12:49.695Z" // Native 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" // luxon DateTime.utc() .set({ second: 30 }) .toJSDate(); // => "2018-09-09T09:12:30.695Z" DateTime.utc() .set({ hour: 13 }) .toJSDate(); // => "2018-09-09T03:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().with({ second: 30 }); // => "2018-09-09T09:12:30.695Z" Temporal.Now.zonedDateTimeISO().with({ hour: 13 }); // => "2018-09-09T03:12:49.695Z" ``` ### Performance tests | Library | Time | | -------- | ---------- | | Moment | 1689.744ms | | Native | 636.741ms | | DateFns | 714.148ms | | DayJs | 2037.603ms | | Luxon | 2897.571ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Date of Month Gets or sets the day of the month. ```js // Moment.js moment().date(); // => 9 moment().date(4); // => "2018-09-04T09:12:49.695Z" // Native 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.695Z" // luxon DateTime.utc().day; // => 9 DateTime.utc() .set({ day: 4 }) .toString(); // => "2018-09-04T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().day; // => 9 Temporal.Now.zonedDateTimeISO().with({ day: 4 }); // => "2018-09-04T09:12:49.695Z" ``` ### Performance tests | Library | Time | | -------- | ---------- | | Moment | 1381.669ms | | Native | 397.415ms | | DateFns | 588.004ms | | DayJs | 1218.025ms | | Luxon | 2705.606ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Day of Week Gets or sets the day of the week. ```js // Moment.js moment().day(); // => 0 (Sunday) moment().day(-14); // => "2018-08-26T09:12:49.695Z" // Native 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" // Luxon DateTime.local().weekday; // => 7 (Sunday) DateTime.local() .minus({ day: 14 }) .toJSDate(); // => "2018-08-26T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().dayOfWeek; // => 7 (Sunday) Temporal.Now.zonedDateTimeISO().subtract(Temporal.Duration.from({ days: 14 })); // => "2018-09-04T09:12:49.695Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1919.404ms | | Native | 543.466ms | | DateFns | 841.436ms | | DayJs | 1229.475ms | | Luxon | 3936.282ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Day of Year Gets or sets the day of the year. ```js // Moment.js moment().dayOfYear(); // => 252 moment().dayOfYear(256); // => "2018-09-13T09:12:49.695Z" // Native Math.floor( (new Date() - new Date(new Date().getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24 ); // => 252 // 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 ⚠️ requires dayOfYear plugin import dayOfYear from 'dayjs/plugin/dayOfYear'; dayjs.extend(dayOfYear); dayjs().dayOfYear(); // => 252 dayjs().dayOfYear(256); // => "2018-09-13T09:12:49.695Z" // Luxon DateTime.local().ordinal; // => 252 DateTime.local() .set({ ordinal: 256 }) .toString(); // => "2018-09-13T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().dayOfYear; // => 252 Temporal.Now.zonedDateTimeISO().with({month: 1, day: 1}).add(Temporal.Duration.from({days: 256})); // => "2018-09-04T09:12:49.695Z" ``` | Library | Time | | -------- | ---------- | | Moment | 5511.172ms | | Native | 530.592ms | | DateFns | 2079.043ms | | DayJs | - | | Luxon | 3540.810ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Week of Year Gets or sets the week of the year. ```js // 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" // native getWeek const day = new Date(); const MILLISECONDS_IN_WEEK = 604800000; const firstDayOfWeek = 1; // monday as the first day (0 = sunday) const startOfYear = new Date(day.getFullYear(), 0, 1); startOfYear.setDate( startOfYear.getDate() + (firstDayOfWeek - (startOfYear.getDay() % 7)) ); const dayWeek = Math.round((day - startOfYear) / MILLISECONDS_IN_WEEK) + 1; // => 37 // native setWeek const day = new Date(); const week = 24; const MILLISECONDS_IN_WEEK = 604800000; const firstDayOfWeek = 1; // monday as the first day (0 = sunday) const startOfYear = new Date(day.getFullYear(), 0, 1); startOfYear.setDate( startOfYear.getDate() + (firstDayOfWeek - (startOfYear.getDay() % 7)) ); const dayWeek = Math.round((day - startOfYear) / MILLISECONDS_IN_WEEK) + 1; day.setDate(day.getDate() - (dayWeek - week) * 7); day.toISOString(); // => "2018-06-10T09:12:49.794Z // dayjs ⚠️ requires weekOfYear plugin import weekOfYear from 'dayjs/plugin/weekOfYear'; dayjs.extend(weekOfYear); dayjs().week(); // => 37 dayjs().week(24); // => "2018-06-10T09:12:49.695Z" // Luxon DateTime.local().weekNumber; // => 37 DateTime.local() .set({ weekNumber: 23 }) .toString(); // => "2018-06-10T09:12:49.794Z // Temporal Temporal.Now.zonedDateTimeISO().weekOfYear; // => 252 Temporal.Now.zonedDateTimeISO().with({month: 1, day: 1}).add(Temporal.Duration.from({weeks: 23})); // => "2018-09-04T09:12:49.695Z" ``` | Library | Time | | -------- | ---------- | | Moment | 7147.201ms | | Native | 1371.631ms | | DateFns | 5834.815ms | | DayJs | - | | Luxon | 4514.771ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Days in Month Get the number of days in the current month. ```js // Moment.js moment('2012-02', 'YYYY-MM').daysInMonth(); // => 29 // Native new Date(2012, 02, 0).getDate(); // => 29 // date-fns import getDaysInMonth from 'date-fns/getDaysInMonth'; getDaysInMonth(new Date(2012, 1)); // => 29 // dayjs dayjs('2012-02').daysInMonth(); // => 29 // Luxon DateTime.local(2012, 2).daysInMonth; // => 29 // Temporal (new Temporal.PlainYearMonth(2012, 2)).daysInMonth // or Temporal.PlainYearMonth.from('2012-02').daysInMonth // => 29 ``` | Library | Time | | -------- | ---------- | | Moment | 4415.065ms | | Native | 186.196ms | | DateFns | 634.084ms | | DayJs | 1922.774ms | | Luxon | 1403.032ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Weeks in Year Gets the number of weeks in the current year, according to ISO weeks. ```js // Moment.js moment().isoWeeksInYear(); // => 52 // Native const year = new Date().getFullYear(); const MILLISECONDS_IN_WEEK = 604800000; const firstMondayThisYear = new Date(+year, 0, 5-(new Date(+year, 0, 4).getDay()||7)); const firstMondayNextYear = new Date(+year+1, 0, 5-(new Date(+year+1, 0, 4).getDay()||7)); (firstMondayNextYear - firstMondayThisYear) / MILLISECONDS_IN_WEEK; // => 52 // date-fns import getISOWeeksInYear from 'date-fns/getISOWeeksInYear'; getISOWeeksInYear(new Date()); // => 52 // dayjs ⚠️ requires isoWeeksInYear plugin import isoWeeksInYear from 'dayjs/plugin/isoWeeksInYear'; dayjs.extend(isoWeeksInYear); dayjs().isoWeeksInYear(); // => 52 // Luxon DateTime.local().weeksInWeekYear; // => 52 // Temporal Temporal.PlainDate.from({day:31, month:12, year: Temporal.Now.plainDateISO()}).weekOfYear // => 52 ``` | Library | Time | | -------- | ---------- | | Moment | 1065.247ms | | Native | - | | DateFns | 4954.042ms | | DayJs | - | | Luxon | 1134.483ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Maximum of the given dates Returns the maximum (most distant future) of the given date. ```js 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" // Native 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 ⚠️ requires minMax plugin import minMax from 'dayjs/plugin/minMax'; dayjs.extend(minMax); dayjs.max(array.map(a => dayjs(a))); // => "2018-03-11T13:00:00.000Z" // Luxon DateTime.max(...array.map(a => DateTime.fromJSDate(a))).toJSDate(); // => "2018-03-11T13:00:00.000Z" // Temporal Temporal.Instant.fromEpochMilliseconds(Math.max.apply(null, array)) // => "2018-03-11T13:00:00.000Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1780.075ms | | Native | 828.332ms | | DateFns | 980.938ms | | DayJs | - | | Luxon | 2694.702ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Minimum of the given dates Returns the minimum (most distant future) of the given date. ```js 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" // Native 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 ⚠️ requires minMax plugin import minMax from 'dayjs/plugin/minMax'; dayjs.extend(minMax); dayjs.min(array.map(a => dayjs(a))); // => "2016-01-08T13:00:00.000Z" // Luxon DateTime.min(...array.map(a => DateTime.fromJSDate(a))).toJSDate(); // => "2016-01-08T13:00:00.000Z" // Temporal Temporal.Instant.fromEpochMilliseconds(Math.min.apply(null, array)) // => "2018-03-11T13:00:00.000Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1744.459ms | | Native | 819.646ms | | DateFns | 841.249ms | | DayJs | - | | Luxon | 2720.462ms | | Temporal | - | **[⬆ back to top](#quick-links)** ## Manipulate ### Add Add the specified number of days to the given date. ```js // Moment.js moment().add(7, 'days'); // => "2018-09-16T09:12:49.695Z" // Native const now = new Date(); now.setDate(now.getDate() + 7); // => "Sun Sep 16 2018 09:12:49" // 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" // Luxon DateTime.local() .plus({ day: 7 }) .toJSDate(); // => "2018-09-16T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().add(Temporal.Duration.from({days: 7})); // => "2018-09-16T09:12:49.695Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1309.485ms | | Native | 259.932ms | | DateFns | 385.394ms | | DayJs | 1911.881ms | | Luxon | 3919.797ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Subtract Subtract the specified number of days from the given date. ```js // Moment.js moment().subtract(7, 'days'); // => "2018-09-02T09:12:49.695Z" // Native const now = new Date(); now.setDate(now.getDate() - 7); // => Sun Sep 09 2018 09:12:49 // 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" // Luxon DateTime.local() .minus({ day: 7 }) .toJSDate(); // => "2018-09-02T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().subtract(Temporal.Duration.from({days: 7})); // => "2018-09-02T09:12:49.695Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1278.384ms | | Native | 215.255ms | | DateFns | 379.057ms | | DayJs | 1772.593ms | | Luxon | 4028.866ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### Start of Time Return the start of a unit of time for the given date. ```js // 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" // Luxon DateTime.local().startOf('month'); // => "2018-09-02T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().with({day: 1}); // => "2018-09-01T14:00:00.000Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1078.948ms | | Native | - | | DateFns | 398.107ms | | DayJs | 765.358ms | | Luxon | 2306.765ms | | Temporal | - | **[⬆ back to top](#quick-links)** ### End of Time Return the end of a unit of time for the given date. ```js // Moment.js moment().endOf('day'); // => "2018-09-09T13:59:59.999Z" // Native const end = new Date(); end.setHours(23, 59, 59, 999); end.toISOString(); // => "2018-09-09T16: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" // Luxon DateTime.local().endOf('day'); // => "2018-09-02T09:12:49.695Z" // Temporal Temporal.Now.zonedDateTimeISO().withPlainTime(new Temporal.PlainTime(23,59,59,999,999,999)); // => "2018-09-09T16:59:59.999999999Z" ``` | Library | Time | | -------- | ---------- | | Moment | 1241.304ms | | Native | 225.519ms | | DateFns | 319.773ms | | DayJs | 914.425ms | | Luxon | 9920.529ms | | Temporal | - | **[⬆ back to top](#quick-links)** ## Display ### Format Return the formatted date string in the given format. ```js // 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" // Native new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'medium' }).format(new Date()) // => "Sunday, September 9, 2018 at 7:12:49 PM" new Intl.DateTimeFormat('en-US', { weekday: 'short', hour: 'numeric' }).format(new Date()) // => "Sun, 7 PM" // date-fns import { intlFormat } from 'date-fns' intlFormat(new Date(), { dateStyle: 'full', timeStyle: 'medium' }, { locale: 'en-US', }) // => "Sunday, September 9, 2018 at 7:12:49 PM" intlFormat(new Date(), { weekday: 'short', hour: 'numeric' }, { locale: 'en-US', }) // => "Sun, 7 PM" // dayjs dayjs().format('dddd, MMMM D YYYY, h:mm:ss A'); // => "Sunday, September 9 2018, 7:12:49 PM" dayjs().format('ddd, hA'); // => "Sun, 7PM" // dayjs ⚠️ requires advancedFormat plugin to support more format tokens import advancedFormat from 'dayjs/plugin/advancedFormat'; dayjs.extend(advancedFormat); dayjs().format('dddd, MMMM Do YYYY, h:mm:ss A'); // => "Sunday, September 9th 2018, 7:12:49 PM" // Luxon DateTime.fromMillis(time).toFormat('EEEE, MMMM dd yyyy, h:mm:ss a'); // => "Sunday, September 9 2018, 7:12:49 PM" ⚠️ not support 9th DateTime.fromMillis(time).toFormat('EEE, ha'); // => "Sun, 7PM" // Temporal new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'medium' }).format(Temporal.Now.zonedDateTimeISO()) // => "Sunday, September 9, 2018 at 7:12:49 PM" new Intl.DateTimeFormat('en-US', { weekday: 'short', hour: 'numeric' }).format(Temporal.Now.zonedDateTimeISO()) // => "Sun, 7 PM" ``` **[⬆ back to top](#quick-links)** ### Time from now Return time from now. ```js // Moment.js moment(1536484369695).fromNow(); // => "4 days ago" // Native new Intl.RelativeTimeFormat().format(-4, 'day'); // => "4 days ago" // date-fns import formatDistance from 'date-fns/formatDistance'; formatDistance(new Date(1536484369695), new Date(), { addSuffix: true }); // => "4 days ago" // dayjs ⚠️ requires relativeTime plugin import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(relativeTime); dayjs(1536484369695).fromNow(); // => "5 days ago" ⚠️ the rounding method of this plugin is different from moment.js and date-fns, use with care. // luxon requires Intl.RelativeTimeFormat DateTime.local(2022, 1, 27).toRelative({ base: this }) // => "in 4 months" // Temporal new Intl.RelativeTimeFormat().format(-4, 'day'); // => "4 days ago" ``` **[⬆ back to top](#quick-links)** ### Time from x Return time from x. ```js // 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 ⚠️ requires relativeTime plugin import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(relativeTime); dayjs('2007-01-27').to(dayjs('2007-01-29')); // => "in 2 days" // luxon ❌ does not support relative time // Temporal Temporal.PlainDate.from('2007-01-27').until('2007-01-29'); // => Temporal.Duration('P2D') ``` **[⬆ back to top](#quick-links)** ### Difference Get the unit of time between the given dates. ```js // Moment.js moment([2007, 0, 27]).diff(moment([2007, 0, 29])); // => -172800000 moment([2007, 0, 27]).diff(moment([2007, 0, 29]), 'days'); // => -2 // Native new Date(2007, 0, 27) - new Date(2007, 0, 29); // => -172800000 Math.ceil( (new Date(2007, 0, 27) - new Date(2007, 0, 29)) / 1000 / 60 / 60 / 24 ); // => -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 // luxon DateTime.local(2007, 1, 27).diff(DateTime.local(2007, 1, 29)).milliseconds; // => -172800000 DateTime.local(2007, 1, 27).diff(DateTime.local(2007, 1, 29), 'days').days; // => -2 // Temporal Temporal.PlainDate.from('2007-01-27').since('2007-01-29').total({unit: 'millisecond'}); // => -172800000 Temporal.PlainDate.from('2007-01-27').since('2007-01-29').total({unit: 'day'}); // => -2 ``` **[⬆ back to top](#quick-links)** ## Query ### Is Before Check if a date is before another date. ```js // Moment.js moment('2010-10-20').isBefore('2010-10-21'); // => true // Native new Date(2010, 10, 20) < new Date(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 // luxon DateTime.fromISO('2010-10-20') < DateTime.fromISO('2010-10-21'); // => true // Temporal Temporal.PlainDate.compare('2010-10-20', '2010-10-21') === -1; // => true ``` **[⬆ back to top](#quick-links)** ### Is Same Check if a date is the same as another date. ```js // 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 // Native new Date(2010, 9, 20).valueOf() === new Date(2010, 9, 21).valueOf(); // => false new Date(2010, 9, 20).valueOf() === new Date(2010, 9, 20).valueOf(); // => true new Date(2010, 9, 20).getTime() === new Date(2010, 9, 20).getTime(); // => true new Date(2010, 9, 20).valueOf() === new Date(2010, 9, 20).getTime(); // => true new Date(2010, 9, 20).toDateString().substring(4, 7) === new Date(2010, 9, 21).toDateString().substring(4, 7); // => 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('2010-10-20').isSame('2010-10-21', 'month'); // => true // luxon (+DateTime.fromISO('2010-10-20') === +DateTime.fromISO('2010-10-21') + // => false DateTime.fromISO('2010-10-20')) === +DateTime.fromISO('2010-10-20'); // => true DateTime.fromISO('2010-10-20').hasSame(DateTime.fromISO('2010-10-21'), 'month'); // => true // Temporal Temporal.PlainDate.from('2010-10-20').equals('2010-10-21'); // => false Temporal.PlainDate.from('2010-10-20').equals('2010-10-20'); // => true Temporal.PlainDate.from('2010-10-20').month === Temporal.PlainDate.from('2010-10-21').month; // => true ``` **[⬆ back to top](#quick-links)** ### Is After Check if a date is after another date. ```js // Moment.js moment('2010-10-20').isAfter('2010-10-19'); // => true // Native new Date(2010, 9, 20) > new Date(2010, 9, 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 // luxon DateTime.fromISO('2010-10-20') > DateTime.fromISO('2010-10-19'); // => true // Temporal Temporal.PlainDate.compare('2010-10-20', '2010-10-19') === 1; // => true ``` **[⬆ back to top](#quick-links)** ### Is Between Check if a date is between two other dates. ```js // 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 ⚠️ requires isBetween plugin import isBetween from 'dayjs/plugin/isBetween'; dayjs.extend(isBetween); dayjs('2010-10-20').isBetween('2010-10-19', '2010-10-25'); // => true // luxon Interval.fromDateTimes( DateTime.fromISO('2010-10-19'), DateTime.fromISO('2010-10-25') ).contains(DateTime.fromISO('2010-10-20')); // => true ``` **[⬆ back to top](#quick-links)** ### Is Leap Year Check if a year is a leap year. ```js // Moment.js moment([2000]).isLeapYear(); // => true // Native new Date(2000, 1, 29).getDate() === 29; // => true // date-fns import isLeapYear from 'date-fns/isLeapYear'; isLeapYear(new Date(2000, 0, 1)); // => true // dayjs ⚠️ requires isLeapYear plugin import isLeapYear from 'dayjs/plugin/isLeapYear'; dayjs.extend(isLeapYear); dayjs('2000-01-01').isLeapYear(); // => true // luxon expect(DateTime.local(2000).isInLeapYear).toBeTruthy(); // => true // Temporal Temporal.PlainDate.from('2000-01-01').inLeapYear; // => true ``` **[⬆ back to top](#quick-links)** ### Is a Date Check if a variable is a native js Date object. ```js // Moment.js moment.isDate(new Date()); // => true // Native new Date() instanceof Date; // => true // date-fns import isDate from 'date-fns/isDate'; isDate(new Date()); // => true // dayjs dayjs(new Date()).isValid(); // luxon DateTime.local().isValid; // => true // Temporal new Date() instanceof Date; Temporal.Now.plainTimeISO() instanceof Temporal.PlainTime; Temporal.Now.plainDateISO() instanceof Temporal.PlainDate; Temporal.Now.plainDateTimeISO() instanceof Temporal.PlainDateTime; Temporal.Now.zonedDateTimeISO() instanceof Temporal.ZonedDateTime; // => true ``` **[⬆ back to top](#quick-links)** # License MIT ================================================ FILE: __tests__/index.js ================================================ const moment = require('moment'); const { DateTime, Interval } = require('luxon'); const date = require('date-fns'); const fr = require('date-fns/locale/fr'); const dayjs = require('dayjs'); const relativeTime = require('dayjs/plugin/relativeTime'); // load on demand const weekOfYear = require('dayjs/plugin/weekOfYear'); // load on demand const isBetween = require('dayjs/plugin/isBetween'); // load on demand const isLeapYear = require('dayjs/plugin/isLeapYear'); // load on demand dayjs.extend(relativeTime); dayjs.extend(weekOfYear); dayjs.extend(isBetween); dayjs.extend(isLeapYear); const time = 1536484369695; describe('Parse', () => { it('String + Date Format', () => { const m = moment('12-25-1995', 'MM-DD-YYYY'); const [, mm, dd, yyyy] = /^(\d{2})-(\d{2})-(\d{4})$/.exec('12-25-1995'); const n = new Date(`${mm}, ${dd} ${yyyy}`); expect(m.valueOf()).toBe(n.getTime()); const d = date.parse('12-25-1995', 'MM-dd-yyyy', new Date()); expect(m.valueOf()).toBe(d.getTime()); const day = dayjs('12-25-1995'); expect(m.valueOf()).toBe(day.valueOf()); const luxon = DateTime.fromFormat('12-25-1995', 'MM-dd-yyyy'); expect(m.valueOf()).toBe(luxon.ts); }); it('String + Time Format', () => { const m = moment('2010-10-20 4:30', 'YYYY-MM-DD HH:mm'); const [ , yyyy, mm, dd, hh, mi, ] = /^(\d{4})-(\d{2})-(\d{2})\s(\d{1,2}):(\d{2})$/.exec('2010-10-20 4:30'); const n = new Date(`${yyyy}-${mm}-${dd}T${('0' + hh).slice(-2)}:${mi}:00`); expect(m.valueOf()).toBe(n.getTime()); const d = date.parse('2010-10-20 4:30', 'yyyy-MM-dd H:mm', new Date()); expect(m.valueOf()).toBe(d.getTime()); const luxon = DateTime.fromFormat('2010-10-20 4:30', 'yyyy-MM-dd H:mm'); expect(m.valueOf()).toBe(luxon.ts); }); it('String + Format + locale', () => { const m = moment('2012 mars', 'YYYY MMM', 'fr'); const d = date.parse('2012 mars', 'yyyy MMMM', new Date(), { locale: fr }); expect(m.valueOf()).toBe(d.getTime()); }); }); describe('Get + Set', () => { it('get Second', () => { const m = moment(time).seconds(); const n = new Date(time).getSeconds(); expect(m).toBe(n); const d = date.getSeconds(new Date(time)); expect(m).toBe(d); const day = dayjs(time).second(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).second; expect(m).toBe(luxon); }); it('set Second', () => { const m = moment(time) .seconds(30) .valueOf(); const n = new Date(time).setSeconds(30); expect(m).toBe(n); const d = date.setSeconds(new Date(time), 30).getTime(); expect(m).toBe(d); const day = dayjs(time) .set('second', 30) .valueOf(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).set({ second: 30 }); expect(m).toBe(luxon.ts); }); it('get Hour', () => { const m = moment(time).hours(); const n = new Date(time).getHours(); expect(m).toBe(n); const d = date.getHours(new Date(time)); expect(m).toBe(d); const day = dayjs(time).hour(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).hour; expect(m).toBe(luxon); }); it('set Hour', () => { const m = moment(time) .hour(13) .valueOf(); const n = new Date(time).setHours(13); expect(m).toBe(n); const d = date.setHours(new Date(time), 13).getTime(); expect(m).toBe(d); const day = dayjs(time) .set('hour', 13) .valueOf(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).set({ hour: 13 }); expect(m).toBe(luxon.ts); }); it('get Date of Month', () => { const m = moment(time).date(); const n = new Date(time).getDate(); expect(m).toBe(n); const d = date.getDate(new Date(time)); expect(m).toBe(d); const day = dayjs(time).date(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).day; expect(m).toBe(luxon); }); it('set Date of Month', () => { const m = moment(time) .date(4) .valueOf(); const n = new Date(time).setDate(4); expect(m).toBe(n); const d = date.setDate(new Date(time), 4).getTime(); expect(m).toBe(d); const day = dayjs(time) .set('date', 4) .valueOf(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).set({ day: 4 }); expect(m).toBe(luxon.ts); }); it('get Day of Week', () => { const m = moment(time).day(); const n = new Date(time).getDay(); expect(m).toBe(n); const d = date.getDay(new Date(time)); expect(m).toBe(d); const day = dayjs(time).day(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).weekday; expect(m).toBe(luxon % 7); }); it('set Day of Week', () => { const m = moment(time) .day(-14) .valueOf(); const n = new Date(time).setDate(new Date(time).getDate() - 14); expect(m).toBe(n); const d = date.setDay(new Date(time), -14).getTime(); expect(m).toBe(d); const day = dayjs(time) .set('day', -14) .valueOf(); expect(m).toBe(day); const luxon = DateTime.fromMillis(time).minus({ day: 14 }); expect(m).toBe(luxon.ts); }); it('get Day of Year', () => { const m = moment(time).dayOfYear(); const n = Math.floor( (new Date(time) - new Date(new Date(time).getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24 ); expect(m).toBe(n); const d = date.getDayOfYear(new Date(time)); expect(m).toBe(d); const luxon = DateTime.fromMillis(time).ordinal; expect(m).toBe(luxon); }); it('set Day of Year', () => { const m = moment(time) .dayOfYear(256) .valueOf(); const d = date.setDayOfYear(new Date(time), 256).getTime(); expect(m).toBe(d); const luxon = DateTime.fromMillis(time).set({ ordinal: 256 }).ts; expect(m).toBe(luxon); }); it('get Week of Year', () => { const m = moment(time).week(); const MILLISECONDS_IN_WEEK = 604800000; const firstDayOfWeek = 1; // monday as the first day (0 = sunday) const t = new Date(time); const s = new Date(t.getFullYear(), 0, 1); s.setDate(s.getDate() + ((firstDayOfWeek - s.getDay()) % 7)); const n = Math.round((t - s) / MILLISECONDS_IN_WEEK) + 1; expect(m).toBe(n); const d = date.getWeek(new Date(time)); expect(m).toBe(d); const day = dayjs(time).week(); // plugin expect(m).toBe(day); const luxon = DateTime.fromMillis(time).weekNumber + 1; expect(m).toBe(luxon); }); it('set Week of Year', () => { const MILLISECONDS_IN_WEEK = 604800000; const firstDayOfWeek = 1; // monday as the first day (0 = sunday) const m = moment(time) .week(24) .valueOf(); const n = new Date(time); const s = new Date(n.getFullYear(), 0, 1); s.setDate(s.getDate() + ((firstDayOfWeek - s.getDay()) % 7)); const w = Math.round((n - s) / MILLISECONDS_IN_WEEK) + 1; n.setDate(n.getDate() - (w - 24) * 7); const d = date.setWeek(new Date(time), 24).getTime(); expect(m).toBe(d); expect(m).toBe(n.getTime()); expect(n.getTime()).toBe(d); const luxon = DateTime.fromMillis(time).set({ weekNumber: 23 }); expect(m).toBe(luxon.ts); }); it('Days in Month', () => { const m = moment('2012-02', 'YYYY-MM').daysInMonth(); const d = date.getDaysInMonth(new Date(2012, 1)); expect(m).toBe(d); const day = dayjs('2012-02').daysInMonth(); expect(m).toBe(day); const n = new Date(2012, 2, 0).getDate(); expect(m).toBe(n); const luxon = DateTime.local(2012, 2).daysInMonth; expect(m).toBe(luxon); }); it('get Weeks In Year', () => { const m = moment(time).isoWeeksInYear(); const d = date.getISOWeeksInYear(new Date(time)); expect(m).toBe(d); const luxon = DateTime.fromMillis(time).weeksInWeekYear; expect(m).toBe(luxon); }); it('Maximum of the given dates', () => { const array = [ new Date(2017, 4, 13), new Date(2018, 2, 12), new Date(2016, 0, 10), new Date(2016, 0, 9), ]; const m = moment.max(array.map(a => moment(a))); const d = date.max(array); expect(m.valueOf()).toBe(d.getTime()); expect(d).toEqual(new Date(2018, 2, 12)); const n = new Date(Math.max.apply(null, array)); expect(n).toEqual(new Date(2018, 2, 12)); const luxon = DateTime.max( ...array.map(a => DateTime.fromJSDate(a)) ).toJSDate(); expect(luxon).toEqual(new Date(2018, 2, 12)); }); it('Minimum of the given dates', () => { const array = [ new Date(2017, 4, 13), new Date(2018, 2, 12), new Date(2016, 0, 10), new Date(2016, 0, 9), ]; const n = new Date(Math.min.apply(null, array)); expect(n).toEqual(new Date(2016, 0, 9)); const m = moment.min(array.map(a => moment(a))); const d = date.min(array); expect(m.valueOf()).toBe(d.getTime()); expect(d).toEqual(new Date(2016, 0, 9)); const luxon = DateTime.min( ...array.map(a => DateTime.fromJSDate(a)) ).toJSDate(); expect(luxon).toEqual(new Date(2016, 0, 9)); }); }); describe('Manipulate', () => { it('Add', () => { const m = moment(time).add(7, 'days'); const d = date.addDays(new Date(time), 7); expect(m.valueOf()).toBe(d.getTime()); const n = new Date(time); n.setDate(n.getDate() + 7); expect(n.valueOf()).toBe(m.valueOf()); const day = dayjs(time).add(7, 'day'); expect(m.valueOf()).toBe(day.valueOf()); const luxon = DateTime.fromMillis(time).plus({ day: 7 }); expect(m.valueOf()).toBe(luxon.ts); }); it('Subtract', () => { const m = moment(time).subtract(7, 'days'); const n = new Date(new Date(time).getTime() - 1000 * 60 * 60 * 24 * 7); expect(n.valueOf()).toBe(m.valueOf()); const d = date.subDays(new Date(time), 7); expect(m.valueOf()).toBe(d.getTime()); const day = dayjs(time).subtract(7, 'day'); expect(m.valueOf()).toBe(day.valueOf()); const luxon = DateTime.fromMillis(time).minus({ day: 7 }); expect(m.valueOf()).toBe(luxon.ts); }); it('Start of Time', () => { const m = moment(time).startOf('month'); const d = date.startOfMonth(new Date(time)); expect(m.valueOf()).toBe(d.getTime()); const day = dayjs(time).startOf('month'); expect(m.valueOf()).toBe(day.valueOf()); const luxon = DateTime.fromMillis(time).startOf('month'); expect(m.valueOf()).toBe(luxon.ts); }); it('End of Time', () => { const m = moment(time).endOf('day'); const n = new Date(time).setHours(23, 59, 59, 999); expect(m.valueOf()).toBe(n); const d = date.endOfDay(new Date(time)); expect(m.valueOf()).toBe(d.getTime()); const day = dayjs(time).endOf('day'); expect(m.valueOf()).toBe(day.valueOf()); const luxon = DateTime.fromMillis(time).endOf('day'); expect(m.valueOf()).toBe(luxon.ts); }); }); describe('Display', () => { it('Format', () => { const m = moment(time).format('dddd, MMMM D YYYY, h:mm:ss A'); const d = date.format(new Date(time), 'eeee, MMMM d yyyy, h:mm:ss aa', { awareOfUnicodeTokens: true, }); const day = dayjs(time).format('dddd, MMMM D YYYY, h:mm:ss A'); const l = DateTime.fromMillis(time).toFormat( 'EEEE, MMMM d yyyy, h:mm:ss a' ); expect(m).toBe(d); expect(m).toBe(day); expect(m).toBe(l); const m2 = moment(time).format('ddd, hA'); const d2 = date.format(new Date(time), 'eee, ha'); const day2 = dayjs(time).format('ddd, hA'); const l2 = DateTime.fromMillis(time).toFormat('EEE, ha'); expect(m2).toBe(d2); expect(m2).toBe(day2); expect(m2).toBe(l2); }); it('Time from now', () => { const month3 = 1000 * 3600 * 24 * 30 * 3; // ms * hour * day * month * 3 const timeDistance = new Date().getTime() - month3; moment.relativeTimeThreshold( 'd', new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate() ); const m = moment(timeDistance).fromNow(); const n = new Intl.RelativeTimeFormat().format(-3, 'month'); const d = date.formatDistanceStrict(new Date(timeDistance), new Date(), { addSuffix: true, }); const day = dayjs(timeDistance).fromNow(); // plugin expect(m).toBe(d); expect(m).toBe(day); expect(m).toBe(n); }); it('Time from X', () => { const m = moment([2007, 0, 27]).to(moment([2007, 0, 29])); const d = date.formatDistance(new Date(2007, 0, 27), new Date(2007, 0, 29)); const day = dayjs('2007-01-27').to(dayjs('2007-01-29')); expect(m).toContain(d); expect(m).toBe(day); }); it('Difference', () => { const m = moment([2007, 0, 27]).diff(moment([2007, 0, 29])); const n = new Date(2007, 0, 27) - new Date(2007, 0, 29); const d = date.differenceInMilliseconds( new Date(2007, 0, 27), new Date(2007, 0, 29) ); const day = dayjs('2007-01-27').diff(dayjs('2007-01-29'), 'milliseconds'); const luxon = DateTime.local(2007, 1, 27).diff(DateTime.local(2007, 1, 29)) .milliseconds; expect(m).toBe(d); expect(m).toBe(day); expect(n).toBe(d); expect(n).toBe(m); expect(n).toBe(day); expect(n).toBe(luxon); const m2 = moment([2007, 0, 27]).diff(moment([2007, 0, 29]), 'days'); const n2 = Math.ceil( (new Date(2007, 0, 27) - new Date(2007, 0, 29)) / 1000 / 60 / 60 / 24 ); const d2 = date.differenceInDays( new Date(2007, 0, 27), new Date(2007, 0, 29) ); const day2 = dayjs('2007-01-27').diff(dayjs('2007-01-29'), 'days'); const luxon2 = DateTime.local(2007, 1, 27).diff( DateTime.local(2007, 1, 29), 'days' ).days; expect(m2).toBe(d2); expect(m2).toBe(day2); expect(n2).toBe(m2); expect(n2).toBe(d2); expect(n2).toBe(day2); expect(n2).toBe(luxon2); }); }); describe('Query', () => { it('Is Before', () => { const m = moment('2010-10-20').isBefore('2010-10-21'); const n = new Date(2010, 10, 20) < new Date(2010, 10, 21); const d = date.isBefore(new Date(2010, 9, 20), new Date(2010, 9, 21)); const day = dayjs('2010-10-20').isBefore('2010-10-21'); //plugin const luxon = DateTime.fromISO('2010-10-20') < DateTime.fromISO('2010-10-21'); expect(m).toBeTruthy(); expect(d).toBeTruthy(); expect(day).toBeTruthy(); expect(n).toBeTruthy(); expect(luxon).toBeTruthy(); }); it('Is Same', () => { expect(moment('2010-10-20').isSame('2010-10-21')).toBeFalsy(); expect(new Date(2010, 9, 20) === new Date(2010, 9, 21)).toBeFalsy(); expect( date.isSameDay(new Date(2010, 9, 20), new Date(2010, 9, 21)) ).toBeFalsy(); expect(dayjs('2010-10-20').isSame('2010-10-21')).toBeFalsy(); expect( +DateTime.fromISO('2010-10-20') === +DateTime.fromISO('2010-10-21') ).toBeFalsy(); expect(moment('2010-10-20').isSame('2010-10-21', 'month')).toBeTruthy(); expect( new Date(2010, 9, 20).valueOf() === new Date(2010, 9, 20).valueOf() ).toBeTruthy(); expect( new Date(2010, 9, 20).getTime() === new Date(2010, 9, 20).getTime() ).toBeTruthy(); expect( new Date(2010, 9, 20).valueOf() === new Date(2010, 9, 20).getTime() ).toBeTruthy(); expect( new Date(2010, 9, 20).toDateString().substring(4, 7) === new Date(2010, 9, 21).toDateString().substring(4, 7) ).toBeTruthy(); expect( date.isSameMonth(new Date(2010, 9, 20), new Date(2010, 9, 21)) ).toBeTruthy(); expect( DateTime.fromISO('2010-10-20').hasSame( DateTime.fromISO('2010-10-21'), 'month' ) ).toBeTruthy(); }); it('Is After', () => { const m = moment('2010-10-20').isAfter('2010-10-19'); const n = new Date(2010, 10, 20) > new Date(2010, 10, 19); const d = date.isAfter(new Date(2010, 9, 20), new Date(2010, 9, 19)); const day = dayjs('2010-10-20').isAfter('2010-10-19'); const luxon = DateTime.fromISO('2010-10-20') > DateTime.fromISO('2010-10-19'); expect(m).toBeTruthy(); expect(n).toBeTruthy(); expect(d).toBeTruthy(); expect(day).toBeTruthy(); expect(luxon).toBeTruthy(); }); it('Is Between', () => { const m = moment('2010-10-20').isBetween('2010-10-19', '2010-10-25'); const d = date.isWithinInterval(new Date(2010, 9, 20), { start: new Date(2010, 9, 19), end: new Date(2010, 9, 25), }); const day = dayjs('2010-10-20').isBetween('2010-10-19', '2010-10-25'); //plugin const luxon = Interval.fromDateTimes( DateTime.fromISO('2010-10-19'), DateTime.fromISO('2010-10-25') ).contains(DateTime.fromISO('2010-10-20')); expect(m).toBeTruthy(); expect(d).toBeTruthy(); expect(day).toBeTruthy(); expect(luxon).toBeTruthy(); }); it('Is Leap Year', () => { expect(moment([2000]).isLeapYear()).toBeTruthy(); expect(moment([2001]).isLeapYear()).toBeFalsy(); expect(new Date(2000, 1, 29).getDate() === 29).toBeTruthy(); expect(date.isLeapYear(new Date(2000, 0, 1))).toBeTruthy(); expect(date.isLeapYear(new Date(2001, 0, 1))).toBeFalsy(); expect(dayjs('2000-01-01').isLeapYear()).toBeTruthy(); expect(dayjs('2001-01-01').isLeapYear()).toBeFalsy(); expect(DateTime.local(2000).isInLeapYear).toBeTruthy(); expect(DateTime.local(2001).isInLeapYear).toBeFalsy(); }); it('Is a Date', () => { expect(moment.isDate(new Date())).toBeTruthy(); expect(new Date() instanceof Date).toBeTruthy(); expect(date.isDate(new Date())).toBeTruthy(); expect(dayjs.isDayjs(dayjs())).toBeTruthy(); expect(DateTime.local().isValid).toBeTruthy(); }); }); ================================================ FILE: __tests__/performance.js ================================================ const moment = require('moment'); const { getSeconds, getHours, setHours, endOfDay, startOfMonth, setSeconds, max, min, getDate, addDays, subDays, setDate, getDay, setDay, getISOWeeksInYear, getDayOfYear, setDayOfYear, setWeek, getWeek, getDaysInMonth, } = require('date-fns'); const dayjs = require('dayjs'); const { DateTime } = require('luxon'); const iterations = 1000000; const array = [ new Date(2017, 4, 13), new Date(2018, 2, 12), new Date(2016, 0, 10), new Date(2016, 0, 9), ]; const performanceTest = (type, testFunction) => { console.time(type); for (let i = 0; i < iterations; i++) { testFunction(); } console.timeEnd(type); }; const runTests = object => { for (const key in object) { if (typeof object[key] === 'function') { object[key](); } } }; const Get = { moment: () => { performanceTest('Moment', () => { moment().seconds(); moment().hours(); }); }, native: () => { performanceTest('Native', () => { new Date().getSeconds(); new Date().getHours(); }); }, dateFns: () => { performanceTest('DateFns', () => { getSeconds(new Date()); getHours(new Date()); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().second(); dayjs().hour(); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().second; DateTime.local().hour; }); }, }; // runTests(Get); const Set = { moment: () => { performanceTest('Moment', () => { moment().seconds(30); moment().hours(13); }); }, native: () => { performanceTest('Native', () => { new Date(new Date().setSeconds(30)); new Date(new Date().setHours(13)); }); }, dateFns: () => { performanceTest('DateFns', () => { setSeconds(new Date(), 30); setHours(new Date(), 13); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().set('second', 30); dayjs().set('hour', 13); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.utc().set({ second: 30 }); DateTime.utc().set({ hour: 13 }); }); }, }; // runTests(Set); const DateOfMonth = { moment: () => { performanceTest('Moment', () => { moment().date(); moment().date(4); }); }, native: () => { performanceTest('Native', () => { new Date().getDate(); new Date().setDate(4); }); }, dateFns: () => { performanceTest('DateFns', () => { getDate(new Date()); setDate(new Date(), 4); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().date(); dayjs().set('date', 4); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().day; DateTime.local().set({ day: 4 }); }); }, }; // runTests(DateOfMonth); const DayOfWeek = { moment: () => { performanceTest('Moment', () => { moment().day(); moment().day(-14); }); }, native: () => { performanceTest('Native', () => { new Date().getDay(); new Date().setDate(new Date().getDate() - 14); }); }, dateFns: () => { performanceTest('DateFns', () => { getDay(new Date()); setDay(new Date(), -14); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().day(); dayjs().set('day', -14); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().weekday; DateTime.local().set({ weekday: -14 }); }); }, }; // runTests(DayOfWeek); const DayOfYear = { moment: () => { performanceTest('Moment', () => { moment().dayOfYear(); moment().dayOfYear(256); }); }, native: () => { performanceTest('Native', () => { Math.floor( (new Date() - new Date(new Date().getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24 ); }); }, dateFns: () => { performanceTest('DateFns', () => { getDayOfYear(new Date()); setDayOfYear(new Date(), 256); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().ordinal; DateTime.local().set({ ordinal: 256 }); }); }, }; // runTests(DayOfYear); const WeekOfYear = { moment: () => { performanceTest('Moment', () => { moment().week(); moment().week(24); }); }, native: () => { performanceTest('Native', () => { const MILLISECONDS_IN_WEEK = 604800000; const firstDayOfWeek = 1; const t = new Date(); const s = new Date(t.getFullYear(), 0, 1); s.setDate(s.getDate() + ((firstDayOfWeek - s.getDay()) % 7)); Math.round((t - s) / MILLISECONDS_IN_WEEK) + 1; const d = new Date(); const f = new Date(d.getFullYear(), 0, 1); f.setDate(f.getDate() + ((firstDayOfWeek - f.getDay()) % 7)); d.setDate( d.getDate() - (Math.round((d - f) / MILLISECONDS_IN_WEEK) + 1 - 24) * 7 ); }); }, dateFns: () => { performanceTest('DateFns', () => { getWeek(new Date()); setWeek(new Date(), 24); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().weekYear; DateTime.local().set({ weekYear: 24 }); }); }, }; // runTests(WeekOfYear); const DaysInMonth = { moment: () => { performanceTest('Moment', () => { moment('2012-02', 'YYYY-MM').daysInMonth(); }); }, native: () => { performanceTest('Native', () => { new Date(2012, 2, 0).getDate(); }); }, dateFns: () => { performanceTest('DateFns', () => { getDaysInMonth(new Date(2012, 2)); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs('2012-02').daysInMonth(); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local(2012, 2).day; }); }, }; // runTests(DaysInMonth); const WeeksInYear = { moment: () => { performanceTest('Moment', () => { moment().isoWeeksInYear(); }); }, dateFns: () => { performanceTest('DateFns', () => { getISOWeeksInYear(new Date()); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().weeksInWeekYear; }); }, }; // runTests(WeeksInYear); const MaximumOfGivenDates = { moment: () => { performanceTest('Moment', () => { moment.max(array.map(a => moment(a))); }); }, native: () => { performanceTest('Native', () => { new Date(Math.max.apply(null, array)).toISOString(); }); }, dateFns: () => { performanceTest('DateFns', () => { max(array); }); }, luxon: () => { performanceTest('Luxon', () => { const dates = array.map(a => DateTime.fromJSDate(a)); DateTime.max(...dates); }); }, }; // runTests(MaximumOfGivenDates); const MinimumOfGivenDates = { moment: () => { performanceTest('Moment', () => { moment.min(array.map(a => moment(a))); }); }, native: () => { performanceTest('Native', () => { new Date(Math.min.apply(null, array)).toISOString(); }); }, dateFns: () => { performanceTest('DateFns', () => { min(array); }); }, luxon: () => { performanceTest('Luxon', () => { const dates = array.map(a => DateTime.fromJSDate(a)); DateTime.min(...dates); }); }, }; // runTests(MinimumOfGivenDates); const Add = { moment: () => { performanceTest('Moment', () => { moment().add(7, 'days'); }); }, native: () => { performanceTest('Native', () => { const now = new Date(); now.setDate(now.getDate() + 7); }); }, dateFns: () => { performanceTest('DateFns', () => { addDays(new Date(), 7); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().add(7, 'day'); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().plus({ day: 7 }); }); }, }; // runTests(Add); const Subtract = { moment: () => { performanceTest('Moment', () => { moment().subtract(7, 'days'); }); }, native: () => { performanceTest('Native', () => { new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 7); }); }, dateFns: () => { performanceTest('DateFns', () => { subDays(new Date(), 7); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().subtract(7, 'day'); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().minus({ day: 7 }); }); }, }; // runTests(Subtract); const StartOfTime = { moment: () => { performanceTest('Moment', () => { moment().startOf('month'); }); }, dateFns: () => { performanceTest('DateFns', () => { startOfMonth(new Date()); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().startOf('month'); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().startOf('month'); }); }, }; // runTests(StartOfTime); const EndOfTime = { moment: () => { performanceTest('Moment', () => { moment().endOf('day'); }); }, native: () => { performanceTest('Native', () => { new Date().setHours(23, 59, 59, 999); }); }, dateFns: () => { performanceTest('DateFns', () => { endOfDay(new Date()); }); }, dayJs: () => { performanceTest('DayJs', () => { dayjs().endOf('day'); }); }, luxon: () => { performanceTest('Luxon', () => { DateTime.local().endOf('day'); }); }, }; // runTests(EndOfTime); ================================================ FILE: docs/.nojekyll ================================================ ================================================ FILE: docs/README.md ================================================ [remoteMarkdownUrl](https://raw.githubusercontent.com/you-dont-need/You-Dont-Need-Momentjs/master/README.md) ================================================ FILE: docs/index.html ================================================ You don't (may not) need Moment.js
================================================ FILE: lib/__tests__/index.js ================================================ const rule = require('../').rules; const RuleTester = require('eslint').RuleTester; RuleTester.setDefaultConfig({ parser: 'babel-eslint', parserOptions: { ecmaVersion: 6, sourceType: 'module', }, }); var ruleTester = new RuleTester(); describe('ESLint plugin', () => { ruleTester.run('no-dynamic-import-moment', rule['no-dynamic-import-moment'], { valid: ["import('date-fns').then()"], invalid: [ { code: "import('moment').then(()=>{})", errors: [ { message: 'Use date-fns or Native Date methods instead of moment.js', type: 'CallExpression', }, ], }, { code: "(async () => { const m = await import('moment'); })()", errors: [ { message: 'Use date-fns or Native Date methods instead of moment.js', type: 'CallExpression', }, ], }, ], }); ruleTester.run('no-import-moment', rule['no-import-moment'], { valid: [ "import { format, formatDistance, formatRelative, subDays } from 'date-fns'", ], invalid: [ { code: "import moment from 'moment'", errors: [ { message: 'Use date-fns or Native Date methods instead of moment.js', type: 'ImportDeclaration', }, ], }, { code: "import * as moment from 'moment'", errors: [ { message: 'Use date-fns or Native Date methods instead of moment.js', type: 'ImportDeclaration', }, ], }, ], }); ruleTester.run('no-moment-constructor', rule['no-moment-constructor'], { valid: ['new Date()', 'Date()'], invalid: [ { code: 'moment()', errors: [ { message: 'Consider using Native new Date().', type: 'CallExpression', }, ], }, { code: "moment('12-25-1995')", errors: [ { message: 'Consider using Native new Date().', type: 'CallExpression', }, ], }, { code: "moment('12-25-1995', 'MM-DD-YYYY')", errors: [ { message: 'Consider using date-fns, e.g. parse("2010-10-20 4:30", "yyyy-MM-dd H:mm", new Date()).', type: 'CallExpression', }, ], }, ], }); ruleTester.run('no-moment-methods/seconds', rule['seconds'], { valid: [], invalid: [ { code: 'moment().seconds()', errors: [ { message: 'Consider using new Date().getSeconds() or new Date().setSeconds()', type: 'CallExpression', }, ], }, ], }); ruleTester.run('no-moment-methods/seconds', rule['seconds'], { valid: [], invalid: [ { code: "moment()['seconds']();", errors: [ { message: 'Consider using new Date().getSeconds() or new Date().setSeconds()', type: 'CallExpression', }, ], }, ], }); ruleTester.run('no-moment-methods/is-after', rule['is-after'], { valid: [], invalid: [ { code: "const m = moment('2010-10-20').isAfter('2010-10-19')", errors: [ { message: 'Consider using date-fns isAfter(date, dateToCompare) or dayjs().isAfter()', type: 'CallExpression', }, ], }, ], }); ruleTester.run('no-require-moment', rule['no-require-moment'], { valid: [ "var { format, formatDistance, formatRelative, subDays } = require('date-fns')", 'var empty = require()', 'var other = r()', ], invalid: [ { code: "var moment = require('moment')", errors: [ { message: 'Use date-fns or Native Date methods instead of moment.js', type: 'CallExpression', }, ], }, { code: "var format = require('moment').format", errors: [ { message: 'Use date-fns or Native Date methods instead of moment.js', type: 'CallExpression', }, ], }, ], }); }); ================================================ FILE: lib/index.js ================================================ const rules = Object.assign( {}, { 'no-dynamic-import-moment': require('./rules/no-dynamic-import-moment'), 'no-import-moment': require('./rules/no-import-moment'), 'no-moment-constructor': require('./rules/no-moment-constructor'), 'no-require-moment': require('./rules/no-require-moment'), }, require('./rules/no-moment-methods') ); module.exports.rules = rules; const configure = (list, level) => { const r = {}; Object.keys(list).map(rule => (r['you-dont-need-momentjs/' + rule] = level)); return r; }; module.exports.configs = { recommended: { plugins: ['you-dont-need-momentjs'], rules: configure(rules, 2), }, }; ================================================ FILE: lib/rules/methods.json ================================================ { "seconds": { "alternative": "new Date().getSeconds() or new Date().setSeconds()" }, "hours": { "alternative": "new Date().getHours() or new Date().setHours()" }, "date": { "alternative": "new Date().getDate() or new Date().setDate()" }, "day": { "alternative": "new Date().getDay() or new Date().setDate()" }, "dayOfYear": { "alternative": "date-fns getDayOfYear(date) or setDayOfYear(date, dayOfYear)" }, "week": { "alternative": "date-fns getWeek(date) or setWeek(date, week)" }, "isoWeeksInYear": { "alternative": "date-fns getISOWeeksInYear(date)" }, "max": { "alternative": "date-fns max(date)" }, "min": { "alternative": "date-fns min(date)" }, "add": { "alternative": "date-fns addDays(date, amount) or dayjs().add(number, unit)" }, "subtract": { "alternative": "date-fns subDays(date, amount) or dayjs().subtract(number, unit)" }, "startOf": { "alternative": "date-fns startOfMonth(date) or dayjs().startOf(unit)" }, "endOf": { "alternative": "date-fns endOfDay(date) or dayjs().endOf(unit)" }, "format": { "alternative": "date-fns format(date, format) or dayjs().format()" }, "fromNow": { "alternative": "date-fns formatDistance(date, baseDate)" }, "to": { "alternative": "date-fns formatDistance(date, baseDate)" }, "diff": { "alternative": "date-fns differenceInMilliseconds(dateLeft, dateRight) or dayjs().diff()" }, "daysInMonth": { "alternative": "date-fns getDaysInMonth(date) or dayjs().daysInMonth();" }, "isBefore": { "alternative": "date-fns isBefore(date, dateToCompare) or dayjs().isBefore()" }, "isSame": { "alternative": "date-fns isSameMonth(dateLeft, dateRight) or dayjs().isSame()" }, "isAfter": { "alternative": "date-fns isAfter(date, dateToCompare) or dayjs().isAfter()" }, "isBetween": { "alternative": "date-fns isWithinInterval(date, interval)" }, "isLeapYear": { "alternative": "date-fns isLeapYear(date)" }, "isDate": { "alternative": "date-fns isDate(date)" } } ================================================ FILE: lib/rules/no-dynamic-import-moment.js ================================================ var message = 'Use date-fns or Native Date methods instead of moment.js'; module.exports = function(context) { return { CallExpression: function(node) { if (node.callee.type !== 'Import') { return; } var arg = node.arguments[0]; if (arg.type === 'Literal' && arg.value === 'moment') { context.report(node, message); } }, }; }; ================================================ FILE: lib/rules/no-import-moment.js ================================================ module.exports = function(context) { return { ImportDeclaration: function(node) { node.specifiers.forEach(function(specifier) { if ( (specifier.type === 'ImportDefaultSpecifier' || specifier.type === 'ImportNamespaceSpecifier') && specifier.local.type === 'Identifier' && specifier.local.name === 'moment' ) { context.report( node, 'Use date-fns or Native Date methods instead of moment.js' ); } }); }, }; }; ================================================ FILE: lib/rules/no-moment-constructor.js ================================================ module.exports = function(context) { return { CallExpression(node) { if (node.callee.name === 'moment') { if (node.arguments.length === 0 || node.arguments.length === 1) { context.report({ node, message: `Consider using Native new Date().`, }); } else { context.report({ node, message: `Consider using date-fns, e.g. parse("2010-10-20 4:30", "yyyy-MM-dd H:mm", new Date()).`, }); } } }, }; }; ================================================ FILE: lib/rules/no-moment-methods.js ================================================ const kebabCase = require('kebab-case'); const rules = require('./methods'); for (const rule in rules) { const alternative = rules[rule].alternative; const ruleName = rules[rule].ruleName || kebabCase(rule); module.exports[ruleName] = { create(context) { return { CallExpression(node) { const callee = node.callee; const objectName = callee.name || (callee.object && callee.object.name) || (callee.object && callee.object.callee && callee.object.callee.name); if ( objectName === 'moment' && callee.property && (callee.property.name === rule || callee.property.value === rule) ) { context.report({ node, message: `Consider using ${alternative}`, }); } }, }; }, }; } ================================================ FILE: lib/rules/no-require-moment.js ================================================ module.exports = function(context) { return { CallExpression: function(node) { if (node.callee.type === 'Identifier' && node.callee.name === 'require') { var arg = node.arguments[0]; if (arg && arg.type === 'Literal' && arg.value === 'moment') { context.report( node, 'Use date-fns or Native Date methods instead of moment.js' ); } } }, }; }; ================================================ FILE: package.json ================================================ { "name": "eslint-plugin-you-dont-need-momentjs", "description": "Check better alternatives you can use without momentjs", "version": "1.6.0", "repository": { "type": "git", "url": "https://github.com/you-dont-need/You-Dont-Need-Momentjs.git" }, "keywords": [ "moment-js", "date-fns", "dayjs", "luxon", "eslint", "eslintplugin", "eslint-plugin", "tree-shaking", "you-dont-need" ], "author": "Andrew Yang ", "contributors": [ "Robert Chang ", "Jago MF (https://github.com/jagomf)", "Steve Mao (https://github.com/stevemao)", "CY Lim (https://l.cy.my/github)" ], "main": "lib/index.js", "scripts": { "test:watch": "jest --watch", "test": "jest --coverage", "test:perf": "node ./__tests__/performance.js", "coveralls": "cat ./coverage/lcov.info | coveralls", "precommit": "pretty-quick --staged" }, "devDependencies": { "babel-eslint": "^10.1.0", "coveralls": "^3.0.2", "date-fns": "^2.0.0", "dayjs": "^1.8.15", "eslint": "^5.5.0", "husky": "^0.14.3", "jest": "^29.6.2", "luxon": "^1.17.2", "moment": "^2.24.0", "prettier": "^1.14.2", "pretty-quick": "^1.6.0" }, "dependencies": { "kebab-case": "^1.0.0" }, "peerDependencies": { "eslint": "^5.5.0 || ^7.0.0" }, "jest": { "collectCoverageFrom": [ "lib/**/*.js" ], "testPathIgnorePatterns": [ "/node_modules/", "./__tests__/performance.js" ] }, "license": "MIT", "bugs": { "url": "https://github.com/you-dont-need/You-Dont-Need-Momentjs/issues" } }