A Pragmatic Tour of `Date` and `Intl`
JavaScript Dates
JavaScript's `Date` type is famously awkward, but for everyday work it's enough — especially paired with `Intl.DateTimeFormat`.
What you'll learn
- Create and read dates
- Format with `Intl.DateTimeFormat` and `toISOString`
- Avoid the common timezone and month-index bugs
A Date represents a moment in time as a number of milliseconds
since 1970-01-01 UTC (“the epoch”). It has a reputation for
awkwardness, but the common-case API is short.
Creating Dates
const now = new Date(); // right now
const a = new Date("2026-05-11"); // ISO string
const b = new Date(2026, 4, 11); // year, month (0-indexed!), day
const c = new Date(0); // 1970-01-01 UTC
console.log(now.toISOString()); Reading Components
const d = new Date("2026-05-11T15:30:00");
console.log(d.getFullYear()); // 2026
console.log(d.getMonth()); // 4 (May — zero-indexed)
console.log(d.getDate()); // 11 (day of month)
console.log(d.getDay()); // day of week (0 = Sunday)
console.log(d.getHours()); // 15 (local time)
console.log(d.getUTCHours()); // hours in UTC Comparing and Arithmetic
Dates compare with < and >, but === doesn’t work (object
identity).
const a = new Date("2026-05-11");
const b = new Date("2026-05-15");
const ms = b - a;
const days = ms / (1000 * 60 * 60 * 24);
console.log(days); // 4 To add or subtract, use millisecond math or set* methods:
const d = new Date("2026-05-11");
d.setDate(d.getDate() + 7);
console.log(d.toISOString().slice(0, 10)); // "2026-05-18" setDate(35) correctly rolls over into the next month — the API
handles overflow.
Formatting
For machine-readable output (logs, APIs), use toISOString().
const d = new Date();
console.log(d.toISOString());
// "2026-05-11T12:34:56.789Z" For human-readable output, use Intl.DateTimeFormat:
const d = new Date("2026-05-11T15:00:00Z");
console.log(d.toLocaleDateString("en-US")); // "5/11/2026"
console.log(d.toLocaleDateString("en-GB")); // "11/05/2026"
console.log(d.toLocaleDateString("ja-JP")); // "2026/5/11"
console.log(d.toLocaleString("en-US", {
dateStyle: "full",
timeStyle: "short",
}));
// "Monday, May 11, 2026 at 3:00 PM" Relative Time
Intl.RelativeTimeFormat gives you “3 days ago”, “in 2 hours”.
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
console.log(rtf.format(-1, "day")); // "yesterday"
console.log(rtf.format(3, "day")); // "in 3 days"
console.log(rtf.format(2, "month")); // "in 2 months" Timezone Pitfall
new Date("2026-05-11") parses as UTC midnight; new Date("2026-05-11T00:00")
parses as local midnight. The two can be a full day apart
depending on the user’s timezone.
Up Next
Numbers come with a sidekick — the Math global.