mrkeyoor.com_
Thu 06 Aug 02:48 UTC
npmUtilsupdated 06 Aug 2026

moment

Moment is the date library that JavaScript grew up on: parse a string or a Date, then chain methods to add days, compare, and format the result into human text. One object type (a Moment) wraps everything, and it covers parsing dozens of input shapes, formatting tokens, relative time like 'in 3 hours', durations, and localized output in over 100 locales. It is also, by the maintainers' own statement in the README, a legacy project in maintenance mode: it takes security fixes but no new features, and the docs tell you to pick a different library for new code. It still ships to millions of installs a week because it is buried inside older apps and transitive dependencies, not because anyone recommends starting with it.

Verdict

Keep it alive in old code, do not put it in new code. The library still works and still gets security patches, but its own maintainers point you at Day.js, date-fns, Luxon, or the coming Temporal API, and every one of those is smaller or safer to reason about.

API stability5/5Nothing changes because nothing is being added: 2.30.1 dates from December 2023 and the feature freeze means code written years ago still behaves identically
Docs4/5momentjs.com/docs covers every method with runnable examples and a searchable sidebar, plus an honest Project Status page recommending replacements; it under-warns about the mutation trap that bites most newcomers
Maintenance2/5Declared maintenance mode in the README, no release since December 2023, and 171 open issues (222 counting PRs); pushes still happen but only for fixes and housekeeping
Ecosystem5/536M weekly downloads, 47.9k stars, moment-timezone and a decade of plugins, and near-universal Stack Overflow coverage; most of that volume is legacy and transitive rather than new adoption

Use it if

  • You already have a large codebase full of moment() calls and the migration cost is real: it still works, it is still patched for security issues, and rewriting date logic under time pressure causes bugs
  • You need moment-timezone's IANA database handling in a legacy build where swapping to Luxon or Temporal means touching hundreds of call sites
  • You need Moment's forgiving parser for messy human-entered date strings across many locales, and you are willing to pass an explicit format string to keep it predictable
  • You are maintaining an old build target (IE11-era bundles, no ES2015 output) where newer date libraries' module formats cause trouble
Skip it if

Setup reality

npm install moment and you are done: no peer dependencies, no config, TypeScript types ship in the package. The pain comes at build time and at runtime, not at install. Bundlers see moment's dynamic require of locale files and pull in all of them, so a plain webpack build adds tens of kilobytes of Serbian and Burmese translations you never asked for, and the fix is a manual IgnorePlugin or ContextReplacementPlugin rule. Timezone work means installing moment-timezone separately and choosing between the full data build and a trimmed date range. Parsing a non-ISO string without a format falls back to the browser's Date constructor and prints a deprecation warning to the console, so most real projects end up passing explicit format strings everywhere.

Patterns

Parse a date and format itparse-and-format

const moment = require('moment');

const m = moment('2026-08-05T14:30:00Z');
console.log(m.format('YYYY-MM-DD HH:mm'));  // local time
console.log(m.format('dddd, MMMM Do YYYY')); // Wednesday, August 5th 2026

Formatting always renders in local time unless you switch the Moment to UTC or a named zone first.

Clone before adding or subtractingclone-before-mutating

const start = moment('2026-01-01');

// wrong: this changes `start` itself
// const end = start.add(7, 'days');

// right:
const end = start.clone().add(7, 'days');
console.log(start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD'));

Every mutating method returns the same object, so a missing .clone() rewrites values held elsewhere. This is the single most common Moment bug.

Parse a known format strictlystrict-parsing

const m = moment('05/08/2026', 'DD/MM/YYYY', true);
console.log(m.isValid()); // true

moment('not a date', 'DD/MM/YYYY', true).isValid(); // false

The third argument turns on strict mode. Without a format string, non-ISO input falls through to the native Date constructor and logs a deprecation warning.

Check whether a parse succeededvalidate-input

const m = moment(userInput, 'YYYY-MM-DD', true);

if (!m.isValid()) {
  console.log(m.invalidAt());          // index of the failing unit
  console.log(m.parsingFlags().overflow);
  throw new Error('Bad date');
}

An invalid Moment does not throw; format() on it returns the string 'Invalid date'. Always call isValid() on user input.

Measure the gap between two datesdiff-two-dates

const a = moment('2026-08-05');
const b = moment('2026-12-25');

console.log(b.diff(a, 'days'));        // 142
console.log(b.diff(a, 'months'));      // 4 (truncated)
console.log(b.diff(a, 'months', true)); // 4.65... (float)

diff truncates toward zero by default; pass true as the third argument for a fractional result.

Render relative time like 'an hour ago'relative-time

moment('2026-08-05T10:00:00Z').fromNow();   // '4 hours ago'
moment().add(3, 'days').fromNow();          // 'in 3 days'
moment().add(3, 'days').fromNow(true);      // '3 days'

moment().add(3, 'days').from(moment('2026-08-01'));

Thresholds are coarse by design: 45 seconds rounds to 'a minute'. Adjust with moment.relativeTimeThreshold if the fuzziness matters.

Snap to the start or end of a periodstart-and-end-of-period

const day = moment().startOf('day').clone();
const monthEnd = moment().endOf('month');

console.log(day.toISOString(), monthEnd.toISOString());

startOf and endOf mutate in place too. endOf('day') lands on 23:59:59.999, so use a half-open range comparison rather than <= for queries.

Work in UTC instead of local timeutc-mode

const u = moment.utc('2026-08-05 14:30', 'YYYY-MM-DD HH:mm');
console.log(u.format());          // 2026-08-05T14:30:00Z
console.log(u.local().format());  // shifted to the machine zone
console.log(u.toISOString());     // always UTC

moment.utc() controls display and parsing, not storage. toISOString() is UTC regardless of the mode, which is what you want in a database.

Convert to a named IANA timezonenamed-timezone

// npm install moment-timezone
const moment = require('moment-timezone');

const t = moment.tz('2026-08-05 09:00', 'Asia/Kolkata');
console.log(t.clone().tz('America/New_York').format('YYYY-MM-DD HH:mm z'));
console.log(moment.tz.guess()); // browser's zone

moment-timezone is a separate install that bundles the IANA database. Require it instead of moment; requiring both in one build wastes bytes.

Build and read a durationdurations

const d = moment.duration(93, 'minutes');
console.log(d.hours(), d.minutes()); // 1 33  (components)
console.log(d.asMinutes());          // 93   (total)
console.log(d.humanize());           // 'an hour'

hours() gives the component inside the duration, asHours() gives the total. Mixing them up produces wrong totals for anything over a day.

Switch locale for formattingset-locale

require('moment/locale/de');

moment.locale('de');
console.log(moment().format('dddd')); // Mittwoch

// per-instance, without changing the global default:
console.log(moment().locale('fr').format('dddd'));

moment.locale() is global state shared by the whole process; in a server rendering pages for many users, set the locale per instance instead.

Stop webpack from bundling every localeshrink-bundle

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale$/,
      contextRegExp: /moment$/,
    }),
  ],
};

Without this rule moment's dynamic locale require pulls in all locale files. Import the few you need explicitly after adding the plugin.

Alternatives

PackageRegistryPick it when
dayjsnpmYou want the same chained API in about 3 KB and immutable objects, with plugins for the extras
date-fnsnpmYou prefer plain functions on native Date objects that tree shake down to only what you import
luxonnpmYou need real timezone and Intl handling and are willing to learn a different, immutable API
@js-joda/corenpmYou want a strict, typed date model borrowed from Java's java.time rather than a loose parser