DateFormatter : concepts clés, formatage de date et localisation

Auteur : IT Sectr Publié le : 2026-07-12 Temps de lecture : 7 min

DateFormatter est une classe Foundation conçue pour la conversion bidirectionnelle entre les objets Date et leur représentation en chaîne. La classe prend en compte les paramètres régionaux, le fuseau horaire et le calendrier de l'utilisateur, garantissant un affichage correct des dates dans n'importe quelle région du monde. Selon la documentation développeur Apple (2025), DateFormatter prend en charge quatre styles prédéfinis de date et d'heure, ainsi que des formats entièrement personnalisés via une chaîne de modèle. Sans DateFormatter, il est impossible d'afficher correctement une date à l'utilisateur dans une application internationalisée.

Points clés

  • DateFormatter — une classe pour convertir Date en chaîne et vice-versa avec prise en charge des paramètres régionaux et du fuseau horaire.
  • dateStyle et timeStyle — des styles prédéfinis (.short, .medium, .long, .full) pour un formatage rapide.
  • dateFormat — une chaîne de modèle pour un format personnalisé spécifiée via les symboles Unicode LDML.
  • Locale et TimeZone — des propriétés du formateur qui déterminent l'affichage régional et le fuseau horaire.
  • ISO8601DateFormatter — une alternative plus rapide pour le format ISO 8601 lors de la sérialisation dans une API.

Qu'est-ce que DateFormatter ?

DateFormatter est une classe du framework Foundation qui implémente la conversion bidirectionnelle entre Date et chaîne. Elle est apparue pour la première fois dans OpenStep sous le nom de NSDateFormatter et est depuis restée l'outil principal de formatage des dates sur toutes les plateformes Apple. La classe hérite de Formatter et fournit une API pratique pour l'affichage localisé des dates.

DateFormatter fonctionne sur la base de modèles Unicode LDML — les mêmes que ceux utilisés dans ICU (International Components for Unicode). Le modèle est défini via la propriété dateFormat, où les symboles y, M, d, H, m, s correspondent à l'année, au mois, au jour, aux heures, aux minutes, aux secondes. La répétition d'un symbole détermine le format : « y » (année à deux chiffres), « yyyy » (année à quatre chiffres).

Créer un DateFormatter est une opération coûteuse, car les données des paramètres régionaux et du calendrier sont chargées lors de l'initialisation. Apple recommande de créer un formateur une fois pour chaque type de formatage et de le réutiliser. Dans SwiftUI et UIKit, les formateurs sont souvent mis en cache dans des propriétés statiques ou créés paresseusement lors du premier accès.

DateFormatter dans iOS SDK

DateFormatter est utilisé dans de nombreux composants système iOS. UIDatePicker utilise DateFormatter en interne pour afficher les dates en mode countDownTimer. Un TextField avec un formateur peut valider automatiquement les dates saisies par l'utilisateur. Core Data prend en charge les attributs de type Date, mais leur représentation en chaîne est toujours gérée via DateFormatter.

Sécurité des threads — DateFormatter n'est pas thread-safe. La modification des propriétés du formateur à partir de différents threads entraîne un comportement indéfini. Pour une utilisation multi-thread, créez des instances séparées du formateur pour chaque thread ou utilisez la synchronisation via NSLock ou une file d'attente série.

Styles de formatage de DateFormatter

dateStyle et timeStyle sont les moyens les plus simples de configurer l'affichage des dates. Chaque style a quatre variantes : .short, .medium, .long, .full. La combinaison de dateStyle et timeStyle permet une configuration indépendante du format de date et d'heure, et la propriété .none désactive la partie correspondante.

Pour les paramètres régionaux américains, .short formate la date comme « 7/21/26 », et pour les russes comme « 21.07.2026 ». Le style .long pour les paramètres régionaux russes affiche « 21 juillet 2026 », et .full affiche « mardi, 21 juillet 2026 » avec le jour de la semaine. Les quatre styles s'adaptent automatiquement aux normes régionales, y compris l'ordre des composants et les séparateurs.

SFDateFormatter dans iOS 15+ offre une approche alternative via RelativeDateFormatter et DateIntervalFormatter. RelativeDateFormatter affiche « aujourd'hui », « hier », « dans 3 jours » pour un contexte immédiat. DateIntervalFormatter affiche les plages de dates : « 21–25 juillet 2026 » — pour les réservations et la planification.

StyleExemple (ru_RU)Exemple (en_US)
.short21.07.20267/21/26
.medium21 juil. 2026Jul 21, 2026
.long21 juillet 2026July 21, 2026
.fullmardi, 21 juillet 2026Tuesday, July 21, 2026

Lors de la combinaison des styles, DateFormatter sélectionne automatiquement le séparateur : pour .short.date + .short.time, le résultat pourrait être « 21.07.2026, 14:30 ». Pour .full.date + .full.time — « mardi, 21 juillet 2026, 14:30:00 MSK ». Le séparateur est géré par les paramètres régionaux, pas par le développeur — cela garantit la conformité avec les attentes régionales de l'utilisateur.

