DateComponents — qu'est-ce que c'est, composants de calendrier et NSCalendar

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

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 — une structure pour stocker les composants de date (année, mois, jour) comme champs entiers optionnels.
  • Calendar.dateComponents — une méthode qui extrait les composants spécifiés de Date en tenant compte du fuseau horaire.
  • Calendar.date(from:) — conversion inverse de DateComponents en Date avec remplissage automatique des champs manquants.
  • Champs optionnels — chaque champ de DateComponents peut être nil, permettant de spécifier des dates partielles.
  • Range et composants — DateComponents est utilisé dans Calendar pour calculer la différence entre les dates et trouver des dates dans une plage.

Qu'est-ce que DateComponents ?

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.

Optionalité des champs

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.

Composants de date : année, mois, jour

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égorieChampsPlage
Calendrieryear, month, day1..∞, 1..12, 1..31
Tempshour, minute, second, nanosecond0..23, 0..59, 0..59, 0..999999999
Semaineweekday, weekOfMonth, weekOfYear1..7, 1..5, 1..53
Spéciauxquarter, yearForWeekOfYear1..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.

Créer DateComponents

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.

swift
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.

Convertir DateComponents en Date

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.

swift
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 et DateComponents

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.

swift
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é.

Exemples DateComponents

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.

Rappel le premier jour de chaque mois

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.

swift
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âcheMéthode CalendarRôle DateComponents
Premier jour du moisnextDate(after:matching:)day: 1
Calcul d'âgedateComponents(from:to:)[.year] de la différence
Regroupement de datesdateComponents(_:from:)clé année + mois
Recherche de jour de semainenextDate(after:matching:)weekday: N

Questions fréquentes

Pourquoi Calendar.date(from:) retourne nil pour DateComponents ?

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.

Peut-on comparer DateComponents entre eux ?

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.

En quoi DateComponents diffère-t-il de Date ?

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.

Comment spécifier seulement l'année et le mois dans DateComponents ?

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.

Comment DateComponents gère-t-il les fuseaux horaires ?

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é

  • DateComponents — une structure Foundation pour stocker les composants calendaires (année, mois, jour, heure) comme champs optionnels Int ?.
  • Calendar.dateComponents extrait les composants de Date en tenant compte du fuseau horaire et du système calendaire.
  • Calendar.date(from:) assemble une Date à partir de DateComponents, en utilisant des valeurs par défaut pour les champs manquants.
  • Champs optionnels permettent de spécifier des dates partielles — Calendar comble les valeurs manquantes.
  • Calendar.nextDate trouve la prochaine date correspondant à DateComponents — pour les rappels et événements récurrents.
  • Calcul d'âge via Calendar.dateComponents([.year], from:to:) — la seule façon correcte qui prend en compte les années bissextiles.
  • MatchingPolicy contrôle le comportement de Calendar lorsque tous les composants ne correspondent pas — un paramètre important pour la recherche de dates.

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