It is certainly possible to format dates using vanilla JavaScript, but most JavaScript developers would consider that masochism. The built-in toLocaleString() function's options syntax is limited and filled with odd quirks. Moment is the de facto choice for converting dates to neatly formatted strings in JavaScript, although some people opt out of using Moment to reduce bundle size.

Formatting Dates

Moment's format() method is what you use to convert a Moment object to a string. For example, here's how you would convert a YYYY-MM-DD string into a more human-readable format:

const moment = require('moment');

const d = new Date('2019/06/01');

moment(d).format('MMMM d, YYYY'); // June 1, 2019

The format() function takes in a string and replaces all instances of tokens with the corresponding date value. A token is a substring like 'YYYY' or 'd' that Moment knows to replace with a part of the date, like the year or the day of the month. Below are some commonly used formatting tokens for dates:

  • YYYY: 4-digit year '2019'
  • YY: 2-digit year '19'
  • MMMM: Full-length month 'June'
  • MMM: 3 character month 'Jun'
  • MM: Month of the year, zero-padded '06'
  • M: Month of the year '6'
  • DD: Day of the month, zero-padded '01'
  • D: Day of the month '1'
  • Do: Day of the month with numeric ordinal contraction '1st'

Here's some common date formats and how to express them in Moment format strings:

  • '2019-06-01': YYYY-MM-DD
  • 'June 1st, 2019': MMMM Do, YYYY
  • 'June \'19': MMMM 'YY
  • '6/1/2019': M/D/YYYY

Sometimes you want to add text to the format string that conflicts with a moment token. For example, if you want a more elaborate date like 'The 1st of June', naively you might try the below format:

// 'T126 1st of June'
m.format('The Do of MMMM');

However, you'll get a surprising output: 'T126 1st of June'. That's because both h and e are moment tokens. You can escape moment tokens using square brackets [].

// 'The 1st of June'
m.format('[The] Do [of] MMMM');

For locale-aware formatting, you can use the L and LL tokens to get a locale-specific formatting of the date.

moment.locale(); // 'en'

let m = moment(new Date('2019/06/01'));

m.format('L'); // 06/01/2019
m.format('LL'); // 'June 1, 2019'

// Set the Moment locale to Germany
moment.locale('de');

m = moment(new Date('2019/06/01'));
m.format('L'); // '01.06.2019'
m.format('LL'); // '1. Juni 2019'

Formatting Times

Moment also supports formatting times. The format() function is very flexible, so you can display just the date component, just the time component, or a combination of both. For example, here's how you can display a date's time in 2:04pm format:

const moment = require('moment');

const m = moment(new Date('2019/06/01 14:04:03'));

m.format('h:mma'); // '2:04pm'

Here's a list of commonly used time format tokens.

  • HH: hour of day from 0-24, zero-padded, '14'
  • H: hour of day from 0-24, '14'
  • hh: hour of day on 12-hour clock, zero-padded, '02'
  • h: hour of the day on 12 hour clock, '2'
  • mm: minute, zero-padded, '04'
  • m: minute, '4'
  • ss: second, zero-padded
  • s: second
  • A: 'AM' or 'PM'
  • a: 'am' or 'pm'

Here's some common date formats and how to express them in Moment format strings:

  • '14:04': HH:mm
  • '14:04:03': HH:mm:ss
  • '2:04pm': h:mma
  • '2:04 PM': h:mm A

Durations

Moment also has the concept of durations that let you humanize the difference between two times into something human-friendly like 'a minute ago'.

The moment.diff() function returns a Moment duration object that represents the difference between two moments. For example:

const moment = require('moment');

const m1 = moment(new Date('2019/06/01 2:04:03'));
const m2 = m1.clone().add(59, 'seconds');

const duration = moment.duration(m1.diff(m2));
duration.seconds(); // 59
duration.milliseconds(); // 59000

duration.humanize(); // 'a minute'
duration.humanize(true); // 'in a minute'

moment.duration(m2.diff(m1)).humanize(true); // 'a minute ago'

The humanize() function takes an optional parameter suffix that, if set to true, indicates whether the duration is positive or negative ('in a minute' vs 'a minute ago'). The humanize() function is locale aware, so you can render durations in your customer's language:

const moment = require('moment');

// Pretend we're in Germany
moment.locale('de');

const m1 = moment(new Date('2019/06/01 2:04:03'));
const m2 = m1.clone().add(59, 'seconds');

const duration = moment.duration(m1.diff(m2));

// Prints "vor einer Minute"
console.log(duration.humanize(true));

Moving On

Moment is an extremely powerful library with an unbelievable breadth of features. Time zones, localization, addition and subtraction, durations: Moment makes most complex date tasks easy. In particular, date formatting is usually the first reason I pull Moment into a new project. The moment.format() function is so flexible, it is hard to imagine writing JavaScript without it.

Found a typo or error? Open up a pull request! This post is available as markdown on Github
comments powered by Disqus