JavaScriptIntermediate

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.

All JavaScript lessons

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 is 1, … May is 4, October is 9, December is 11. 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, no Z) is read as your local midnight. In some time zones this can show the previous day. When you want your local date, build it with new 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). Use getDate() for the day of the month.
  • Using getYear(). Use getFullYear().
  • Comparing dates with ===. Compare getTime() values instead.
  • Changing a date by accident. setDate, setMonth and the others change the original. Copy with new 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, but new Date(2026, 9, 2) is local.
  • Expecting an error for bad input. You get Invalid Date (NaN) instead. Check with Number.isNaN(date.getTime()).
  • Assuming every day has 24 hours. Daylight saving time changes this in many countries. Use Math.round or work with setDate.
  • 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

  1. 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).
  2. Print today’s date as "2 October 2026" using toLocaleDateString with options.
  3. Write formatDate(date) that returns DD-MM-YYYY with leading zeros.
  4. Write addDays(date, n) without changing the original date, and test it with n = 45.
  5. Find how many days are left until the next 1 January.
  6. Write getAge(birthDate) and test it with two different birthdays.
  7. Write daysInMonth(year, month) and test it with February of a leap year and a normal year.
  8. Write isWeekend(date) and use it to print “Weekend” or “Weekday” for 5 different dates.
  9. Sort an array of 4 events by date, nearest first.
  10. Check whether new Date("2026-13-45") is valid. Explain your result.
  11. Challenge: build a timeAgo(date) function that returns text such as "5 minutes ago", "2 hours ago" or "3 days ago", using Intl.RelativeTimeFormat.

Recap

  • A Date is stored as one number: the milliseconds since 1 January 1970 UTC (the timestamp). Get it with getTime() or Date.now().
  • Create dates with new Date() (now), new Date(year, month, day...), new Date("ISO text"), or new Date(milliseconds). Months start at 0.
  • Read parts with getFullYear, getMonth, getDate, getDay, getHours, getMinutes… Change them with the matching set methods. Setters change the original, so copy with new 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 compare getTime() for equality. Subtract two dates to get milliseconds.
  • Format dates for people with toLocaleDateString(locale, options), Intl.DateTimeFormat and Intl.RelativeTimeFormat. Use toISOString() for servers and storage.
  • Invalid input gives Invalid Date with NaN inside. Check it with Number.isNaN(date.getTime()).
  • Next you will learn regular expressions: patterns that let you search, check and replace text.