How to Format Dates in TypeScript (5 Methods)

Imagine a shipping-label screen for a US warehouse. The label needs “Saturday, October 10, 2026”, the database wants a sortable string, and the file name wants 2026-10-10. That’s three ways to format a date in TypeScript, from one Date.

To format a date, or convert a date to a string, use toLocaleDateString("en-US", options) for display and toISOString() for storage. The trap is the time zone: a 9:45 PM order can turn into tomorrow’s date in the stored string.

Below are five ways to do it, plus what happens with an invalid date. I ran every snippet with TypeScript 7.0.2 and Node.js v22.22.2, in the US Eastern time zone.

The sample dates we’ll format

Every example uses two orders from the same day:

const placed = new Date(2026, 9, 10, 14, 30);   // Oct 10, 2:30 PM
const late = new Date(2026, 9, 10, 21, 45);     // Oct 10, 9:45 PM

The month is 9 because JavaScript counts months from 0. The late order is already October 11 in UTC, which is why it’s the tricky one. If your orders sit in a list, arrays of objects in TypeScript shows how to type them.

Method 1: Format a date with toLocaleDateString() (Recommended)

This is the one I reach for when a person reads the result. It uses the user’s local time zone and the conventions of the locale you pass, like en-US.

const placed = new Date(2026, 9, 10, 14, 30);   // Oct 10, 2:30 PM
const late = new Date(2026, 9, 10, 21, 45);     // Oct 10, 9:45 PM

console.log(placed.toLocaleDateString("en-US"));

const long: Intl.DateTimeFormatOptions = {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric",
};
console.log(placed.toLocaleDateString("en-US", long));
console.log(placed.toLocaleString("en-US", { dateStyle: "medium", timeStyle: "short" }));

Output:

10/10/2026
Saturday, October 10, 2026
Oct 10, 2026, 2:30 PM
Command Prompt output of TypeScript toLocaleDateString showing a US short date, a long date with weekday, and a combined date and time for an order
One Date becomes a short date, a long date with the weekday, and a date with time.

How does this code work?

With no options you get month/day/year. An options object picks the pieces, so weekday, month and day spelled out give “Saturday, October 10, 2026”. dateStyle and timeStyle are the shortest way to get both date and time.

Always pass "en-US" when output must be identical for everyone; without it, the result follows the visitor’s browser. To format a whole list this way, a for…of loop in TypeScript works well.

Method 2: Convert a date to a string with toISOString()

For a database or API, toISOString() always returns YYYY-MM-DDTHH:mm:ss.sssZ in UTC, so it sorts correctly as text.

const placed = new Date(2026, 9, 10, 14, 30);   // Oct 10, 2:30 PM
const late = new Date(2026, 9, 10, 21, 45);     // Oct 10, 9:45 PM

console.log("placed:", placed.toISOString());
console.log("late:  ", late.toISOString());
console.log("late date part:", late.toISOString().slice(0, 10));

Output:

placed: 2026-10-10T18:30:00.000Z
late:   2026-10-11T01:45:00.000Z
late date part: 2026-10-11
Command Prompt output of TypeScript toISOString for two orders, where the 9:45 PM order shows the next day in UTC
The late order’s ISO date is one day ahead of its local date.

How does this code work?

New York is four hours behind UTC in October, so 2:30 PM becomes 18:30. At 9:45 PM, UTC is 01:45 the next morning, so slicing the string gives 2026-10-11 while the local date is still October 10.

Store ISO strings, but never slice one to show a customer the date. Build that from local values (Method 4). To convert the other direction, see converting a string to a date in TypeScript, and for the UTC side, converting dates to UTC in TypeScript.

The built-ins toString() and toDateString() also return text, but the layout is fixed (“Sat Oct 10 2026” for the latter), so I only use them in logs.

Method 3: Format many dates with Intl.DateTimeFormat

toLocaleDateString builds a new formatter on every call. For a table of orders, create one Intl.DateTimeFormat and reuse it.

const placed = new Date(2026, 9, 10, 14, 30);   // Oct 10, 2:30 PM
const late = new Date(2026, 9, 10, 21, 45);     // Oct 10, 9:45 PM

const fmt = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  year: "numeric",
  hour: "numeric",
  minute: "2-digit",
});

[placed, late].forEach((d) => console.log(fmt.format(d)));

Output:

Oct 10, 2026, 2:30 PM
Oct 10, 2026, 9:45 PM

How does this code work?

new Intl.DateTimeFormat("en-US", options) returns an object whose format() accepts a Date. It’s the same engine behind toLocaleDateString, so the output matches.

The forEach call above is covered in the forEach method on arrays.

Method 4: Build a custom format with getFullYear(), getMonth() and getDate()

