Question 1Que se passe-t-il si tu déclares let count = 0; dans la fonction passée à setInterval et que tu essaies de l'arrêter quand count atteint 3 ?
Minuteurs et dates — setTimeout / Date / Intl
setTimeout, l'arrêt de setInterval, les mois de Date comptés à partir de 0, l'affichage avec Intl.DateTimeFormat et l'écart en jours.
Fermer une notification au bout de 3 secondes, ou décompter les secondes restantes une fois par seconde : du code qui s'exécute simplement de haut en bas n'en est pas capable. Et tant qu'une date reste une chaîne, tu ne peux ni afficher le jour de la semaine d'une date de publication, ni compter les jours qui restent avant une échéance.
Cet article couvre setTimeout et setInterval, qui créent des minuteurs, ainsi que Date et Intl.DateTimeFormat, qui servent à manipuler les dates et les heures.
Programmer un appel pour plus tard — setTimeout et clearTimeout
Sur un site de partage de photos, tu affiches la notification « Photo publiée » et tu veux la fermer au bout de 3 secondes. Du code qui s'exécute de haut en bas n'a aucun moyen de dire « attends 3 secondes, puis passe à la suite ». Et si tu fais tourner une boucle for à vide pour gagner du temps, la page cesse de réagir aux clics et de se mettre à jour tant que la boucle tourne.
setTimeout(fonction, millisecondes) se contente de programmer l'appel : l'exécution passe aussitôt à la ligne suivante. La fonction renvoie un identifiant de minuteur, le même genre d'identifiant que celui du timeout de fetch, et le passer à clearTimeout annule l'appel.
// Renvoie une Promise fulfilled au bout de ms millisecondes (le delay de l'article sur Promise, sans l'argument value)
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Programme la fermeture de la notification dans 100 ms et passe tout de suite à la ligne suivante (plutôt 3000 ms sur une vraie page)
setTimeout(() => console.log("Notification fermée"), 100); // Notification fermée (2e)
console.log("Photo publiée"); // Photo publiée (1re)
// L'utilisateur a quitté la page : on annule l'affichage des recommandations. Il n'a jamais lieu, même après 100 ms
const recommendTimer = setTimeout(() => console.log("Photos recommandées affichées"), 100);
clearTimeout(recommendTimer);
// On attend 200 ms avant de continuer
await delay(200);
console.log("200 ms plus tard"); // 200 ms plus tard (3e)
Une fonction programmée peut s'exécuter alors que la dernière ligne de ton code est déjà terminée. Pour voir ce qu'elle affiche dans la console des exercices, termine ton code par une ligne qui attend, comme await delay(…), ainsi que tu l'as fait dans l'article sur Promise.
Arrêter une répétition — setInterval et clearInterval
Tu veux afficher le nombre de secondes avant la fin d'une vente flash, en le diminuant chaque seconde. setTimeout n'appelle la fonction programmée qu'une seule fois : pour répéter, il faudrait que la fonction se reprogramme elle-même à chaque appel, et la condition d'arrêt se retrouverait noyée dans ce même code.
setInterval (une fonction qui appelle la même fonction encore et encore, toutes les N millisecondes) continue de l'appeler jusqu'à ce que tu passes à clearInterval l'identifiant de minuteur qu'elle a renvoyé.
Pour n'exécuter la ligne suivante qu'une fois la répétition terminée, enveloppe le tout dans une Promise et appelle resolve juste après clearInterval, dans le même if.
// Diminue de 1 le nombre de secondes restantes toutes les 100 ms (toutes les 1000 ms sur une vraie page)
function startCountdown(seconds) {
return new Promise((resolve) => {
let remaining = seconds; // Déclarée hors de la fonction appelée, pour garder sa valeur d'un appel à l'autre
const timerId = setInterval(() => {
remaining -= 1;
console.log(`Temps restant : ${remaining} s`); // Temps restant : 2 s → 1 s → 0 s
if (remaining === 0) {
clearInterval(timerId); // On arrête à l'appel qui atteint 0 (timerId est déjà affecté à ce moment-là)
resolve(); // On prévient la ligne await que c'est fini
}
}, 100);
});
}
await startCountdown(3);
console.log("La vente flash est terminée"); // La vente flash est terminée
- Ne passe pas à la ligne suivante tant que la Promise renvoyée n'est pas fulfilled
La vente flash est terminées'affiche après resolve
let remaining = seconds— créée une seule fois ici, avec la valeur 3const timerId = setInterval(...)— l'identifiant à passer pour arrêter
remaining -= 1— diminue la variable externe : 2 → 1 → 0- À l'appel qui atteint 0 :
clearInterval(timerId)etresolve()
Si tu déplaces let remaining = seconds dans la fonction appelée, la variable repart de 3 à chaque appel et n'atteint jamais 0 : ni clearInterval ni resolve ne sont appelés. Au bout de 15 secondes sans avancer, la console des exercices indique que l'exécution a expiré.
Une répétition jamais arrêtée se mélange aux exécutions suivantes
Dans cet article, la console des exercices utilise la même page pour toutes les exécutions. Si une exécution se termine sans appeler clearInterval, sa fonction continue d'être appelée jusqu'à ce que tu recharges la page. Ce qu'elle affiche se mélange alors aux résultats des exercices lancés ensuite qui attendent avec await, et même un code correct est jugé faux. Si ça arrive, recharge la page de l'article.
Transformer une date en texte à afficher — getMonth et Intl
Dans une liste de vidéos, tu veux afficher la date de publication sous la forme « mer. 2 septembre 2026 ». Si tu extrais avec slice le mois d'une chaîne envoyée par l'API, comme "2026-09-02T09:00:00", tu obtiens la chaîne "09". Et le jour de la semaine n'y figure nulle part : impossible de le trouver à partir de la chaîne seule.
Date (un objet intégré qui représente une date et une heure) lit "2026-09-02T09:00:00" comme 9 h dans le fuseau horaire de l'appareil (l'heure locale d'une région, définie par son décalage avec l'heure de référence UTC), et ses méthodes qui commencent par get renvoient le mois, le jour de la semaine, etc., sous forme de nombres.
Intl.DateTimeFormat (une classe qui met en forme dates et heures selon les conventions d'une langue) se crée en lui passant une locale, par exemple "fr-FR" (français de France).
const publishedAt = new Date("2026-09-02T09:00:00");
// Les méthodes en get renvoient des nombres. Janvier vaut 0 pour les mois, dimanche vaut 0 pour les jours de la semaine
console.log(publishedAt.getMonth(), publishedAt.getDate(), publishedAt.getDay()); // 8 2 3
// On crée un format en passant la langue et la forme de chaque élément à afficher
const dateFormat = new Intl.DateTimeFormat("fr-FR", {
year: "numeric", // L'année en chiffres
month: "long", // Le mois en toutes lettres, comme "septembre"
day: "numeric", // Le jour en chiffres
weekday: "short", // Le jour de la semaine en abrégé
});
console.log(dateFormat.format(publishedAt)); // mer. 2 septembre 2026
console.log(new Intl.DateTimeFormat("fr-FR", { hour: "numeric", minute: "2-digit" }).format(publishedAt)); // 9:00
// Une chaîne sans heure est lue comme minuit UTC
const dateOnly = new Date("2026-09-02");
console.log(dateOnly.getDate()); // 2 au Japon, 1 à New York (la veille à 20 h)
Dans les fuseaux en avance sur UTC, comme au Japon, tu obtiens quand même 2 : le problème passe donc facilement inaperçu. Quand l'API envoie une date sans heure, ajoute "T00:00:00" avant de la passer à new Date, pour qu'elle soit lue comme minuit en heure locale. Le tableau ci-dessous résume ce que renvoient les méthodes en get pour publishedAt.
| Méthode | publishedAt | Pour l'affichage |
|---|---|---|
| getFullYear() | 2026 | Tel quel |
| getMonth() | 8 | Janvier = 0 : +1 → 9 |
| getDate() | 2 | Commence à 1 : tel quel |
| getDay() | 3 | Dimanche = 0 : 3 = mer. |
| getHours() | 9 | Format 24 h, de 0 à 23 |
Compter les jours avant une échéance — soustraire des objets Date
Sur le site d'une bibliothèque, tu veux afficher le nombre de jours qui restent avant la date de retour d'un livre. Si tu soustrais seulement les numéros de jour, un livre emprunté le 2 septembre et à rendre le 3 octobre donne 3 − 2 = 1 jour : les jours du mois de septembre qui séparent les deux dates ne sont pas comptés.
Un objet Date contient, sous forme de nombre, les millisecondes écoulées depuis le 1er janvier 1970 à minuit (UTC). Soustraire un objet Date d'un autre renvoie cet écart : en le divisant par le nombre de millisecondes d'une journée, 24 * 60 * 60 * 1000, tu obtiens un nombre de jours.
new Date(année, mois, jour) crée ce jour-là à minuit, et là aussi, les mois se comptent à partir de 0.
// Millisecondes dans une journée (24 heures × 60 minutes × 60 secondes × 1000)
const DAY_MS = 24 * 60 * 60 * 1000;
// Date d'emprunt et date de retour. Même quand on les crée avec des nombres, les mois se comptent à partir de 0
const borrowedAt = new Date(2026, 8, 2); // 2 septembre 2026
const dueDate = new Date(2026, 9, 3); // 3 octobre 2026
// Soustraire un objet Date d'un autre donne l'écart en millisecondes
const diffMs = dueDate - borrowedAt;
console.log(Math.round(diffMs / DAY_MS)); // 31
// Passer 31, un jour qui n'existe pas en septembre, ne lève pas d'erreur : on bascule sur le mois suivant
const overflowDate = new Date(2026, 8, 31);
console.log(overflowDate.getMonth() + 1, overflowDate.getDate()); // 10 1
Le code arrondit avec Math.round à cause de l'heure d'été (le fait d'avancer les horloges d'une heure pendant l'été). Là où elle s'applique, certaines journées durent 23 ou 25 heures, et la division ne tombe pas toujours juste : tu peux obtenir par exemple 30.958… au lieu d'un entier. Au Japon, où il n'y a pas d'heure d'été, la division tombe toujours juste, et on oublie facilement d'arrondir.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Que renvoie new Date("2026-09-02T09:00:00").getMonth() ?
Question 3Que renvoie getDate() pour un objet Date créé avec new Date(2026, 8, 31) ?