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/#/)
[](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.

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) |  |   |
| Luxon | No | High | OO | - | Good (Intl) |  |   |
| date-fns | Yes | High | Functional | 64 | Good (date-fns-tz) |  |   |
| dayjs | No | High | OO | 138 | Good (Intl) |  |   |
## Voice of Developers
> [Removed moment.js to replace with date-fns - build output reduced by 40%](https://github.com/oysterprotocol/webnode/pull/116)
> —<cite>Jared Farago from [webnode](https://github.com/oysterprotocol/webnode/pull/116) project.</cite>
> [Good library if you’re looking to replace Moment.js for one reason or another. Immutable too.](https://twitter.com/dan_abramov/status/805030922785525760)
> —<cite>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.</cite>
> [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)
> —<cite>Matija Marohnić, a design-savvy frontend developer from Croatia.</cite>
## ESLint Plugin
<p align="center">
<a href="https://www.npmjs.com/package/eslint-plugin-you-dont-need-momentjs">
<img src="https://img.shields.io/npm/v/eslint-plugin-you-dont-need-momentjs.svg?style=flat-square"
alt="NPM Version">
</a>
<a href="https://www.npmjs.org/package/eslint-plugin-you-dont-need-momentjs">
<img src="http://img.shields.io/npm/dm/eslint-plugin-you-dont-need-momentjs.svg?style=flat-square?style=flat-square"
alt="Downloads">
</a>
<a href="https://travis-ci.org/you-dont-need/You-Dont-Need-Momentjs">
<img src="https://img.shields.io/travis/you-dont-need/You-Dont-Need-Momentjs/master.svg?style=flat-square"
alt="Build Status">
</a>
<a href="https://coveralls.io/github/you-dont-need/You-Dont-Need-Momentjs?branch=master">
<img src="https://img.shields.io/coveralls/you-dont-need/You-Dont-Need-Momentjs/master.svg?style=flat-square"
alt="Coverage Status" />
</a>
</p>
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
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>You don't (may not) need Moment.js</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<link
rel="stylesheet"
href="//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css"
/>
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: "You don't need Momentjs",
nameLink: '/',
repo: 'https://github.com/you-dont-need/You-Dont-Need-Momentjs',
autoHeader: true,
maxLevel: 3,
markdown: {
smartypants: true,
},
remoteMarkdown: {
tag: 'remoteMarkdownUrl',
},
};
</script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify-remote-markdown/dist/docsify-remote-markdown.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-js-extras.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-js-templates.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-jsdoc.min.js"></script>
</body>
</html>
================================================
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 <ddvkid@gmail.com>",
"contributors": [
"Robert Chang <cht8687@gmail.com>",
"Jago MF <jagomf@gmail.com> (https://github.com/jagomf)",
"Steve Mao <maochenyan@gmail.com> (https://github.com/stevemao)",
"CY Lim <cylim@pm.me> (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": [
"<rootDir>/node_modules/",
"./__tests__/performance.js"
]
},
"license": "MIT",
"bugs": {
"url": "https://github.com/you-dont-need/You-Dont-Need-Momentjs/issues"
}
}
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
SYMBOL INDEX (2 symbols across 2 files)
FILE: lib/rules/no-moment-constructor.js
method CallExpression (line 3) | CallExpression(node) {
FILE: lib/rules/no-moment-methods.js
method create (line 8) | create(context) {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (84K chars).
[
{
"path": ".gitignore",
"chars": 109,
"preview": "node_modules\n.DS_Store\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n.vscode\n\ncoverage\nyarn.lock\n\n.history"
},
{
"path": ".prettierrc",
"chars": 52,
"preview": "{\n \"singleQuote\": true,\n \"trailingComma\": \"es5\"\n}\n"
},
{
"path": ".travis.yml",
"chars": 85,
"preview": "language: node_js\nnode_js:\n - 12\n - 13\n - 14\nafter_success:\n - npm run coveralls\n"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2018 You-Dont-Need\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 38209,
"preview": "# [You don't (may not) need Moment.js](https://you-dont-need.github.io/You-Dont-Need-Momentjs/#/)\n\n[\n"
},
{
"path": "docs/index.html",
"chars": 1404,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>You don't (may not) need Moment.js</ti"
},
{
"path": "lib/__tests__/index.js",
"chars": 4283,
"preview": "const rule = require('../').rules;\nconst RuleTester = require('eslint').RuleTester;\n\nRuleTester.setDefaultConfig({\n par"
},
{
"path": "lib/index.js",
"chars": 664,
"preview": "const rules = Object.assign(\n {},\n {\n 'no-dynamic-import-moment': require('./rules/no-dynamic-import-moment'),\n "
},
{
"path": "lib/rules/methods.json",
"chars": 2091,
"preview": "{\n \"seconds\": {\n \"alternative\": \"new Date().getSeconds() or new Date().setSeconds()\"\n },\n \"hours\": {\n \"alternat"
},
{
"path": "lib/rules/no-dynamic-import-moment.js",
"chars": 388,
"preview": "var message = 'Use date-fns or Native Date methods instead of moment.js';\n\nmodule.exports = function(context) {\n return"
},
{
"path": "lib/rules/no-import-moment.js",
"chars": 543,
"preview": "module.exports = function(context) {\n return {\n ImportDeclaration: function(node) {\n node.specifiers.forEach(fu"
},
{
"path": "lib/rules/no-moment-constructor.js",
"chars": 529,
"preview": "module.exports = function(context) {\n return {\n CallExpression(node) {\n if (node.callee.name === 'moment') {\n "
},
{
"path": "lib/rules/no-moment-methods.js",
"chars": 913,
"preview": "const kebabCase = require('kebab-case');\nconst rules = require('./methods');\n\nfor (const rule in rules) {\n const altern"
},
{
"path": "lib/rules/no-require-moment.js",
"chars": 436,
"preview": "module.exports = function(context) {\n return {\n CallExpression: function(node) {\n if (node.callee.type === 'Ide"
},
{
"path": "package.json",
"chars": 1714,
"preview": "{\n \"name\": \"eslint-plugin-you-dont-need-momentjs\",\n \"description\": \"Check better alternatives you can use without mome"
}
]
About this extraction
This page contains the full source code of the you-dont-need/You-Dont-Need-Momentjs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (78.0 KB), approximately 25.3k tokens, and a symbol index with 2 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.