When you need an exact pattern, like 2026-10-10 for a file name, build it from the date’s parts. A union type keeps the allowed formats explicit:

const placed = new Date(2026, 9, 10, 14, 30);   // Oct 10, 2:30 PM
const late = new Date(2026, 9, 10, 21, 45);     // Oct 10, 9:45 PM

type DateFormat = "yyyy-MM-dd" | "MM-dd-yyyy" | "ISO";

const pad = (n: number): string => String(n).padStart(2, "0");

function formatDate(d: Date, format: DateFormat): string {
  const year = d.getFullYear();
  const month = pad(d.getMonth() + 1);
  const day = pad(d.getDate());
  switch (format) {
    case "yyyy-MM-dd":
      return `${year}-${month}-${day}`;
    case "MM-dd-yyyy":
      return `${month}-${day}-${year}`;
    case "ISO":
      return d.toISOString();
  }
}

console.log(formatDate(late, "yyyy-MM-dd"));
console.log(formatDate(placed, "MM-dd-yyyy"));

Output:

2026-10-10
10-10-2026
Command Prompt output of a custom TypeScript formatDate function printing 2026-10-10 and 10-10-2026 for the 9:45 PM and 2:30 PM orders
The 9:45 PM order stays on October 10 because the getters read local time.

How does this code work?

getFullYear(), getMonth() and getDate() read local time, so the late order stays on October 10. getMonth() is zero-based, hence the + 1, and padStart(2, "0") turns 5 into 05.

The DateFormat union means a call like formatDate(d, "dd/MM") fails at compile time. Pulling the year back out later is covered in extracting the year from a date in TypeScript.

Method 5: Format a date with date-fns

If you format dates in many patterns, the date-fns library reads better than manual padding. Install it with npm install date-fns, then call format() with a pattern string:

import { format } from "date-fns";

const placed = new Date(2026, 9, 10, 14, 30);
console.log(format(placed, "MM/dd/yyyy hh:mm a"));
console.log(format(placed, "EEEE, MMMM d, yyyy"));

Output:

10/10/2026 02:30 PM
Saturday, October 10, 2026

The pattern letters matter: MM is month, mm is minutes, and lowercase yyyy is the calendar year. Moment.js does the same job, but its maintainers now treat it as a legacy project, so I’d pick date-fns or plain Intl for new code.

To pick the newest date from a list before formatting it, see the array reduce method.

What happens when the date is invalid?

A Date built from bad input doesn’t throw. Only some methods complain:

const bad = new Date("10/32/2026");

console.log(bad.toString());
console.log(Number.isNaN(Date.parse("10/32/2026")));

try {
  bad.toISOString();
} catch (err) {
  console.log((err as Error).name + ": " + (err as Error).message);
}

Output:

Invalid Date
true
RangeError: Invalid time value
Command Prompt output of TypeScript showing Invalid Date from toString, true from isNaN on Date.parse, and RangeError from toISOString
The bad date prints Invalid Date, parsing returns NaN, and toISOString() throws a RangeError.

"10/32/2026" isn’t a real date, so Date.parse() returns NaN and toString() quietly prints “Invalid Date”, but toISOString() throws. Check Number.isNaN(d.getTime()) before you format user input. Dropping bad rows first is easy with filtering an array of objects in TypeScript.

Which way to format a date should you use?

MethodOutputUse it when
toLocaleDateString("en-US", opts)Saturday, October 10, 2026A person reads it (Recommended)
toISOString()2026-10-10T18:30:00.000ZStoring or sending to an API
Intl.DateTimeFormatSame as locale methodsFormatting many dates
getFullYear() and friendsAny pattern you buildExact formats like yyyy-MM-dd
date-fns format()Pattern-driven textMany patterns, one readable call

Things to Keep in Mind When Formatting Dates

  • Months start at 0: new Date(2026, 9, 10) is October. Add 1 when you print.
  • toISOString() is UTC, so a late-evening local time can show tomorrow’s date. For text going the other way, see handling ISO date strings in TypeScript.

More array guides that pair well with date handling:

Frequently asked questions

How do I format a date in TypeScript?

Call date.toLocaleDateString("en-US", options) for a readable date, or build an exact pattern from getFullYear(), getMonth() + 1 and getDate().

How do I convert a date to a string in TypeScript?

Use toLocaleDateString() for display or toISOString() for a UTC timestamp you can store.

How do I format a date as YYYY-MM-DD in TypeScript?

Pad the local parts with padStart(2, "0"), or use format(date, "yyyy-MM-dd") from date-fns. Avoid slicing toISOString(), which is UTC.

Why does toISOString() show the wrong day?

It converts to UTC. In the US, an evening local time is already the next day in UTC, so use local getters or toLocaleDateString.

Where is toLocaleDateString documented?