Calendar ist eine Foundation-Klasse, die ein Kalendersystem definiert und Methoden für Kalenderberechnungen bereitstellt: Extrahieren von Datumskomponenten, Berechnen von Differenzen zwischen Daten, Finden von Zeitraumgrenzen und Verschieben von Daten. Der Kalender verbindet die absolute Zeit (Date) mit menschenlesbaren Komponenten und berücksichtigt regionale Besonderheiten: Wochenanfang, Zeitzone und Sommerzeit. Laut Apple Developer Documentation (2025) unterstützt Foundation 17 Kalendersysteme — vom gregorianischen bis zum buddhistischen und japanischen — was Calendar zu einem universellen Werkzeug für internationalisierte Anwendungen macht.
Wichtige Punkte
Calendar ist eine Foundation-Klasse, die Kalenderberechnungen auf Basis von ICU (International Components for Unicode) implementiert. Der Kalender definiert, wie die absolute Zeit (Date) auf Kalenderkomponenten abgebildet wird: Jahr, Monat, Tag, Stunde, Minute, Sekunde. Ohne Calendar ist es unmöglich zu wissen, welches Jahr, welcher Monat und welcher Tag ist — Date selbst enthält diese Informationen nicht.
Der Kalender berücksichtigt drei Gruppen von Parametern: das Kalendersystem (gregorianisch, buddhistisch, japanisch), die Zeitzone und die Regionalsprache. Calendar.current kombiniert alle drei aus den Systemeinstellungen des Benutzers. Calendar.autoupdatingCurrent ist eine spezielle Version, die sich bei Änderungen der Einstellungen automatisch aktualisiert, ohne die App neu zu starten, über NotificationCenter.
Calendar ist ein Wertetyp (value type) in Foundation. Calendar(identifier:) erstellt eine neue Instanz mit festen Parametern. Calendar kann kopiert, mit == verglichen und als Dictionary-Schlüssel verwendet werden. Dies ermöglicht die Erstellung von Kalendern mit spezifischen timeZone- und locale-Einstellungen für Tests.
Calendar ist die Swift-Version von Objective-Cs NSCalendar, die über as Calendar / as NSCalendar gebrückt wird. In modernem Swift wird Calendar überall verwendet. NSCalendar bleibt aus Gründen der Abwärtskompatibilität mit Objective-C-APIs erhalten. Calendar verfügt über einen vollständigen Satz von Methoden ohne das NS-Präfix, mit typsicheren Argumenten und Swift-Optionals.
Thread-Sicherheit — Calendar ist beim Lesen threadsicher. Eine erstellte Instanz kann sicher von mehreren Threads gelesen werden. Das Ändern von Eigenschaften (timeZone, locale) ist nicht threadsicher — erstellen Sie separate Calendar-Instanzen für verschiedene Konfigurationen.
Foundation unterstützt 17 Kalendersysteme über die Enumeration Calendar.Identifier. Jedes System hat eigene Regeln für Schaltjahre, Anzahl der Monate und den Beginn der Ära. Die Wahl des Kalenders beeinflusst alle Berechnungen: dateComponents, dateInterval, nextDate.
Wichtigste Kalendersysteme:
Calendar(identifier: .gregorian) — der am häufigsten verwendete. Er entspricht dem internationalen Standard ISO 8601 und ist der Standardkalender in den meisten Ländern. Für Anwendungen mit internationalem Publikum verwenden Sie Calendar.current — er entspricht automatisch dem Systemkalender des Benutzers.
| Kennung | Typ | Verwendungsregion |
|---|---|---|
| .gregorian | Sonnenkalender | International |
| .buddhist | Sonnenkalender | Thailand, Kambodscha |
| .japanese | Sonnenkalender | Japan |
| .hebrew | Lunisolarkalender | Israel |
| .islamic | Mondkalender | Islamische Länder |
| .chinese | Lunisolarkalender | China |
DateComponents und Calendar sind ein untrennbares Paar. Calendar.dateComponents(_:from:) extrahiert Komponenten aus Date unter Berücksichtigung der Zeitzone des Kalenders. Calendar.date(from:) setzt ein Date aus DateComponents zusammen und füllt fehlende Felder mit Standardwerten: Tag = 1, Stunde = 0, Minute = 0, Sekunde = 0.
Die Methode Calendar.component extrahiert eine einzelne Komponente, geeignet für schnelle Überprüfungen. Calendar.dateComponents extrahiert mehrere Komponenten in einem Aufruf — das ist leistungsfähiger, da Calendar die Kalenderberechnungen einmal durchführt, anstatt für jede Komponente einzeln. Verwenden Sie für eine Liste von 3+ Komponenten immer dateComponents.
Calendar.compare vergleicht zwei Dates mit einer bestimmten Genauigkeit. Der Parameter toGranularity bestimmt die Komponentengenauigkeit: .year vergleicht nur das Jahr, .month — Jahr und Monat, .day — Jahr, Monat, Tag. Dies ist nützlich, um zu prüfen, ob zwei Daten auf denselben Tag fallen, ohne die Uhrzeit zu berücksichtigen.
let calendar = Calendar.current
let now = Date()
// Extrahieren einer einzelnen Komponente
let year = calendar.component(.year, from: now)
// Extrahieren eines Satzes von Komponenten
let comps = calendar.dateComponents(
[.year, .month, .day], from: now
)
// Vergleich mit Tagesgranularität
let isSameDay = calendar.compare(date1, to: date2,
toGranularity: .day) == .orderedSame
// Prüfen, ob das Datum heute ist
let isToday = calendar.isDateInToday(someDate)
Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — Methoden für relative Überprüfungen. Calendar.isDate(_:inSameDayAs:) prüft, ob zwei Daten auf denselben Kalendertag fallen, unter Berücksichtigung der Zeitzone des Kalenders. Diese Methoden verwenden intern Calendar.compare und sind für häufige Aufrufe optimiert.
Calendar.dateInterval ist eine der nützlichsten Methoden für Analysen und die Benutzeroberfläche. Sie gibt ein DateInterval für die angegebene Komponente zurück: Anfang und Ende eines Tages, einer Woche, eines Monats, eines Jahres. DateInterval enthält start (Date) und end (Date) — die Grenzen des Zeitraums. Zum Beispiel gibt dateInterval(of: .weekOfYear, for: Date()) den Anfang von Montag und das Ende von Sonntag der aktuellen Woche zurück.
Calendar.date mit byAdding — eine Methode zum Verschieben von Daten. Calendar.date(byAdding: .day, value: 7, to: Date()) gibt das Datum eine Woche später zurück. Calendar.date(byAdding: DateComponents) ist eine flexiblere Version, die das gleichzeitige Verschieben mehrerer Komponenten ermöglicht: +1 Monat +3 Tage. Calendar berücksichtigt automatisch unterschiedliche Monatslängen und Schaltjahre.
Calendar.nextDate sucht das nächste Datum, das den angegebenen DateComponents entspricht. Der Parameter matchingPolicy definiert das Verhalten bei Nichtübereinstimmung: .nextTime — die nächste zeitliche Übereinstimmung, .nextTimePreservingSmallerComponents — behält Minuten und Sekunden des ursprünglichen Datums bei, .strict — erfordert eine exakte Übereinstimmung.
let calendar = Calendar.current
let today = Date()
// Anfang und Ende der Woche
let weekInterval = calendar.dateInterval(
of: .weekOfYear, for: today
)!
// Verschiebung um 1 Monat
let nextMonth = calendar.date(
byAdding: .month, value: 1, to: today
)!
// Verschiebung über DateComponents
var delta = DateComponents()
delta.month = 1
delta.day = 3
let shifted = calendar.date(byAdding: delta, to: today)!
// Nächster Freitag der 13.
let friday13Components = DateComponents(
weekday: 6, day: 13
)
let nextFriday13 = calendar.nextDate(
after: today, matching: friday13Components,
matchingPolicy: .nextTime
)
EnumerateDates — eine leistungsstarke Methode zum Iterieren über Daten nach einem Muster. Calendar.enumerateDates(startingAfter:matching:matchingPolicy:using:) ruft einen Block für jede Übereinstimmung auf, bis der Block stop = true zurückgibt. Wird zum Generieren wiederkehrender Ereignisse in Kalendern und Zeitplänen verwendet. Diese Methode ist effizienter als eine manuelle Schleife mit nextDate, da sie von ICU optimiert wird.
TimeZone ist ein wesentlicher Bestandteil von Calendar. Die Zeitzone bestimmt, welcher Kalenderzeit ein absolutes Date entspricht. Dasselbe Date in UTC und in Moskau ergibt unterschiedliche Komponenten: Date() in UTC kann 10:00 anzeigen, während es in MSK 13:00 ist. Calendar.timeZone ist standardmäßig TimeZone.current.
Locale beeinflusst den ersten Wochentag, die Mindestanzahl von Tagen in der ersten Kalenderwoche (minDaysInFirstWeek) und die Namen der Monate/Wochentage (bei der Konvertierung über DateFormatter). Calendar.locale ist standardmäßig Locale.current. In der russischen Regionalsprache beginnt die Woche am Montag, in der amerikanischen am Sonntag.
Calendar.availableIdentifiers gibt eine Liste aller unterstützten Kalenderkennungen zurück. Die statische Eigenschaft Calendar.availableCalendarIdentifiers ist ein Array von Zeichenfolgen mit denselben Kennungen. Wird zum Erstellen einer Kalenderauswahl-UI und zum Überprüfen der Verfügbarkeit eines bestimmten Kalendersystems auf dem Gerät verwendet.
// Calendar mit bestimmter Zeitzone
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(identifier: "UTC")!
// Calendar mit russischer Regionalsprache
var russianCalendar = Calendar(identifier: .gregorian)
russianCalendar.locale = Locale(identifier: "ru_RU")
// Erster Wochentag hängt von der Regionalsprache ab
let firstWeekday = russianCalendar.firstWeekday
// 2 = Montag (in ru_RU)
// Liste verfügbarer Kalender
for identifier in Calendar.availableIdentifiers {
print(identifier)
}
firstWeekday — eine Calendar-Eigenschaft, die bestimmt, welcher Wochentag als erster gilt. In der russischen Regionalsprache ist Sunday = 2 (Montag ist der erste). In der amerikanischen Regionalsprache ist Sunday = 1. Dies beeinflusst weekOfMonth und weekOfYear: Dasselbe Datum kann in verschiedenen Regionalsprachen unterschiedlichen Wochennummern zugeordnet werden. Verwenden Sie für Anwendungen, die mit Daten arbeiten, Calendar.current oder legen Sie firstWeekday explizit fest.
Betrachten wir praktische Szenarien, die die Fähigkeiten von Calendar demonstrieren. Jedes Beispiel löst eine bestimmte iOS-Entwicklungsaufgabe und zeigt die korrekte Verwendung von Kalenderberechnungen.
Calendar.dateInterval(of: .month, for:) gibt die Grenzen des aktuellen Monats zurück. Die Überprüfung, ob ein Date in dieses Intervall fällt, ist der schnellste Weg, um festzustellen, ob ein Datum zum aktuellen Monat gehört. Eine Alternative ist Calendar.compare mit der Granularität .month: Wenn das Ergebnis .orderedSame ist, stimmt der Monat überein.
func isInCurrentMonth(_ date: Date) -> Bool {
let calendar = Calendar.current
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
return monthInterval.contains(date)
}
// Anzahl der Tage in einem Monat
func daysInMonth(for date: Date) -> Int {
let calendar = Calendar.current
return calendar.range(
of: .day, in: .month, for: date
)?.count ?? 0
}
// Hinzufügen von Monaten mit korrekter Behandlung
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:) gibt den Bereich gültiger Werte für eine angegebene Komponente im Kontext einer anderen Komponente zurück. Zum Beispiel gibt range(of: .day, in: .month, for: date) 1..<32 für Monate mit 31 Tagen oder 1..<29 für Februar in einem Nicht-Schaltjahr zurück. Dies ist die korrekte Methode, um die Anzahl der Tage in einem Monat zu ermitteln, anstatt hartcodierte Werte zu verwenden.
Hinzufügen von Monaten über Calendar.date(byAdding:value:to:) behandelt Randdaten korrekt. Wenn man zum 31. Januar 1 Monat hinzufügt, gibt Calendar den 28. Februar zurück (oder den 29. in einem Schaltjahr), nicht den 3. März, der sich bei einfachem Hinzufügen von 30 Tagen über TimeInterval ergeben würde. Dies ist ein weiterer Grund, TimeInterval nicht für Kalenderberechnungen zu verwenden.
| Calendar-Methode | Zweck | Beispiel |
|---|---|---|
| dateInterval | Zeitraumgrenzen | Anfang und Ende eines Monats |
| range(of:in:for:) | Komponentenbereich | Tage im aktuellen Monat |
| date(byAdding:) | Datumsverschiebung | +1 Monat ab heute |
| isDateInToday | Überprüfung auf heute | Gehört das Datum zu heute? |
| compare(toGranularity:) | Vergleich mit Genauigkeit | Gleicher Tag ohne Uhrzeit |
Häufig gestellte Fragen
Calendar.current gibt den Kalender aus den Systemeinstellungen des Benutzers zurück — er kann nicht gregorianisch sein (z. B. buddhistisch in Thailand). Calendar(identifier: .gregorian) erstellt immer einen gregorianischen Kalender, unabhängig von den Einstellungen. Verwenden Sie Calendar.current zum Anzeigen von Daten und eine explizit gewählte Kennung für die Geschäftslogik.
Dies liegt an den unterschiedlichen Monatslängen. Wenn das aktuelle Datum der 31. Januar ist, ergibt das Hinzufügen von 1 Monat den 28. Februar, da der Februar keinen 31. Tag hat. Calendar passt das Datum automatisch an den letzten gültigen Tag des Monats an. Verwenden Sie für eine präzise Steuerung DateComponents mit day: 1, um zum ersten Tag des Monats zu gelangen.
DateFormatter verwendet Calendar.current — den Systemkalender des Benutzers. Wenn eine Anwendung Daten unabhängig von den Einstellungen immer im gregorianischen Kalender anzeigen soll, setzen Sie formatter.calendar = Calendar(identifier: .gregorian). Dies gewährleistet eine einheitliche Anzeige für alle Benutzer.
Calendar.range(of: .day, in: .year, for: date) gibt 365 oder 366 Tage zurück. Einfacher: Calendar.date(from: DateComponents(year: year, month: 2, day: 29)) != nil — wenn der 29. Februar existiert, ist das Jahr ein Schaltjahr. Calendar verarbeitet die Regeln des jeweiligen Kalendersystems automatisch.
Ja, die Eigenschaft firstWeekday ist beschreibbar. Die Änderung wirkt sich auf weekOfMonth, weekOfYear und alle Berechnungen im Zusammenhang mit Wochennummern aus. Beim Setzen von locale = Locale(identifier: “ru_RU”) wird firstWeekday automatisch 2 (Montag). Die manuelle Einstellung überschreibt den Wert aus der Regionalsprache.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch