Dates & Intl
Create and compare Dates, time zones, and format dates, numbers and currencies with Intl.
Dates are famously tricky: time zones, daylight saving, months that start at zero, and every country writing dates differently. This lesson covers JavaScript's Date object — how to create, read, compare and calculate with dates — and the Intl API, which formats dates, numbers, currencies and more for any language and region.
Some outputs below depend on your computer's time zone. Examples that show exact output pass an explicit
timeZoneso they're the same everywhere.
What a Date really is#
A Date stores a single number: milliseconds since 1 January 1970, 00:00 UTC (the "Unix epoch"). Everything else — the day, hour, time zone — is calculated from that number when you ask.
Creating dates#
Avoid parsing other string formats like "30/09/2026" or "Sep 30 2026" — results vary between browsers. And beware: "2026-09-30" (date only) is UTC, but "2026-09-30T10:00" (no offset) is local time.
Invalid dates
Reading parts of a date#
Each getUTC* method has a local-time twin (getFullYear, getMonth, getHours…) that uses the computer's time zone. Setters (setDate, setHours…) mutate the date in place.
Comparing and calculating#
Since dates are numbers underneath, comparisons and subtraction just work:
Adding time
setDate handles overflow (day 35 of September becomes 5 October). Adding days via setDate is safer than adding 24 * 60 * 60 * 1000 ms in local time, because a "day" around a daylight-saving change can be 23 or 25 hours.
Sorting dates
Converting dates to strings#
JSON.stringify turns dates into ISO strings, but JSON.parse does not turn them back — you get a string, and must call new Date(str) yourself.
For anything a human will read, use Intl (or toLocaleString, which uses Intl underneath).
Formatting dates with Intl.DateTimeFormat#
- The first argument is a locale (
"en-IN","hi-IN","fr-FR"), orundefinedto use the user's own. dateStyle/timeStyle("full","long","medium","short") give sensible presets.timeZoneaccepts IANA names like"Asia/Kolkata","Europe/London","UTC".- Create a formatter once and reuse it — it's faster than calling
toLocaleStringrepeatedly.
The exact punctuation can change slightly between browser and Node versions, so never parse formatted output — it's for display only.
Relative times
Formatting numbers with Intl.NumberFormat#
Prefer Intl.NumberFormat over toFixed for display: it handles separators, currency symbols and rounding for each locale.
Other handy Intl tools#
Time zone advice#
- Store and transmit dates in UTC (ISO strings or timestamps).
- Display in the user's time zone (the default) or a specific one via
timeZone. - For "all-day" values like birthdays, store just the date string (
"2026-01-15") rather than a moment in time, so it doesn't shift across time zones. - For heavy date logic (recurring events, calendars across zones), use a library such as
date-fns/date-fns-tz, or the new built-in Temporal API, which is rolling out in browsers and fixes most ofDate's design problems. Check support before relying on it.
Common mistakes#
- Forgetting months are 0-based:
new Date(2026, 9, 30)is October 30. - Parsing non-ISO strings like
"30/09/2026". - Comparing dates with
===. - Mutating a date passed into a function (
date.setDate(...)) — copy it first. - Building display strings by hand with
getMonth() + 1and padding instead of usingIntl.
What's next#
Next, a tour of modern JavaScript features — optional chaining, nullish coalescing, logical assignment, at(), Object.groupBy and more.
Check your understanding
Quick quiz
1.What does
new Date(2026, 0, 15)create?2.Which is the best way to store or send a moment in time to a server?
3.What does
new Intl.NumberFormat("en-IN", { style: "currency", currency: "INR" }).format(1234567)produce?
Finished reading?
Mark this lesson complete to track your progress.