Calendar est une classe Foundation qui définit un système calendaire et fournit des méthodes pour les calculs calendaires : extraction de composants de date, calcul de différences entre dates, recherche de limites de périodes et décalage de dates. Le calendrier relie le temps absolu (Date) aux composants lisibles par l'homme et prend en compte les particularités régionales : début de semaine, fuseau horaire et heure d'été. Selon la documentation Apple Developer (2025), Foundation prend en charge 17 systèmes calendaires — du grégorien au bouddhiste et au japonais — faisant de Calendar un outil universel pour les applications internationalisées.
Points clés
Calendar est une classe Foundation qui implémente des calculs calendaires basés sur ICU (International Components for Unicode). Le calendrier définit comment le temps absolu (Date) correspond aux composants calendaires : année, mois, jour, heure, minute, seconde. Sans Calendar, il est impossible de savoir quelle année, quel mois et quel jour on est — Date lui-même ne contient pas cette information.
Le calendrier prend en compte trois groupes de paramètres : le système calendaire (grégorien, bouddhiste, japonais), le fuseau horaire et les paramètres régionaux. Calendar.current combine les trois à partir des paramètres système de l'utilisateur. Calendar.autoupdatingCurrent est une version spéciale qui se met automatiquement à jour lors des changements de paramètres sans redémarrer l'application via NotificationCenter.
Calendar est un type valeur (value type) dans Foundation. Calendar(identifier:) crée une nouvelle instance avec des paramètres fixes. Calendar peut être copié, comparé avec == et utilisé comme clé de dictionnaire. Cela permet de créer des calendriers avec des paramètres timeZone et locale spécifiques pour les tests.
Calendar est la version Swift de NSCalendar d'Objective-C, pontée via as Calendar / as NSCalendar. Dans Swift moderne, Calendar est utilisé partout. NSCalendar reste pour la rétrocompatibilité avec les API Objective-C. Calendar dispose d'un ensemble complet de méthodes sans le préfixe NS, avec des arguments type-safe et des optionnels Swift.
Sécurité des threads — Calendar est thread-safe pour la lecture. Une instance créée peut être lue en toute sécurité depuis plusieurs threads. La modification des propriétés (timeZone, locale) n'est pas thread-safe — créez des instances séparées de Calendar pour différentes configurations.
Foundation prend en charge 17 systèmes calendaires via l'énumération Calendar.Identifier. Chaque système a ses propres règles pour les années bissextiles, le nombre de mois et le début de l'ère. Le choix du calendrier affecte tous les calculs : dateComponents, dateInterval, nextDate.
Principaux systèmes calendaires :
Calendar(identifier: .gregorian) — le plus utilisé. Il est conforme à la norme internationale ISO 8601 et est le calendrier par défaut dans la plupart des pays. Pour les applications avec un public international, utilisez Calendar.current — il correspond automatiquement au calendrier système de l'utilisateur.
| Identifiant | Type | Région d'utilisation |
|---|---|---|
| .gregorian | Solaire | International |
| .buddhist | Solaire | Thaïlande, Cambodge |
| .japanese | Solaire | Japon |
| .hebrew | Lunisolaire | Israël |
| .islamic | Lunaire | Pays islamiques |
| .chinese | Lunisolaire | Chine |
DateComponents et Calendar sont une paire indissociable. Calendar.dateComponents(_:from:) extrait les composants de Date en respectant le fuseau horaire du calendrier. Calendar.date(from:) assemble une Date à partir de DateComponents, en remplissant les champs manquants avec des valeurs par défaut : jour = 1, heure = 0, minute = 0, seconde = 0.
La méthode Calendar.component extrait un seul composant, pratique pour les vérifications rapides. Calendar.dateComponents extrait plusieurs composants en un seul appel — c'est plus performant car Calendar effectue les calculs calendaires une seule fois plutôt que pour chaque composant séparément. Pour une liste de 3+ composants, utilisez toujours dateComponents.
Calendar.compare compare deux Dates avec une précision déterminée. Le paramètre toGranularity définit la précision du composant : .year compare seulement l'année, .month — l'année et le mois, .day — l'année, le mois, le jour. Utile pour vérifier si deux dates tombent le même jour, sans tenir compte de l'heure.
let calendar = Calendar.current
let now = Date()
// Extraire un seul composant
let year = calendar.component(.year, from: now)
// Extraire un ensemble de composants
let comps = calendar.dateComponents(
[.year, .month, .day], from: now
)
// Comparer avec une granularité de jour
let isSameDay = calendar.compare(date1, to: date2,
toGranularity: .day) == .orderedSame
// Vérifier si la date est aujourd'hui
let isToday = calendar.isDateInToday(someDate)
Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — méthodes pour les vérifications relatives. Calendar.isDate(_:inSameDayAs:) vérifie si deux dates tombent le même jour calendaire en tenant compte du fuseau horaire du calendrier. Ces méthodes utilisent Calendar.compare en interne et sont optimisées pour les appels fréquents.
Calendar.dateInterval est l'une des méthodes les plus utiles pour l'analyse et l'interface utilisateur. Elle retourne un DateInterval pour le composant spécifié : début et fin d'un jour, d'une semaine, d'un mois, d'une année. DateInterval contient start (Date) et end (Date) — les limites de la période. Par exemple, dateInterval(of: .weekOfYear, for: Date()) retourne le début du lundi et la fin du dimanche de la semaine en cours.
Calendar.date avec byAdding — une méthode pour décaler les dates. Calendar.date(byAdding: .day, value: 7, to: Date()) retourne la date une semaine plus tard. Calendar.date(byAdding: DateComponents) est une version plus flexible permettant de décaler plusieurs composants à la fois : +1 mois +3 jours. Calendar prend automatiquement en compte les différentes longueurs des mois et les années bissextiles.
Calendar.nextDate recherche la date suivante correspondant aux DateComponents spécifiés. Le paramètre matchingPolicy définit le comportement en cas de non-correspondance : .nextTime — la prochaine correspondance horaire, .nextTimePreservingSmallerComponents — conserve les minutes et secondes de la date d'origine, .strict — exige une correspondance exacte.
let calendar = Calendar.current
let today = Date()
// Début et fin de la semaine
let weekInterval = calendar.dateInterval(
of: .weekOfYear, for: today
)!
// Décaler d'1 mois
let nextMonth = calendar.date(
byAdding: .month, value: 1, to: today
)!
// Décaler via DateComponents
var delta = DateComponents()
delta.month = 1
delta.day = 3
let shifted = calendar.date(byAdding: delta, to: today)!
// Vendredi 13 suivant
let friday13Components = DateComponents(
weekday: 6, day: 13
)
let nextFriday13 = calendar.nextDate(
after: today, matching: friday13Components,
matchingPolicy: .nextTime
)
EnumerateDates — une méthode puissante pour itérer sur les dates par motif. Calendar.enumerateDates(startingAfter:matching:matchingPolicy:using:) appelle un bloc pour chaque correspondance jusqu'à ce que le bloc retourne stop = true. Utilisé pour générer des événements récurrents dans les calendriers et les plannings. Cette méthode est plus efficace qu'une boucle manuelle avec nextDate, car elle est optimisée par ICU.
TimeZone fait partie intégrante de Calendar. Le fuseau horaire détermine à quelle heure calendaire correspond un Date absolu. Le même Date en UTC et à Moscou donne des composants différents : Date() en UTC peut afficher 10h00, tandis qu'à MSK — 13h00. Calendar.timeZone par défaut est TimeZone.current.
Locale affecte le premier jour de la semaine, le nombre minimal de jours dans la première semaine de l'année (minDaysInFirstWeek) et les noms des mois/jours de la semaine (lors de la conversion via DateFormatter). Calendar.locale par défaut est Locale.current. Dans les paramètres régionaux russes, la semaine commence le lundi, dans les américains — le dimanche.
Calendar.availableIdentifiers retourne une liste de tous les identifiants de calendrier pris en charge. La propriété statique Calendar.availableCalendarIdentifiers est un tableau de chaînes avec les mêmes identifiants. Utilisé pour construire une interface de sélection de calendrier et pour vérifier la disponibilité d'un système calendaire spécifique sur l'appareil.
// Calendar avec fuseau horaire spécifique
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(identifier: "UTC")!
// Calendar avec paramètres régionaux russes
var russianCalendar = Calendar(identifier: .gregorian)
russianCalendar.locale = Locale(identifier: "ru_RU")
// Le premier jour ouvrable dépend des paramètres régionaux
let firstWeekday = russianCalendar.firstWeekday
// 2 = lundi (dans ru_RU)
// Liste des calendriers disponibles
for identifier in Calendar.availableIdentifiers {
print(identifier)
}
firstWeekday — une propriété de Calendar qui détermine quel jour de la semaine est considéré comme le premier. Dans les paramètres régionaux russes, Sunday = 2 (lundi est le premier). Dans les paramètres régionaux américains, Sunday = 1. Cela affecte weekOfMonth et weekOfYear : la même date peut appartenir à des numéros de semaine différents selon les paramètres régionaux. Pour les applications qui travaillent avec des dates, utilisez Calendar.current ou définissez explicitement firstWeekday.
Considérons des scénarios pratiques démontrant les capacités de Calendar. Chaque exemple résout une tâche spécifique de développement iOS et montre la bonne façon d'utiliser les calculs calendaires.
Calendar.dateInterval(of: .month, for:) retourne les limites du mois en cours. Vérifier si un Date se trouve dans cet intervalle est le moyen le plus rapide de déterminer si une date appartient au mois en cours. Une alternative est Calendar.compare avec une granularité .month : si le résultat est .orderedSame, le mois correspond.
func isInCurrentMonth(_ date: Date) -> Bool {
let calendar = Calendar.current
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
return monthInterval.contains(date)
}
// Nombre de jours dans un mois
func daysInMonth(for date: Date) -> Int {
let calendar = Calendar.current
return calendar.range(
of: .day, in: .month, for: date
)?.count ?? 0
}
// Ajout de mois avec ajustement correct
func addMonths(_ months: Int, to date: Date) -> Date {
let calendar = Calendar.current
return calendar.date(
byAdding: .month, value: months, to: date
)!
}
Calendar.range(of:in:for:) retourne la plage de valeurs valides pour un composant spécifié dans le contexte d'un autre composant. Par exemple, range(of: .day, in: .month, for: date) retourne 1..<32 pour les mois de 31 jours ou 1..<29 pour février d'une année non bissextile. C'est la bonne façon d'obtenir le nombre de jours dans un mois, sans utiliser de valeurs codées en dur.
Ajout de mois via Calendar.date(byAdding:value:to:) gère correctement les dates limites. Si vous ajoutez 1 mois au 31 janvier, Calendar retourne le 28 février (ou 29 en année bissextile), plutôt que le 3 mars qui résulterait d'un simple ajout de 30 jours via TimeInterval. C'est une raison supplémentaire de ne pas utiliser TimeInterval pour les calculs calendaires.
| Méthode de Calendar | Objectif | Exemple |
|---|---|---|
| dateInterval | Limites de période | Début et fin d'un mois |
| range(of:in:for:) | Plage de composant | Jours du mois en cours |
| date(byAdding:) | Décalage de date | +1 mois à partir d'aujourd'hui |
| isDateInToday | Vérification de jour | La date est-elle aujourd'hui ? |
| compare(toGranularity:) | Comparaison avec précision | Même jour sans tenir compte de l'heure |
Questions fréquentes
Calendar.current retourne le calendrier des paramètres système de l'utilisateur — il peut ne pas être grégorien (par exemple, bouddhiste en Thaïlande). Calendar(identifier: .gregorian) crée toujours un calendrier grégorien indépendamment des paramètres. Utilisez Calendar.current pour afficher les dates et un identifiant explicitement choisi pour la logique métier.
Cela est dû aux différentes longueurs des mois. Si la date actuelle est le 31 janvier, l'ajout d'1 mois donne le 28 février, car février n'a pas 31 jours. Calendar ajuste automatiquement la date au dernier jour valide du mois. Pour un contrôle précis, utilisez DateComponents avec day : 1 pour passer au premier jour du mois.
DateFormatter utilise Calendar.current — le calendrier système de l'utilisateur. Si une application doit toujours afficher les dates dans le calendrier grégorien indépendamment des paramètres, définissez formatter.calendar = Calendar(identifier: .gregorian). Cela garantit un affichage uniforme pour tous les utilisateurs.
Calendar.range(of: .day, in: .year, for: date) retourne 365 ou 366 jours. Plus simple : Calendar.date(from: DateComponents(year: year, month: 2, day: 29)) != nil — si le 29 février existe, l'année est bissextile. Calendar gère automatiquement les règles du système calendaire spécifique.
Oui, la propriété firstWeekday est modifiable. Le changement affecte weekOfMonth, weekOfYear et tous les calculs liés aux numéros de semaine. Lors de la définition de locale = Locale(identifier: “ru_RU”), firstWeekday devient automatiquement 2 (lundi). La définition manuelle remplace la valeur du locale.
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