JavaScript Dates and Time: Date Object and Formatting
Learn the JavaScript Date object: create dates, read and change parts, use timestamps, format dates, and calculate ages, differences and deadlines.
What you will learn
Almost every real website works with dates: a blog post shows when it was published, a shop shows the delivery date, a booking form blocks past days, a countdown timer counts down to a sale. JavaScript has a built-in object for this called Date. In this lesson you will learn how to create dates in different ways, read and change their parts, understand timestamps, format dates in a friendly way, and do the most useful calculations: adding days, finding the difference between two dates, working out an age, and more.
Creating a date
A Date object is created with new Date(...). There are several ways.
1. The current date and time
const now = new Date();
console.log(now); // the current date and time, in your computer's time zone
2. From year, month, day (and more)
// new Date(year, monthIndex, day, hours, minutes, seconds, milliseconds)
const birthday = new Date(2000, 4, 15); // 15 May 2000, 00:00
const meeting = new Date(2026, 9, 2, 14, 30); // 2 Oct 2026, 2:30 PM
Big trap: the month starts at 0. January is
0, February is1, … May is4, October is9, December is11. But the day of the month starts at 1.
| Month | Index | Month | Index |
|---|---|---|---|
| January | 0 | July | 6 |
| February | 1 | August | 7 |
| March | 2 | September | 8 |
| April | 3 | October | 9 |
| May | 4 | November | 10 |
| June | 5 | December | 11 |
3. From a date text
const a = new Date("2026-10-02"); // date only
const b = new Date("2026-10-02T14:30:00"); // date and time (local time)
const c = new Date("2026-10-02T14:30:00Z"); // the Z means UTC time
const d = new Date("October 2, 2026"); // works, but avoid unusual formats
The safest text format is the ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS.
Careful: a date-only text like
"2026-10-02"is read as UTC midnight, while"2026-10-02T00:00:00"(with time, noZ) is read as your local midnight. In some time zones this can show the previous day. When you want your local date, build it withnew Date(2026, 9, 2).
4. From a timestamp (milliseconds)
const start = new Date(0);
console.log(start.toISOString()); // "1970-01-01T00:00:00.000Z"
const nextDay = new Date(24 * 60 * 60 * 1000); // 1 day in milliseconds
console.log(nextDay.toISOString()); // "1970-01-02T00:00:00.000Z"
5. Copying a date
Dates are objects, so const b = a shares the same date (reference). Make a real copy with new Date(a):
const a = new Date(2026, 9, 2);
const b = new Date(a); // a separate copy
b.setDate(20);
console.log(a.getDate()); // 2 (unchanged)
Timestamps: the number behind every date
Inside, a Date is just one number: the milliseconds that have passed since 1 January 1970, 00:00:00 UTC. This moment is called the Unix epoch.
const date = new Date(2026, 9, 2);
console.log(date.getTime()); // the timestamp (a big number)
console.log(Date.now()); // timestamp of this exact moment
A timestamp is the same all over the world. That is why servers and databases love it. Because it is a plain number, you can compare and subtract dates:
const earlier = new Date(2026, 9, 1);
const later = new Date(2026, 9, 2);
console.log(earlier < later); // true
console.log(later - earlier); // 86400000 (one day in milliseconds)
Comparing dates
Use < and > freely. But do not use === for equality, because two different date objects are never the same reference:
const a = new Date(2026, 9, 2);
const b = new Date(2026, 9, 2);
console.log(a === b); // false
console.log(a.getTime() === b.getTime()); // true (compare the numbers)
Reading the parts of a date
const date = new Date(2026, 9, 2, 14, 30, 45); // Friday, 2 Oct 2026, 14:30:45
console.log(date.getFullYear()); // 2026
console.log(date.getMonth()); // 9 (October, starts at 0)
console.log(date.getDate()); // 2 (day of the month)
console.log(date.getDay()); // 5 (day of the week)
console.log(date.getHours()); // 14
console.log(date.getMinutes()); // 30
console.log(date.getSeconds()); // 45
console.log(date.getMilliseconds()); // 0
| Method | Returns | Range |
|---|---|---|
getFullYear() |
Year | e.g. 2026 |
getMonth() |
Month | 0 to 11 |
getDate() |
Day of the month | 1 to 31 |
getDay() |
Day of the week | 0 (Sunday) to 6 (Saturday) |
getHours() |
Hours | 0 to 23 |
getMinutes() / getSeconds() |
Minutes / seconds | 0 to 59 |
getTime() |
Timestamp in milliseconds | any number |
Do not use getYear(). It is old and wrong. Always use getFullYear().
Getting the name of the day or month
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const date = new Date(2026, 9, 2);
console.log(days[date.getDay()]); // "Friday"
(Later in this lesson you will see an easier way using toLocaleDateString.)
Local time vs UTC
Every “get” method has a UTC twin (getUTCFullYear, getUTCHours, …). Local methods use the time zone of the user’s device. UTC methods give the same answer everywhere.
const date = new Date(Date.UTC(2026, 9, 2, 12, 0)); // 12:00 UTC
console.log(date.getUTCHours()); // 12 (always)
console.log(date.getHours()); // depends on the time zone of the device
Tip: for saving or sending dates to a server, use UTC (
toISOString()). For showing a date to the user, use local time.
Changing a date
Every “get” has a “set”:
const date = new Date(2026, 9, 2);
date.setFullYear(2027);
date.setMonth(0); // January
date.setDate(15);
date.setHours(9, 30); // 9:30 AM
console.log(date.getFullYear(), date.getMonth(), date.getDate()); // 2027 0 15
Setters change the original date (dates are mutable). Make a copy first if you need to keep the old one.
Dates fix overflow automatically
If you set a value that is too big, JavaScript rolls over to the next month or year. This is the secret of easy date maths:
const date = new Date(2026, 9, 31); // 31 October
date.setDate(date.getDate() + 1); // 32 October = 1 November
console.log(date.getMonth(), date.getDate()); // 10 1 (November 1)
const jan31 = new Date(2026, 0, 31);
jan31.setMonth(1); // February 31 does not exist
console.log(jan31.getMonth(), jan31.getDate()); // 2 3 (March 3)
The second example is a classic surprise: moving 31 January to “February” lands in March.
Formatting dates
Built-in text methods
const date = new Date(Date.UTC(2026, 9, 2, 14, 30));
console.log(date.toISOString()); // "2026-10-02T14:30:00.000Z" (good for servers)
console.log(date.toJSON()); // same as toISOString()
const local = new Date(2026, 9, 2, 14, 30);
console.log(local.toDateString()); // "Fri Oct 02 2026"
console.log(local.toLocaleDateString()); // depends on the user's language
console.log(local.toLocaleTimeString()); // depends on the user's language
console.log(local.toLocaleString()); // date and time together
toLocaleDateString with options
This is the best way to show a friendly date. Pass a language code and an options object:
const date = new Date(2026, 9, 2);
console.log(date.toLocaleDateString("en-IN")); // "2/10/2026" (day/month/year)
console.log(date.toLocaleDateString("en-US")); // "10/2/2026" (month/day/year)
console.log(date.toLocaleDateString("en-IN", {
day: "numeric",
month: "long",
year: "numeric"
}));
// "2 October 2026"
console.log(date.toLocaleDateString("en-US", {
weekday: "long",
month: "short",
day: "numeric"
}));
// "Friday, Oct 2"
console.log(date.toLocaleDateString("hi-IN", { month: "long" })); // month name in Hindi
Common options:
| Option | Possible values |
|---|---|
weekday |
"long", "short", "narrow" |
year |
"numeric", "2-digit" |
month |
"numeric", "2-digit", "long", "short" |
day |
"numeric", "2-digit" |
hour, minute, second |
"numeric", "2-digit" |
hour12 |
true or false |
timeZone |
e.g. "Asia/Kolkata", "UTC" |
Time with options:
const date = new Date(2026, 9, 2, 14, 5);
console.log(date.toLocaleTimeString("en-IN", {
hour: "2-digit",
minute: "2-digit",
hour12: true
}));
// "02:05 pm"
Intl.DateTimeFormat: create a formatter once
If you format many dates the same way, create one formatter and reuse it:
const formatter = new Intl.DateTimeFormat("en-IN", {
dateStyle: "medium"
});
console.log(formatter.format(new Date(2026, 9, 2))); // "2 Oct 2026"
console.log(formatter.format(new Date(2026, 11, 25))); // "25 Dec 2026"
dateStyle and timeStyle accept "full", "long", "medium" and "short" for quick results.
Building your own format
For a fixed format such as DD/MM/YYYY, build it from the parts and add a leading zero with padStart:
function formatDate(date) {
const day = String(date.getDate()).padStart(2, "0");
const month = String(date.getMonth() + 1).padStart(2, "0"); // +1 because months start at 0
const year = date.getFullYear();
return `${day}/${month}/${year}`;
}
console.log(formatDate(new Date(2026, 9, 2))); // "02/10/2026"
“2 days ago”: relative time
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
console.log(rtf.format(-1, "day")); // "yesterday"
console.log(rtf.format(-3, "day")); // "3 days ago"
console.log(rtf.format(2, "hour")); // "in 2 hours"
console.log(rtf.format(1, "month")); // "next month"
Date calculations
Add days to a date
function addDays(date, days) {
const result = new Date(date); // copy, so the original is safe
result.setDate(result.getDate() + days);
return result;
}
const today = new Date(2026, 9, 2);
console.log(addDays(today, 30).toLocaleDateString("en-IN", { dateStyle: "long" }));
// "1 November 2026"
console.log(addDays(today, -7).toLocaleDateString("en-IN", { dateStyle: "long" }));
// "25 September 2026"
Days between two dates
Subtract the dates (you get milliseconds) and divide:
const MS_PER_DAY = 1000 * 60 * 60 * 24;
function daysBetween(start, end) {
return Math.round((end - start) / MS_PER_DAY);
}
const today = new Date(2026, 9, 2);
const christmas = new Date(2026, 11, 25);
console.log(daysBetween(today, christmas)); // 84
We use Math.round because in time zones with daylight saving time, one “day” can be 23 or 25 hours.
Last day of a month
Day 0 of the next month means “the last day of this month”:
function daysInMonth(year, monthIndex) {
return new Date(year, monthIndex + 1, 0).getDate();
}
console.log(daysInMonth(2026, 1)); // 28 (February 2026)
console.log(daysInMonth(2028, 1)); // 29 (February 2028, a leap year)
console.log(daysInMonth(2026, 9)); // 31 (October)
Calculate an age
function getAge(birthDate, today = new Date()) {
let age = today.getFullYear() - birthDate.getFullYear();
const hadBirthdayThisYear =
today.getMonth() > birthDate.getMonth() ||
(today.getMonth() === birthDate.getMonth() && today.getDate() >= birthDate.getDate());
if (!hadBirthdayThisYear) age--;
return age;
}
console.log(getAge(new Date(2000, 4, 15), new Date(2026, 9, 2))); // 26
console.log(getAge(new Date(2000, 11, 1), new Date(2026, 9, 2))); // 25
Is it a weekend?
function isWeekend(date) {
const day = date.getDay();
return day === 0 || day === 6;
}
console.log(isWeekend(new Date(2026, 9, 3))); // true (Saturday)
console.log(isWeekend(new Date(2026, 9, 2))); // false (Friday)
Is a date in the past?
function isPast(date) {
return date < new Date();
}
console.log(isPast(new Date(2020, 0, 1))); // true
console.log(isPast(new Date(2100, 0, 1))); // false
Invalid dates
If JavaScript cannot understand your input, you get an Invalid Date. It does not throw an error. Instead the date holds NaN.
const bad = new Date("hello");
console.log(bad); // Invalid Date
console.log(bad.getTime()); // NaN
console.log(Number.isNaN(bad.getTime())); // true
A reusable check:
function isValidDate(value) {
const date = new Date(value);
return !Number.isNaN(date.getTime());
}
console.log(isValidDate("2026-10-02")); // true
console.log(isValidDate("not a date")); // false
Note that new Date(2026, 1, 31) is not invalid. It silently becomes 3 March. If you need strict checking, compare the parts back after creating the date.
Real-life use cases
1. A countdown to an event
function countdown(target) {
const diff = target - new Date();
if (diff <= 0) return "The event has started!";
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((diff / (1000 * 60)) % 60);
return `${days} days, ${hours} hours, ${minutes} minutes left`;
}
console.log(countdown(new Date(2030, 0, 1)));
Run it every second with setInterval (you will learn timers soon) to make a live countdown.
2. A greeting based on the time of day
function greeting(date = new Date()) {
const hour = date.getHours();
if (hour < 12) return "Good morning";
if (hour < 17) return "Good afternoon";
if (hour < 21) return "Good evening";
return "Good night";
}
console.log(greeting(new Date(2026, 9, 2, 9))); // "Good morning"
console.log(greeting(new Date(2026, 9, 2, 15))); // "Good afternoon"
3. Delivery date (skip Sundays)
function deliveryDate(orderDate, businessDays) {
const result = new Date(orderDate);
let added = 0;
while (added < businessDays) {
result.setDate(result.getDate() + 1);
if (result.getDay() !== 0) added++; // do not count Sundays
}
return result;
}
const delivery = deliveryDate(new Date(2026, 9, 2), 3); // ordered on Friday
console.log(delivery.toLocaleDateString("en-IN", {
weekday: "long", day: "numeric", month: "short", year: "numeric"
})); // "Tuesday, 6 Oct 2026"
4. Sort by date (newest first)
const posts = [
{ title: "Closures", date: new Date(2026, 8, 25) },
{ title: "Arrays", date: new Date(2026, 9, 1) },
{ title: "Loops", date: new Date(2026, 7, 10) }
];
const newestFirst = [...posts].sort((a, b) => b.date - a.date);
console.log(newestFirst.map((p) => p.title)); // ["Arrays", "Closures", "Loops"]
5. Group items by month
const orders = [
{ id: 1, date: new Date(2026, 8, 5) },
{ id: 2, date: new Date(2026, 8, 20) },
{ id: 3, date: new Date(2026, 9, 2) }
];
const byMonth = {};
for (const order of orders) {
const key = order.date.toLocaleDateString("en-IN", { month: "long", year: "numeric" });
(byMonth[key] ??= []).push(order.id);
}
console.log(byMonth); // { "September 2026": [1, 2], "October 2026": [3] }
6. Block past dates in a date input
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const minDate = `${year}-${month}-${day}`;
console.log(minDate); // for example "2026-10-02"
// document.querySelector("#bookingDate").min = minDate;
7. Measure how long code takes
const start = Date.now();
let total = 0;
for (let i = 0; i < 1_000_000; i++) total += i;
const end = Date.now();
console.log(`Took ${end - start} ms`);
8. Show a post date for readers
function showDate(isoText) {
return new Date(isoText).toLocaleDateString("en-IN", {
day: "numeric",
month: "short",
year: "numeric",
timeZone: "UTC"
});
}
console.log(showDate("2026-10-02")); // "2 Oct 2026"
The timeZone: "UTC" option makes sure a date-only text shows the same day everywhere.
9. Start and end of today
const startOfDay = new Date();
startOfDay.setHours(0, 0, 0, 0);
const endOfDay = new Date();
endOfDay.setHours(23, 59, 59, 999);
console.log(startOfDay.getHours(), endOfDay.getHours()); // 0 23
Common mistakes
- Forgetting that the month starts at 0.
new Date(2026, 10, 1)is November, not October. - Using
getDay()for the day of the month.getDay()is the weekday (0 to 6). UsegetDate()for the day of the month. - Using
getYear(). UsegetFullYear(). - Comparing dates with
===. ComparegetTime()values instead. - Changing a date by accident.
setDate,setMonthand the others change the original. Copy withnew Date(date)first. - Trusting
new Date("some random text"). Browsers read unusual formats differently. Use ISO text or the separate numbers. - Mixing UTC and local time without noticing. A date-only text like
"2026-10-02"is UTC, butnew Date(2026, 9, 2)is local. - Expecting an error for bad input. You get
Invalid Date(NaN) instead. Check withNumber.isNaN(date.getTime()). - Assuming every day has 24 hours. Daylight saving time changes this in many countries. Use
Math.roundor work withsetDate. - Doing hard date maths by hand (like manual month lengths). Let the Date object roll over for you, or use
new Date(year, month + 1, 0)for the last day. - Storing a formatted date text (like
"2/10/2026") as data. Store ISO text or a timestamp, and format only when you display it.
Practice
- Create the date of your birthday with
new Date(year, month, day)and print the year, the month name and the day of the week (use an array of names). - Print today’s date as
"2 October 2026"usingtoLocaleDateStringwith options. - Write
formatDate(date)that returnsDD-MM-YYYYwith leading zeros. - Write
addDays(date, n)without changing the original date, and test it withn = 45. - Find how many days are left until the next 1 January.
- Write
getAge(birthDate)and test it with two different birthdays. - Write
daysInMonth(year, month)and test it with February of a leap year and a normal year. - Write
isWeekend(date)and use it to print “Weekend” or “Weekday” for 5 different dates. - Sort an array of 4 events by date, nearest first.
- Check whether
new Date("2026-13-45")is valid. Explain your result. - Challenge: build a
timeAgo(date)function that returns text such as"5 minutes ago","2 hours ago"or"3 days ago", usingIntl.RelativeTimeFormat.
Recap
- A
Dateis stored as one number: the milliseconds since 1 January 1970 UTC (the timestamp). Get it withgetTime()orDate.now(). - Create dates with
new Date()(now),new Date(year, month, day...),new Date("ISO text"), ornew Date(milliseconds). Months start at 0. - Read parts with
getFullYear,getMonth,getDate,getDay,getHours,getMinutes… Change them with the matchingsetmethods. Setters change the original, so copy withnew Date(date). - Dates roll over automatically: day 32 becomes the next month.
new Date(year, month + 1, 0).getDate()gives the number of days in a month. - Compare with
<and>, or comparegetTime()for equality. Subtract two dates to get milliseconds. - Format dates for people with
toLocaleDateString(locale, options),Intl.DateTimeFormatandIntl.RelativeTimeFormat. UsetoISOString()for servers and storage. - Invalid input gives
Invalid DatewithNaNinside. Check it withNumber.isNaN(date.getTime()). - Next you will learn regular expressions: patterns that let you search, check and replace text.