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

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

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

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

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?
| Method | Output | Use it when |
|---|---|---|
toLocaleDateString("en-US", opts) | Saturday, October 10, 2026 | A person reads it (Recommended) |
toISOString() | 2026-10-10T18:30:00.000Z | Storing or sending to an API |
Intl.DateTimeFormat | Same as locale methods | Formatting many dates |
getFullYear() and friends | Any pattern you build | Exact formats like yyyy-MM-dd |
date-fns format() | Pattern-driven text | Many 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?
See Date.prototype.toLocaleDateString() on MDN.