Q1What happens if you declare let count = 0; inside the function passed to setInterval and try to stop it when count reaches 3?
Timers and Dates — setTimeout / Date / Intl
Call functions later with setTimeout, stop setInterval, handle Date's zero-based months, format dates with Intl.DateTimeFormat, and count days between dates.
Code that simply runs from top to bottom can't close a notification after 3 seconds or count down the time left once a second. And as long as a date is just a string, you can't show which day of the week it falls on or count the days left until a deadline.
This article covers setTimeout and setInterval, which set up timers, and Date and Intl.DateTimeFormat, which work with dates and times.
Scheduling a Call for Later — setTimeout and clearTimeout
Say a photo-sharing site shows an "Upload complete" notification, and you want to close it after 3 seconds. Code that runs from top to bottom has no way to say "wait 3 seconds, then run the next part", and if you kill time with an empty for loop, the page stops responding to clicks and stops updating until the loop finishes.
setTimeout(function, milliseconds) only schedules the call; execution moves straight on to the next line. It returns a timer ID, the same kind you used for the fetch timeout, and passing that ID to clearTimeout cancels the call.
// Returns a Promise that's fulfilled after ms milliseconds (the delay from the Promise article, without the value argument)
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Schedule closing the notification in 100ms, then move on right away (about 3000ms on a real page)
setTimeout(() => console.log("Notification closed"), 100); // Notification closed (2nd)
console.log("Upload complete"); // Upload complete (1st)
// The user left the page, so cancel the recommendations. This never runs, even after 100ms
const recommendTimer = setTimeout(() => console.log("Showing recommended photos"), 100);
clearTimeout(recommendTimer);
// Wait here 200ms before moving on
await delay(200);
console.log("Waited 200ms"); // Waited 200ms (3rd)
A scheduled function can run after the last line of your code has already finished. To see its output in the exercise console, end your code with a line that waits, such as await delay(…), as you did in the Promise article.
Stopping a Repeat — setInterval and clearInterval
Say you want to show the seconds left until a sale ends, counting down once per second. setTimeout calls the scheduled function only once, so to repeat it, the function would have to schedule itself again on every call, with the stop condition tangled up in that same code.
setInterval (a function that calls another function over and over at a fixed interval in milliseconds) keeps calling it until you pass the timer ID it returned to clearInterval.
To run the next line only after the repetition ends, wrap the whole thing in a Promise and call resolve right after clearInterval, inside the same if.
// Count down the seconds left by 1 every 100ms (every 1000ms on a real page)
function startCountdown(seconds) {
return new Promise((resolve) => {
let remaining = seconds; // Declared outside the callback, so it keeps its value between calls
const timerId = setInterval(() => {
remaining -= 1;
console.log(`Time left: ${remaining}s`); // Time left: 2s → Time left: 1s → Time left: 0s
if (remaining === 0) {
clearInterval(timerId); // Stop on the call that hits 0 (timerId is already assigned by then)
resolve(); // Let the await line know it's done
}
}, 100);
});
}
await startCountdown(3);
console.log("The sale has ended"); // The sale has ended
- Doesn't move to the next line until the returned Promise is fulfilled
The sale has endedprints after resolve
let remaining = seconds— created only once here, holding 3const timerId = setInterval(...)— the ID to pass when stopping
remaining -= 1— decrements the outer variable: 2 → 1 → 0- On the call that hits 0,
clearInterval(timerId)andresolve()
If you move let remaining = seconds inside the callback, it starts over at 3 on every call and never gets below 2, so neither clearInterval nor resolve is ever called. After 15 seconds, the exercise console gives up and reports a timeout.
An Interval You Never Stop Leaks into Later Runs
In this article, the exercise console runs every exercise on the same page. If a run ends without calling clearInterval, its callback keeps getting called until you reload the page, and its output leaks into the results of any later exercise that waits with await, so even correct code is marked wrong. If that happens, reload the article page.
Turning a Date into Display Text — getMonth and Intl
Say a video list shows each publish date in the form "Wed, September 2, 2026". If you slice the month out of an API string like "2026-09-02T09:00:00", you get the string "09", and since the day of the week isn't written anywhere, you can't work it out from the string alone.
Date (a built-in object that represents a date and time) reads "2026-09-02T09:00:00" as 9:00 AM in the device's time zone (a region's local time, defined by its offset from the reference time UTC), and its get methods return the month, the day of the week, and so on as numbers.
Intl.DateTimeFormat (a class that formats dates and times as strings for a given language) takes a locale such as "en-US" (US English) when you create it.
const publishedAt = new Date("2026-09-02T09:00:00");
// Methods starting with get return numbers. For months, January is 0; for days of the week, Sunday is 0
console.log(publishedAt.getMonth(), publishedAt.getDate(), publishedAt.getDay()); // 8 2 3
// Create a formatter by passing a language and the style for each part to show
const dateFormat = new Intl.DateTimeFormat("en-US", {
year: "numeric", // Year as a number
month: "long", // Month as a name, like "September"
day: "numeric", // Day as a number
weekday: "short", // Day of the week as a short name
});
console.log(dateFormat.format(publishedAt)); // Wed, September 2, 2026
console.log(new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "2-digit" }).format(publishedAt)); // 9:00 AM
// A string without a time is read as midnight UTC
const dateOnly = new Date("2026-09-02");
console.log(dateOnly.getDate()); // 2 in Japan, 1 in New York (8:00 PM the day before)
In time zones ahead of UTC, such as Japan, you still get 2, so the problem is easy to miss. When an API sends a date-only string, append "T00:00:00" before passing it to new Date so it's read as midnight local time. The table below lists what the get methods return for publishedAt.
| Method | For publishedAt | For display |
|---|---|---|
| getFullYear() | 2026 | Use directly |
| getMonth() | 8 | January is 0; add 1 to get 9 |
| getDate() | 2 | Starts at 1; use directly |
| getDay() | 3 | Sunday is 0, so 3 is Wed |
| getHours() | 9 | 24-hour clock, 0–23 |
Counting the Days Until a Deadline — Subtracting Dates
Say a library site shows how many days are left until a book is due. If you subtract just the day-of-month numbers, a book borrowed on September 2 and due October 3 comes out to 3 - 2 = 1 day, because the days in between that belong to September aren't counted.
Internally, a Date is a number: the milliseconds elapsed since midnight UTC on January 1, 1970. Subtracting one Date from another gives the difference in milliseconds, so dividing by the milliseconds in one day, 24 * 60 * 60 * 1000, gives the number of days.
new Date(year, month, day) creates midnight local time on that day, and here too, months count from 0.
// Milliseconds in one day (24 hours × 60 minutes × 60 seconds × 1000)
const DAY_MS = 24 * 60 * 60 * 1000;
// Borrow date and due date. When you create them from numbers, months still count from 0
const borrowedAt = new Date(2026, 8, 2); // September 2, 2026
const dueDate = new Date(2026, 9, 3); // October 3, 2026
// Subtracting one Date from another gives the difference in milliseconds
const diffMs = dueDate - borrowedAt;
console.log(Math.round(diffMs / DAY_MS)); // 31
// Passing 31, a day September doesn't have, rolls over into the next month instead of throwing an error
const overflowDate = new Date(2026, 8, 31);
console.log(overflowDate.getMonth() + 1, overflowDate.getDate()); // 10 1
The code rounds with Math.round because of daylight saving time (moving clocks forward one hour in summer). Where it's observed, some days are 23 or 25 hours long, so the division doesn't always come out to a whole number; you might get something like 30.958… instead. In places without it, such as Japan, the division is always exact, so it's easy to forget the rounding.
Knowledge Check
Answer each question one by one.
Q2What does new Date("2026-09-02T09:00:00").getMonth() return?
Q3What does getDate() return for a Date created with new Date(2026, 8, 31)?