Formats personnalisés via dateFormat

dateFormat permet de définir un motif de formatage arbitraire à l'aide de symboles de spécification Unicode LDML. Cela donne un contrôle total sur l'affichage : vous pouvez afficher uniquement l'année et le mois, ou le jour de la semaine sans la date, ou l'heure sans les secondes. Le format personnalisé est indispensable pour des exigences de conception spécifiques.

Symboles principaux — yyyy (année : 2026), MM (mois : 07), dd (jour : 21), HH (heures : 14), mm (minutes : 30), ss (secondes : 00). Pour le nom complet du mois, utilisez MMMM (juillet), pour l'abrégé — MMM (juil.). Jour de la semaine — EEEE (mardi), abrégé — E (mar.).

Lors de l'utilisation de dateFormat, il est important de définir les paramètres régionaux du formateur. Si les paramètres régionaux ne sont pas définis, le formateur utilise les paramètres régionaux du système, ce qui peut être indésirable pour un format fixe dans une API. Apple recommande de définir locale = Locale(identifier: « en_US_POSIX ») pour un format fixe inter-régional, en particulier lors de l'analyse des dates provenant des réponses du serveur.

swift
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"

// Analyse d'une chaîne personnalisée
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!

Une erreur dans dateFormat est l'une des causes courantes de plantage de l'application. Si le format ne correspond pas à la chaîne, la méthode date(from:) renvoie nil. Utilisez guard let ou ?? pour le déballage sécurisé des optionnels. Pour valider le format, testez-le dans toutes les langues prises en charge — certains symboles LDML fonctionnent différemment selon les paramètres régionaux.

Localisation et TimeZone

Locale détermine comment les noms des mois, des jours de la semaine et les séparateurs sont affichés. DateFormatter utilise Locale.current par défaut, mais dans certains scénarios, des paramètres régionaux spécifiques doivent être spécifiés : pour un format fixe dans les journaux, utilisez en_US_POSIX, pour les dates du serveur — les paramètres régionaux correspondant au serveur.

La propriété TimeZone détermine le fuseau horaire pour l'affichage. Par défaut, le fuseau horaire du système est utilisé, mais pour les applications avec un public international, il est souvent nécessaire d'afficher les dates dans le fuseau horaire de l'utilisateur ou en UTC. La modification de timeZone n'affecte que l'affichage — la valeur Date reste inchangée.

Une caractéristique importante : si DateFormatter est utilisé pour analyser une chaîne et que la chaîne contient une indication de fuseau horaire (par exemple, « 2026-07-21T14:30:00Z » avec Z pour UTC), la propriété timeZone est ignorée — le formateur utilise le fuseau horaire de la chaîne. Si le fuseau horaire est absent de la chaîne, le timeZone du formateur est appliqué.

swift
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
formatter.dateStyle = .long
formatter.timeStyle = .short

let moscowTime = formatter.string(from: Date())
// "21 July 2026, 14:30"

// Analyse sans fuseau horaire dans la chaîne
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!

AutoupdatingCurrentLocale — un type spécial de paramètres régionaux qui se met automatiquement à jour lorsque les paramètres système de l'utilisateur changent. DateFormatter le prend en charge par défaut. Si l'application s'exécute en arrière-plan et que l'utilisateur change la langue du système, un formateur créé avant le changement continuera d'utiliser les anciens paramètres régionaux — pour le mettre à jour, une nouvelle instance doit être créée.

ISO8601DateFormatter et alternatives

ISO8601DateFormatter est un formateur spécialisé pour travailler avec des dates au format ISO 8601. Ce format est le standard de facto pour les API REST, JSON et l'échange de données. ISO8601DateFormatter fonctionne beaucoup plus rapidement que DateFormatter car il ne dépend pas des paramètres régionaux et utilise une grammaire d'analyse fixe.

Options principales du formateur — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (ajoute des millisecondes), .withTimeZone (inclut le décalage horaire). En combinant les options, vous pouvez obtenir n'importe quelle variante ISO 8601 : avec millisecondes, avec fuseau horaire, avec date uniquement.

JSONEncoder.DateEncodingStrategy permet de configurer globalement l'encodage des dates pour tous les modèles Codable. Options — .iso8601 (utilise ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Le choix de la stratégie affecte l'ensemble du cycle de vie de la sérialisation et doit être cohérent sur tous les points de terminaison de l'API.

swift
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"

// JSONEncoder avec ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601

// Alternative : JSONEncoder avec formateur personnalisé
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)

DateFormatter vs ISO8601DateFormatter — choisissez ISO8601DateFormatter pour sérialiser et analyser les dates dans l'API, car il est 5 à 10 fois plus rapide que DateFormatter et n'est pas sujet aux erreurs de localisation. Utilisez DateFormatter pour l'interface utilisateur où un affichage localisé avec les noms des mois et des jours dans la langue maternelle de l'utilisateur est requis.

Exemples de formatage de dates

Examinons des scénarios réels d'utilisation de DateFormatter dans une application iOS : affichage dans un fil d'actualités, saisie d'une date de naissance et exportation d'un rapport avec des dates dans différents fuseaux horaires.

