DateComponents est une structure de Foundation qui stocke les composants d'une date calendaire sous forme de champs séparés : année, mois, jour, heure, minute, seconde et autres. Contrairement à Date, qui représente un moment absolu dans le temps, DateComponents contient des valeurs lisibles par l'homme qui dépendent du calendrier et du fuseau horaire. Selon la documentation Apple Developer (2025), DateComponents est utilisée comme lien intermédiaire entre Date et Calendar — à travers elle, les dates calendaires sont extraites et construites, les calculs et les décalages de dates sont effectués sans arithmétique manuelle.
Points clés
DateComponents est un type valeur de Foundation conçu pour stocker les composants temporels calendaires. Chaque composant est représenté par un champ Int optionnel : year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear et autres.
La principale différence avec Date est la liaison au calendrier. Date stocke le temps absolu (nombre de secondes depuis la date de référence), tandis que DateComponents est une représentation lisible qui n'a de sens que dans le contexte d'un Calendar spécifique. Une même Date peut être représentée par différents DateComponents dans différents calendriers et fuseaux horaires.
DateComponents n'est pas un type de temps indépendant, mais un conteneur de données. Pour interpréter DateComponents comme une date, un Calendar est nécessaire pour comprendre comment les composants se rapportent au système calendaire. Calendar.dateComponents(from: Date) effectue l'extraction des composants, Calendar.date(from: DateComponents) effectue l'assemblage inverse.
Chaque champ de DateComponents est optionnel (Int ?), ce qui est fondamental pour travailler avec des dates partielles. Si seulement l'année et le mois sont spécifiés, Calendar remplit les champs manquants avec des valeurs par défaut : jour = 1, heure = 0, minute = 0. C'est pratique pour créer des dates de début de période — il suffit de spécifier les composants concernés.
Lors de la comparaison de DateComponents avec l'opérateur ==, seuls les champs spécifiés (non nil) sont comparés. Deux structures DateComponents avec la même année 2026 mais des mois différents sont considérées comme distinctes. isEqual de NSObjectProtocol ne s'applique pas à DateComponents — DateComponents n'hérite pas de NSObject.
Champs principaux de DateComponents incluent year, month, day, hour, minute, second, nanosecond. Chaque champ stocke une valeur numérique dans l'unité correspondante : année — 2026, mois — 1..12, jour — 1..31, heure — 0..23, minute — 0..59, seconde — 0..59. Les nanosecondes peuvent aller de 0 à 999999999.
Champs de semaine — weekday (1..7, où 1 = dimanche dans le calendrier grégorien), weekOfMonth, weekOfYear. Ces champs dépendent du Calendar et n'ont pas de sens en dehors de son contexte. weekday dépend du paramètre firstWeekday du calendrier : dans la locale russe, la semaine commence le lundi (weekday = 2 dans le système grégorien), tandis que dans la locale américaine, elle commence le dimanche (weekday = 1).
Champs spécialisés — quarter (1..4), yearForWeekOfYear (l'année à laquelle appartient la semaine), isLeapMonth (un indicateur booléen pour les mois bissextiles dans les calendriers hébraïque ou chinois). Les champs calendar et timeZone stockent des références aux objets correspondants avec lesquels la structure a été créée.
| Catégorie | Champs | Plage |
|---|---|---|
| Calendrier | year, month, day | 1..∞, 1..12, 1..31 |
| Temps | hour, minute, second, nanosecond | 0..23, 0..59, 0..59, 0..999999999 |
| Semaine | weekday, weekOfMonth, weekOfYear | 1..7, 1..5, 1..53 |
| Spéciaux | quarter, yearForWeekOfYear | 1..4, dépendant |
Lors de l'extraction de composants via Calendar.dateComponents, il est important de ne demander que les champs nécessaires pour la performance. Calendar extrait tous les champs demandés en un seul passage — c'est considérablement plus rapide que d'appeler Calendar.component pour chaque champ individuellement.
Initialiser DateComponents — la façon la plus simple : créer une structure vide et remplir les champs nécessaires. Tous les champs non spécifiés reçoivent automatiquement nil. Une date créée à partir de composants partiels n'est pas validée à l'initialisation — une erreur ne peut survenir que lors de la conversion en Date via Calendar.
L'initialiseur DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) permet de définir tous les champs en un seul appel. Cet initialiseur est pratique pour créer une date complète à partir de valeurs prêtes, mais est rarement utilisé avec plus de 5-6 arguments en raison de la lisibilité.
Calendar.dateComponents(_:from:) — la méthode principale pour obtenir DateComponents à partir d'un Date existant. Le deuxième argument est l'ensemble des composants à extraire. Calendar effectue les calculs calendaires en tenant compte du fuseau horaire et retourne une structure avec seulement les champs demandés ; les champs restants restent nil.
import Foundation
// Création via initialiseur de champs
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21
// Extraction de Date
let now = Date()
let extracted = Calendar.current.dateComponents(
[.year, .month, .day],
from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")
// Création via initialiseur étendu
let birthday = DateComponents(
calendar: Calendar.current,
year: 1990, month: 5, day: 15
)
Lors de la création de DateComponents en définissant manuellement les champs, vérifiez toujours le Calendar avant la conversion en Date. Lors de la conversion date(from:), Calendar peut retourner nil si les composants forment une date inexistante — par exemple, le 31 février ou le 30 février dans une année non bissextile. La validation de la date est la responsabilité de Calendar, pas de DateComponents.
Calendar.date(from:) — la méthode principale pour convertir DateComponents en Date. Calendar interprète les composants selon son propre calendrier et fuseau horaire. Si certains champs ne sont pas définis (nil), Calendar utilise des valeurs par défaut : jour = 1, heure = 0, minute = 0, seconde = 0.
La méthode retourne une Date optionnelle — nil se produit si les composants se contredisent ou forment une date invalide. Causes typiques de nil : date inexistante (32 janvier, 29 février 2023), champs contradictoires (weekday=1, day=5 dans le même ensemble), année impossible pour le calendrier donné (année 0 dans le calendrier grégorien).
DateComponents avec timeZone — si DateComponents contient une timeZone, Calendar l'utilise lors de la conversion. Si timeZone n'est pas spécifiée, Calendar utilise sa propre timeZone actuelle. Si Calendar.timeZone ne correspond pas au fuseau horaire attendu de la date, le résultat peut différer de plusieurs heures — assurez-vous que timeZone est explicitement définie dans l'un des objets.
let calendar = Calendar(identifier: .gregorian)
// Création de Date à partir de DateComponents
var comps = DateComponents()
comps.year = 2026
comps.month = 12
comps.day = 25
comps.hour = 10
if let date = calendar.date(from: comps) {
print("Christmas: \(date)")
}
// Création avec spécification de timeZone
calendar.timeZone = TimeZone(identifier: "UTC")!
let utcComps = DateComponents(
calendar: calendar, year: 2026, month: 7, day: 21,
hour: 12
)
let utcDate = calendar.date(from: utcComps)!
Calendar.dateComponents pour la différence de dates — un autre cas d'utilisation de DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) retourne la différence en années, mois et jours entre deux dates. C'est la façon correcte de calculer l'âge au lieu de diviser TimeInterval par le nombre de secondes dans une année, car Calendar prend en compte les années bissextiles.
Calendar — la classe centrale qui travaille avec DateComponents. Toutes les opérations d'extraction, d'assemblage et de comparaison des dates passent par Calendar. Sans Calendar, DateComponents n'est qu'un ensemble de nombres sans signification temporelle. Calendar donne aux composants leur interprétation : il détermine que le mois 2 est février et que weekday 2 est lundi.
Calendar.nextDate et Calendar.enumerateDates — deux méthodes basées sur DateComponents. nextDate(after: Date(), matching: DateComponents) trouve la prochaine date correspondant aux composants spécifiés — par exemple, le prochain lundi après aujourd'hui. enumerateDates(startingAfter:matching:matchingPolicy:using:) parcourt toutes les dates correspondant au motif jusqu'à la limite spécifiée.
Calendar.dateInterval — une méthode qui retourne un DateInterval pour le composant spécifié. dateInterval(of: .month, for: Date()) retourne le début et la fin du mois actuel. En interne, cette méthode utilise DateComponents pour trouver les limites de la période : elle crée DateComponents avec le premier et le dernier jour du mois et les convertit en Date via Calendar.
let calendar = Calendar.current
// Lundi prochain
let nextMonday = calendar.nextDate(
after: Date(),
matching: DateComponents(weekday: 2),
matchingPolicy: .nextTime
)!
// Différence entre dates en jours
let diff = calendar.dateComponents(
[.day], from: Date(), to: nextMonday
)
// Plage du mois
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end
MatchingPolicy — un paramètre important des méthodes Calendar lors du travail avec DateComponents. strictPolicy exige une correspondance exacte de tous les composants, nextTimePolicy sélectionne la correspondance temporelle suivante, nextTimePreservingSmallerComponents préserve les composants plus petits (minutes, secondes) de la date source. Le choix de la politique affecte le résultat de la recherche de dates, en particulier lors du déplacement à travers les changements d'heure d'été.
Explorons des cas d'utilisation pratiques de DateComponents dans une application. Chaque exemple illustre une tâche typique à laquelle un développeur iOS est confronté lorsqu'il travaille avec des dates calendaires.
Calendar.nextDate avec DateComponents(day: 1) trouve le premier jour du mois suivant. Calendar détermine automatiquement le nombre de jours dans le mois actuel et passe au suivant. Pour les notifications récurrentes, utilisez enumerateDates ou Combine.Timer avec une clé Calendar.
func firstDayOfNextMonth(from date: Date) -> Date {
let calendar = Calendar.current
let comps = DateComponents(day: 1)
return calendar.nextDate(
after: date,
matching: comps,
matchingPolicy: .nextTime
)!
}
// Calcul d'âge en années
func ageInYears(from birthDate: Date) -> Int {
let calendar = Calendar.current
let ageComponents = calendar.dateComponents(
[.year], from: birthDate, to: Date()
)
return ageComponents.year ?? 0
}
// Regroupement d'événements par année et mois
func groupEventsByMonth(_ events: [Event]) -> [String: [Event]] {
let calendar = Calendar.current
return Dictionary(grouping: events) { event in
let comps = calendar.dateComponents(
[.year, .month], from: event.date
)
return "\(comps.year!)-\(comps.month!)"
}
}
Calcul d'âge via Calendar.dateComponents([.year], from:to:) — la seule façon correcte qui prend en compte les années bissextiles. Le calcul basé sur TimeInterval (secondes / 31536000) donne une erreur pour les personnes nées le 29 février. Calendar détermine correctement si l'anniversaire a eu lieu dans l'année en cours et retourne l'âge exact.
Regroupement par année et mois — une tâche courante pour les écrans d'historique ou de calendrier. DateComponents sert de clé de regroupement : extrayez l'année et le mois de la date de l'événement, formez une clé de chaîne et regroupez via Dictionary(grouping:). Pour l'affichage, utilisez DateFormatter avec le modèle « LLLL yyyy » pour un nom de mois localisé.
| Tâche | Méthode Calendar | Rôle DateComponents |
|---|---|---|
| Premier jour du mois | nextDate(after:matching:) | day: 1 |
| Calcul d'âge | dateComponents(from:to:) | [.year] de la différence |
| Regroupement de dates | dateComponents(_:from:) | clé année + mois |
| Recherche de jour de semaine | nextDate(after:matching:) | weekday: N |
Questions fréquentes
Causes : date inexistante (31 avril), champs contradictoires (weekday=1 avec day=5), combinaison invalide de champs pour le calendrier sélectionné. Calendar essaie d'interpréter les composants dans son système — si la combinaison est impossible, le résultat est nil. Utilisez toujours guard let ou if let lors de la conversion.
Oui, via l'opérateur ==. DateComponents implémente Equatable, comparant tous les champs. Deux structures sont égales si tous leurs champs sont égaux (nil == nil est considéré comme vrai). Pour comparer seulement un sous-ensemble de champs — extrayez le même ensemble via Calendar.dateComponents.
Date est un moment absolu dans le temps sans liaison au calendrier. DateComponents est un ensemble de nombres lisibles (année, mois, jour) qui n'ont de sens que dans le contexte d'un Calendar. Date peut être comparé, soustrait, sérialisé en ISO 8601. DateComponents est une représentation intermédiaire pour interagir avec le calendrier.
Définissez uniquement les champs year et month, en laissant les autres à nil. Lors de la conversion en Date via Calendar.date(from:), Calendar définira automatiquement jour = 1, heure = 0, minute = 0. Le résultat est un Date correspondant au premier jour du mois spécifié à minuit.
DateComponents ne stocke pas d'informations de fuseau horaire dans ses champs — les valeurs des champs (année, mois, jour) dépendent elles-mêmes de la timeZone dans laquelle elles ont été extraites. Les composants « 21 juillet 2026 14:00 MSK » et « 21 juillet 2026 10:00 UTC » représentent la même Date, mais les champs DateComponents sont différents.
Résumé
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.
Lisez aussi