W3docs

Formatage des dates en Java

Formatez des dates et heures Java en chaînes avec DateTimeFormatter et des motifs standard ou personnalisés.

Le formatage de date consiste à transformer une valeur date/heure en chaîne lisible par un humain. Ce chapitre couvre DateTimeFormatter — comment en construire un (intégré, localisé ou basé sur un motif), l'alphabet complet des motifs, la gestion des locales et des fuseaux horaires, et les pièges qui produisent une sortie incorrecte. Il fonctionne avec tous les types java.time : LocalDate, LocalTime, LocalDateTime, ZonedDateTime et Instant.

Chaque type java.time possède un toString() qui produit la représentation ISO-8601 : 2025-11-04, 14:30:00, 2025-11-04T14:30:00Z. C'est parfait pour les journaux et les échanges machine à machine. Pour l'affichage destiné aux humains (« November 4, 2025 » ou « 4 Nov, 14:30 »), vous avez besoin d'un formateur.

La classe est java.time.format.DateTimeFormatter. C'est le remplaçant moderne, thread-safe et immuable du legacy java.text.SimpleDateFormat (qui n'était pas thread-safe et causait des bugs subtils en production lorsqu'il était partagé). Mettez-en un en cache comme static final et réutilisez-le entre les threads indéfiniment — pas de synchronisation, pas de copie défensive.

Trois façons de construire un formateur

// 1. Built-in ISO formatters
DateTimeFormatter.ISO_LOCAL_DATE;                  // 2025-11-04
DateTimeFormatter.ISO_LOCAL_DATE_TIME;             // 2025-11-04T14:30:00
DateTimeFormatter.ISO_OFFSET_DATE_TIME;            // 2025-11-04T14:30:00-05:00
DateTimeFormatter.ISO_ZONED_DATE_TIME;             // 2025-11-04T14:30:00-05:00[America/New_York]
DateTimeFormatter.ISO_INSTANT;                     // 2025-11-04T19:30:00Z
DateTimeFormatter.BASIC_ISO_DATE;                  // 20251104

// 2. Localised formatters
DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);          // November 4, 2025 (en-US)
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);    // Nov 4, 2025, 2:30:00 PM

// 3. Pattern-based formatters
DateTimeFormatter.ofPattern("dd MMM yyyy");                   // 04 Nov 2025
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm zzz");          // 2025-11-04 14:30 EST

L'API de motifs est celle que vous utiliserez le plus. La version localisée est appropriée lorsque vous avez besoin d'un format adapté à une culture et que vous souhaitez que le JDK choisisse la mise en page pour vous.

Formatage

La forme d'appel est symétrique des deux côtés :

String s = formatter.format(temporal);
String s2 = temporal.format(formatter);                       // same thing, fluent style

Les deux fonctionnent. La plupart du code utilise la forme fluide.

LocalDate today = LocalDate.now();
String us = today.format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));         // 11/04/2025
String iso = today.format(DateTimeFormatter.ISO_LOCAL_DATE);                 // 2025-11-04
String eu = today.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));          // 04.11.2025

L'alphabet des motifs

Le grand tableau — celui auquel vous reviendrez. Les lettres sont sensibles à la casse et le nombre de répétitions compte.

LettreSignificationExemple
yannéey2025, yy25, yyyy2025
MmoisM11, MM11, MMMNov, MMMMNovember
djour du moisd4, dd04
Ejour de la semaineETue, EEEETuesday
Hheure 0-23H14, HH14
hheure 1-12h2, hh02 (à utiliser avec a)
aAM/PMaPM
mminutem5, mm05
ssecondes9, ss09
Sfraction de secondeSSS123 (millis)
nnanosecondennnnnnnnn123456789
znom du fuseau horairezEST, zzzzEastern Standard Time
Zdécalage de fuseau horaireZ-0500, ZZ-0500, ZZZZGMT-05:00
Xdécalage ISOX-05, XX-0500, XXX-05:00
VID de fuseau horaireVVAmerica/New_York

Le texte littéral s'encadre entre guillemets simples :

DateTimeFormatter.ofPattern("EEEE, MMMM d 'at' h:mm a");      // Tuesday, November 4 at 2:30 PM

Pour un guillemet simple littéral, utilisez-en deux : ''.

La paire la plus source de confusion est m vs M (minuscule = minute, majuscule = mois) et H vs h (majuscule = 0-23, minuscule = 1-12). La plupart des bugs du type « l'heure est décalée de quelque chose de bizarre » proviennent d'une de ces fautes de frappe.

Localisation : Locale et withLocale

Un formateur utilise la locale par défaut de la JVM sauf indication contraire. Pour une sortie « toujours en anglais » ou « toujours en allemand », fixez la locale :

DateTimeFormatter english = DateTimeFormatter.ofPattern("EEEE, MMMM d", Locale.US);
DateTimeFormatter german  = DateTimeFormatter.ofPattern("EEEE, d. MMMM", Locale.GERMAN);
DateTimeFormatter french  = DateTimeFormatter.ofPattern("EEEE d MMMM", Locale.FRENCH);

today.format(english);   // Tuesday, November 4
today.format(german);    // Dienstag, 4. November
today.format(french);    // mardi 4 novembre

Pour le contenu rendu côté serveur, passez toujours une locale. La « locale par défaut de la JVM » est imprévisible sur les serveurs de production et est la source des bugs du type « ça marche sur ma machine, mais pas sur le serveur ».

Affichage du fuseau horaire

ZonedDateTime et Instant sont les seuls types qui disposent d'informations de fuseau horaire. Formater un LocalDateTime avec un motif incluant z ou Z lève une exception — il n'y a pas de fuseau à afficher. Convertissez d'abord :

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/New_York"));
zdt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm z"));   // 2025-11-04 14:30 EST

Pour Instant, le formateur a également besoin d'un fuseau — Instant n'en a pas, donc les formateurs d'affichage incluant des champs dépendant du fuseau horaire nécessitent un withZone :

DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
    .withZone(ZoneId.of("America/New_York"));
f.format(Instant.now());                                      // formatter supplies the zone for display

Sans withZone, le formatage d'un Instant avec un motif de forme calendaire lève une exception.

Formateurs stylisés avec FormatStyle

Les fabriques localisées vous donnent quatre tailles canoniques :

DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);   // 11/4/25 (en-US), 04.11.25 (de-DE)
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);  // Nov 4, 2025
DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);    // November 4, 2025
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);    // Tuesday, November 4, 2025

Ces quatre tailles existent également pour ofLocalizedTime et ofLocalizedDateTime. Utilisez-les lorsque vous souhaitez que la mise en page suive la locale de l'utilisateur plutôt que d'imposer une forme fixe. Combinez-les avec .withLocale(...) pour fixer la locale.

Exemple concret : une date, six variantes d'affichage

Le programme ci-dessous formate un seul ZonedDateTime de six façons courantes : ISO pour les journaux machine, 12 heures américain pour les utilisateurs anglophones, 24 heures européen pour les utilisateurs germanophones, une forme localisée longue, un motif personnalisé avec texte littéral intégré, et un formateur Instant-via-withZone pour les horodatages bruts.

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • Les champs static final DateTimeFormatter mis en cache ont la bonne forme. DateTimeFormatter est immuable et thread-safe ; créer une instance est peu coûteux mais pas gratuit, et réutiliser la même instance partout est le pattern recommandé par le JDK. Ne construisez pas un nouveau formateur dans une boucle chaude.
  • Le même ZonedDateTime a produit six chaînes différentes selon le formateur. L'objet valeur n'a jamais changé ; le formateur est le seul élément qui contrôle la mise en page. C'est la séparation pour laquelle DateTimeFormatter existe — gardez le type valeur propre, déléguez la présentation au formateur.
  • Le bloc « fautes de frappe courantes » a affiché 14:11 pour HH:MM parce que M est le mois, pas la minute. Ces deux lettres sont la paire la plus source de confusion dans l'alphabet des motifs. Si l'heure affichée ressemble étrangement à un composant de date, vérifiez la casse dans le motif.
  • L'échelle FormatStyle a produit quatre chaînes de longueur croissante. Utilisez FormatStyle.MEDIUM comme valeur par défaut sensée pour « afficher une date à un utilisateur sans trop réfléchir » ; LONG et FULL pour les contextes où l'année et le jour de la semaine doivent être sans ambiguïté ; SHORT pour les espaces d'interface restreints.
  • LocalDateTime avec un motif incluant un fuseau horaire a levé une exception — le formateur a besoin de données de fuseau horaire, et LocalDateTime n'en a pas. Le correctif consiste à convertir (ldt.atZone(zone)) ou à supprimer le champ lié au fuseau du motif. Dans tous les cas, le mode d'échec est clair à l'exécution.

Et ensuite

Le formatage est la direction valeur → chaîne. Le chapitre suivant, Analyse des dates Java, est l'inverse — chaîne → valeur — en utilisant les mêmes motifs DateTimeFormatter et les mêmes mises en garde. Les deux ensemble constituent la frontière d'E/S pour tout code qui échange des dates avec des utilisateurs, des configurations, des journaux ou des API distantes.

Pratique

Pratique
Un serveur web journalise les horodatages avec `ZonedDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm'))`. Sur une JVM avec locale allemande, le mois s'affiche 'Nov' au lieu de '11'. Quelle est la cause la plus probable ?
Un serveur web journalise les horodatages avec `ZonedDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm'))`. Sur une JVM avec locale allemande, le mois s'affiche 'Nov' au lieu de '11'. Quelle est la cause la plus probable ?
Was this page helpful?