Affichage de la date d'une actualité dans une liste

RelativeDateFormatter est optimal pour les fils d'actualités. Il affiche « à l'instant », « il y a 5 minutes », « hier » pour les actualités récentes et passe à la date complète pour les anciennes. Le seuil de basculement est configuré via le calendrier : pour les actualités, utilisez un seuil de 24 heures, pour les messageries — une semaine.

swift
func formatRelativeDate(_ date: Date) -> String {
    let relative = RelativeDateFormatter()
    relative.unitsStyle = .full

    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    formatter.timeStyle = .short

    let daysDiff = Calendar.current.dateComponents(
        [.day], from: date, to: Date()
    ).day ?? 0

    return daysDiff < 1
        ? relative.localizedString(for: date, relativeTo: Date())
        : formatter.string(from: date)
}

Saisie d'une date de naissance — un autre scénario courant. DateFormatter est configuré avec un dateFormat spécifique « dd.MM.yyyy » et locale « ru_RU ». Lors de l'analyse de la chaîne saisie, il est important de gérer les erreurs potentielles : le formateur renvoie nil pour une chaîne invalide. Après une analyse réussie, la date est vérifiée pour être dans une plage acceptable — pas avant 1900, pas après aujourd'hui.

Exportation d'un rapport avec des dates nécessite un format fixe indépendant des paramètres régionaux de l'utilisateur. Utilisez dateFormat « yyyy-MM-dd HH:mm:ss » avec locale en_US_POSIX et fuseau horaire UTC. Cette approche garantit que le fichier s'ouvrira correctement dans n'importe quel pays, indépendamment des paramètres régionaux du système.

ScénarioFormateurConfiguration clé
Fil d'actualitésRelativeDateFormatterunitsStyle = .full
Saisie de dateDateFormatterdateFormat + secours
Sérialisation APIISO8601DateFormatterwithInternetDateTime
Exportation de rapportDateFormatteren_US_POSIX + UTC

Foire aux questions

Pourquoi DateFormatter renvoie-t-il nil pour une chaîne valide ?

La raison la plus courante — une inadéquation entre dateFormat et le format de la chaîne. Par exemple, le format « dd.MM.yyyy » n'analysera pas la chaîne « 2026-07-21 ». La deuxième raison — une inadéquation des paramètres régionaux : la chaîne « July 21, 2026 » ne sera pas analysée avec les paramètres régionaux ru_RU. La troisième — des fautes de frappe dans les symboles LDML : utilisez yyyy, pas YYYY (signification différente).

Dois-je créer un nouveau DateFormatter pour chaque appel ?

Non. DateFormatter est un objet lourd, son initialisation inclut le chargement des données des paramètres régionaux. Créez une instance par type de formatage et réutilisez-la. Dans un environnement multi-thread, utilisez le stockage local de thread ou un pool de formateurs avec une file d'attente série pour la synchronisation.

Quelle est la différence entre DateFormatter et RelativeDateFormatter ?

DateFormatter affiche une date absolue (21 juillet 2026), tandis que RelativeDateFormatter affiche une date relative (aujourd'hui, hier, dans 3 jours). RelativeDateFormatter a été introduit dans iOS 15+ et utilise le même modèle LDML mais sélectionne automatiquement l'affichage relatif.

Comment gérer les dates sans fuseau horaire provenant d'une API ?

Définissez le timeZone du formateur sur UTC avant l'analyse. Si le serveur renvoie une date en heure locale sans indication de fuseau horaire, vérifiez la spécification de l'API — très probablement, UTC est implicite. Pour ISO 8601 avec Z à la fin, timeZone n'est pas nécessaire — le formateur analyse le décalage à partir de la chaîne.

Comment rendre DateFormatter thread-safe ?

N'utilisez pas une seule instance à partir de différents threads sans synchronisation. Créez une nouvelle instance dans chaque thread ou utilisez Thread.current.threadDictionary pour le stockage. Une alternative est NSLock avec verrouillage pendant la durée de string(from:) et date(from:).

Résumé

  • DateFormatter — une classe Foundation pour convertir Date en chaîne et vice-versa avec prise en charge des paramètres régionaux, du fuseau horaire et du calendrier.
  • Styles prédéfinis dateStyle et timeStyle avec les variantes .short, .medium, .long, .full couvrent la plupart des scénarios d'interface utilisateur.
  • dateFormat personnalisé via les symboles LDML donne un contrôle total sur le format mais nécessite de la prudence avec la localisation.
  • Locale et TimeZone — des propriétés nécessaires pour un affichage correct : pour l'UI — paramètres régionaux du système, pour l'API — en_US_POSIX et UTC.
  • ISO8601DateFormatter — le choix préféré pour la sérialisation des dates dans l'API en raison de sa rapidité et de sa stabilité.
  • DateFormatter n'est pas thread-safe — utilisez des instances séparées pour chaque thread ou synchronisez l'accès.
  • RelativeDateFormatter (iOS 15+) — la solution optimale pour afficher les dates relatives dans les fils d'actualités et les messageries.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi