Date formatting without any libraries

You should only reach for a library if you truly need advanced parsing or complex time-zone arithmetic.

This is the simplest, most reliable format construction.

function formatMMDDYYYY(date) {
  const mm = String(date.getMonth() + 1).padStart(2, '0');
  const dd = String(date.getDate()).padStart(2, '0');
  const yyyy = date.getFullYear();
  return `${mm}/${dd}/${yyyy}`;
}
// → "12/24/2025"

There are also different approaches:

LinkIconIntl.DateTimeFormat

Another modern way to format is using Intl.DateTimeFormat

InfoIcon

This is the correct tool for any UI formatting. It handles locale, numbering systems, calendars, and time zones out of the box.

const now = Date.now()
const formatted = new Intl.DateTimeFormat('en-US', {
  month: '2-digit',
  day: '2-digit',
  year: 'numeric'
}).format(now);
// → MM/DD/YYYY

LinkIconFormat in a different locale

new Intl.DateTimeFormat('fr-FR').format(new Date());
// → "09/12/2025"

LinkIconFormat time with options

new Intl.DateTimeFormat('en-US', {
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit'
}).format(new Date());
// → "08:38:44 AM"

LinkIconFormat with timezone

new Intl.DateTimeFormat('en-US', {
  timeZone: 'UTC',
  hour: '2-digit',
  minute: '2-digit'
}).format(new Date());
// → "01:39 PM"

LinkIconISO Strings (Machine-Readable Formats)

JavaScript can also generate ISO timestamps.

new Date().toISOString();
// → "2025-12-08T03:14:25.123Z"

Use cases

  • APIs
  • Databases
  • Logs
  • Server-client communication

LinkIconTemporal (The Future of Date Handling)

Temporal is being added to the language and is available in some runtimes (and polyfills).

This will replace most remaining date libraries.

Temporal.Now.plainDateISO().toString();
// "2025-12-08"

Custom formatting with toLocaleString:

Temporal.Now.plainDateTimeISO().toLocaleString('en-US', {
  month: 'short',
  day: 'numeric',
  year: 'numeric'
});

LinkIconComparissons

LinkIconMoment vs Native

Moment

moment().format('MM/DD/YYYY');

Native

new Intl.DateTimeFormat('en-US', {
  month: '2-digit',
  day: '2-digit',
  year: 'numeric'
}).format(new Date());

LinkIconDay.js vs Native

Day.js:

dayjs().format('MMMM D, YYYY');

Native:

new Intl.DateTimeFormat('en-US', {
  month: 'long',
  day: 'numeric',
  year: 'numeric'
}).format(new Date());

LinkIcondate-fns vs Native

Date-fns:

format(new Date(), 'yyyy/MM/dd');

Native:

new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: '2-digit',
  day: '2-digit'
}).format(new Date());

LinkIconBest Practices

  1. Always format with Intl.DateTimeFormat in UI code.
  2. Use ISO (.toISOString()) for storage & API communication.
  3. Avoid libraries unless doing heavy date arithmetic.
  4. Never rely on date.toLocaleString() without specifying options, too much variability.
  5. When building custom formats, construct them manually (e.g., MM/DD/YYYY).
  6. Be explicit about time zones—ideally UTC for backend.

LinkIconA Reusable Native Formatter Utility

A simple, production-ready date utility without dependencies:

export const DateFormat = {
  iso: date => date.toISOString(),
 
  usShort: date =>
    new Intl.DateTimeFormat('en-US', {
      month: '2-digit',
      day: '2-digit',
      year: 'numeric'
    }).format(date),
 
  long: date =>
    new Intl.DateTimeFormat('en-US', {
      month: 'long',
      day: 'numeric',
      year: 'numeric'
    }).format(date),
 
  time: date =>
    new Intl.DateTimeFormat('en-US', {
      hour: '2-digit',
      minute: '2-digit'
    }).format(date),
 
  custom: (date, joiner = '/') => {
    const m = String(date.getMonth() + 1).padStart(2, '0');
    const d = String(date.getDate()).padStart(2, '0');
    const y = date.getFullYear();
    return [m, d, y].join(joiner);
  }
};