Calendar — ce este, calendarul Date și calculele în Swift

Autor: IT Sectr Publicat: 2026-07-12 Timp de citire: 7 min

Calendar — este o clasă Foundation care definește sistemul calendaristic și oferă metode pentru calcule calendaristice: extragerea componentelor datei, calcularea diferenței între date, găsirea limitelor perioadelor și deplasarea datelor. Calendarul leagă timpul absolut (Date) de componente lizibile pentru om și ține cont de particularitățile regionale: începutul săptămânii, fusul orar și ora de vară. Conform Apple Developer Documentation (2025), Foundation suportă 17 sisteme calendaristice — de la gregorian la budist și japonez, ceea ce face din Calendar un instrument universal pentru aplicații internaționalizate.

Principalele puncte

  • Calendar — clasa Foundation pentru calcule calendaristice: extragerea componentelor, compararea și deplasarea datelor.
  • Calendar.current — calendarul de sistem al utilizatorului, care ține cont automat de setările regionale.
  • 17 sisteme calendaristice — Foundation suportă gregorian, budist, japonez, ebraic, islamic și altele.
  • Calendar.dateComponents extrage componentele (an, lună, zi) din Date ținând cont de fusul orar.
  • Calendar.dateInterval returnează data de început și de sfârșit a unei perioade specificate (zi, săptămână, lună).

Ce este Calendar în Foundation?

Calendar — este o clasă Foundation care implementează calcule calendaristice bazate pe ICU (International Components for Unicode). Calendarul determină modul în care timpul absolut (Date) este mapat la componentele calendaristice: an, lună, zi, oră, minut, secundă. Fără Calendar, nu se poate determina ce an, lună și zi este astăzi — Date în sine nu conține aceste informații.

Calendarul ține cont de trei grupuri de parametri: sistemul calendaristic (gregorian, budist, japonez), fusul orar și locația. Calendar.current le combină pe toate trei din setările de sistem ale utilizatorului. Calendar.autoupdatingCurrent — o versiune specială care se actualizează automat la modificarea setărilor fără repornirea aplicației prin NotificationCenter.

Calendarul este un tip de valoare (value type) în Foundation. Calendar(identifier:) creează o nouă instanță cu parametri fixați. Calendarul poate fi copiat, comparat prin == și folosit ca cheie într-un dicționar. Acest lucru permite crearea de calendare cu setări specifice timeZone și locale pentru testare.

Calendar și NSCalendar

Calendar — versiunea Swift a NSCalendar din Objective-C, cu puntea as Calendar / as NSCalendar. În Swift modern, Calendar este folosit peste tot. NSCalendar rămâne pentru compatibilitatea inversă cu API-ul Objective-C. Calendar are un set complet de metode fără prefixul NS, cu argumente type-safe și opționalitate Swift.

Thread Safety — Calendar este thread-safe pentru citire. Instanța creată poate fi citită în siguranță din mai multe fire. Modificarea proprietăților (timeZone, locale) nu este thread-safe — pentru configurații diferite, creați instanțe separate de Calendar.

Tipuri de calendare în Foundation

Foundation suportă 17 sisteme calendaristice prin enumerarea Calendar.Identifier. Fiecare sistem are propriile reguli pentru ani bisecți, numărul de luni și începutul erei. Alegerea calendarului afectează toate calculele: dateComponents, dateInterval, nextDate.

Sistemele calendaristice principale:

  • .gregorian — standardul internațional, 12 luni, 365/366 zile, era creștină.
  • .buddhist — calendarul budist, folosit în Thailanda, Cambodgia, Laos, era depășește gregorianul cu 543 de ani.
  • .japanese — calendarul japonez după erele de domnie ale împăraților, 12 luni ca în gregorian.
  • .hebrew — calendarul ebraic, 12/13 luni, luna bisectă Adar II.
  • .islamic — calendarul islamic, 12 luni lunare, 354/355 zile.
  • .indian — calendarul național indian (Saka), 12 luni.

Calendar(identifier: .gregorian) — cel mai frecvent utilizat. Respectă standardul internațional ISO 8601 și este calendarul implicit în majoritatea țărilor. Pentru aplicații cu audiență internațională, utilizați Calendar.current — se potrivește automat cu calendarul de sistem al utilizatorului.

IdentificatorTipRegiunea de utilizare
.gregorianSolarInternațional
.buddhistSolarThailanda, Cambodgia
.japaneseSolarJaponia
.hebrewLunar-solarIsrael
.islamicLunarȚările islamice
.chineseLunar-solarChina

Calendar și DateComponents

DateComponents și Calendar — o pereche inseparabilă. Calendar.dateComponents(_:from:) extrage componentele din Date ținând cont de fusul orar al calendarului. Calendar.date(from:) construiește Date din DateComponents, completând câmpurile lipsă cu valori implicite: zi = 1, oră = 0, minut = 0, secundă = 0.

Metoda Calendar.component extrage o singură componentă, ceea ce este convenabil pentru verificări rapide. Calendar.dateComponents extrage un set de componente într-un singur apel — este mai eficient, deoarece Calendar efectuează calculele calendaristice o singură dată, nu pentru fiecare componentă separat. Pentru o listă de 3+ componente, utilizați întotdeauna dateComponents.

Calendar.compare compară două Date cu o precizie specificată. Parametrul toGranularity determină până la ce componentă se efectuează compararea: .year compară doar anul, .month — anul și luna, .day — anul, luna, ziua. Este convenabil pentru a verifica dacă două date aparțin aceleiași zile, fără a lua în considerare timpul.

swift
let calendar = Calendar.current
let now = Date()

// Extragerea unei singure componente
let year = calendar.component(.year, from: now)

// Extragerea unui set de componente
let comps = calendar.dateComponents(
    [.year, .month, .day], from: now
)

// Comparare cu granularitate pe zi
let isSameDay = calendar.compare(date1, to: date2,
                                  toGranularity: .day) == .orderedSame

// Verifică dacă data este astăzi
let isToday = calendar.isDateInToday(someDate)

Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — metode pentru verificări relative. Calendar.isDate(_:inSameDayAs:) verifică dacă două date cad în aceeași zi calendaristică, ținând cont de fusul orar al calendarului. Aceste metode folosesc Calendar.compare intern și sunt optimizate pentru apeluri frecvente.

Calcule Calendar

Calendar.dateInterval — una dintre cele mai utile metode pentru analitică și UI. Returnează DateInterval pentru componenta specificată: începutul și sfârșitul zilei, săptămânii, lunii, anului. DateInterval conține start (Date) și end (Date) — limitele perioadei. De exemplu, dateInterval(of: .weekOfYear, for: Date()) returnează începutul lunii și sfârșitul duminicii săptămânii curente.

Calendar.date cu byAdding — metoda pentru deplasarea datei. Calendar.date(byAdding: .day, value: 7, to: Date()) returnează data peste o săptămână. Calendar.date(byAdding: DateComponents) — o versiune mai flexibilă, permițând deplasarea mai multor componente simultan: +1 lună +3 zile. Calendar ține cont automat de lungimea diferită a lunilor și de anii bisecți.

Calendar.nextDate caută următoarea dată care se potrivește cu DateComponents specificate. Parametrul matchingPolicy determină comportamentul în caz de nepotrivire: .nextTime — următoarea potrivire după timp, .nextTimePreservingSmallerComponents — păstrează minutele și secundele din data originală, .strict — necesită o potrivire exactă.

swift
let calendar = Calendar.current
let today = Date()

// Începutul și sfârșitul săptămânii
let weekInterval = calendar.dateInterval(
    of: .weekOfYear, for: today
)!

// Deplasare cu 1 lună
let nextMonth = calendar.date(
    byAdding: .month, value: 1, to: today
)!

// Deplasare prin DateComponents
var delta = DateComponents()
delta.month = 1
delta.day = 3
let shifted = calendar.date(byAdding: delta, to: today)!

// Următoarea vineri 13
let friday13Components = DateComponents(
    weekday: 6, day: 13
)
let nextFriday13 = calendar.nextDate(
    after: today, matching: friday13Components,
    matchingPolicy: .nextTime
)

EnumerateDates — o metodă puternică pentru iterarea datelor după un model. Calendar.enumerateDates(startingAfter:matching:matchingPolicy:using:) apelează un bloc pentru fiecare potrivire, până când blocul returnează stop = true. Este folosită pentru generarea evenimentelor recurente în calendare și programări. Metoda este mai eficientă decât o buclă manuală cu nextDate, deoarece este optimizată de ICU.

TimeZone și Locale

TimeZone — o parte inseparabilă a Calendar. Fusul orar determină cărui timp calendaristic îi corespunde Date-ul absolut. Același Date în UTC și la Moscova dă componente diferite: Date() în UTC poate arăta 10:00, iar în MSK — 13:00. Calendar.timeZone este implicit egal cu TimeZone.current.

Locale influențează prima zi a săptămânii, numărul minim de zile în prima săptămână a anului (minDaysInFirstWeek) și numele lunilor/zilelor săptămânii (la conversia prin DateFormatter). Calendar.locale este implicit egal cu Locale.current. În locala românească, săptămâna începe de luni, în cea americană — de duminică.

Calendar.availableIdentifiers returnează lista tuturor identificatorilor calendaristici suportați. static property Calendar.availableCalendarIdentifiers — un tablou de șiruri cu aceiași identificatori. Folosit pentru construirea UI-ului de selectare a calendarului și pentru verificarea disponibilității unui sistem calendaristic specific pe dispozitiv.

swift
// Calendar cu fus orar specific
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(identifier: "UTC")!

// Calendar cu locala românească
var russianCalendar = Calendar(identifier: .gregorian)
russianCalendar.locale = Locale(identifier: "ru_RU")

// Prima zi a săptămânii depinde de locală
let firstWeekday = russianCalendar.firstWeekday
// 2 = luni (în ro_RO)

// Lista calendarelor disponibile
for identifier in Calendar.availableIdentifiers {
    print(identifier)
}

firstWeekday — proprietatea Calendar care determină ce zi a săptămânii este considerată prima. În locala românească Sunday = 2 (luni prima). În cea americană Sunday = 1. Aceasta afectează funcționarea weekOfMonth și weekOfYear: aceeași dată poate fi atribuită unor numere diferite de săptămână în locații diferite. Pentru aplicații cu date, utilizați Calendar.current sau setați explicit firstWeekday.

Exemple de lucru cu Calendar

Să examinăm scenarii practice care demonstrează capacitățile Calendar. Fiecare exemplu rezolvă o sarcină specifică de dezvoltare iOS și arată modul corect de utilizare a calculelor calendaristice.

Verificare: data este în această lună?

Calendar.dateInterval(of: .month, for:) returnează limitele lunii curente. Verificarea apartenenței Date la acest interval — cel mai rapid mod de a determina dacă data aparține lunii curente. Mod alternativ — Calendar.compare cu granularity .month: dacă rezultatul este .orderedSame, atunci luna se potrivește.

swift
func isInCurrentMonth(_ date: Date) -> Bool {
    let calendar = Calendar.current
    let monthInterval = calendar.dateInterval(
        of: .month, for: Date()
    )!
    return monthInterval.contains(date)
}

// Numărul de zile într-o lună
func daysInMonth(for date: Date) -> Int {
    let calendar = Calendar.current
    return calendar.range(
        of: .day, in: .month, for: date
    )?.count ?? 0
}

// Adăugarea lunilor cu finalizare corectă
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:) returnează intervalul valorilor permise pentru componenta specificată în contextul altei componente. De exemplu, range(of: .day, in: .month, for: date) returnează 1..<32 pentru lunile cu 31 de zile sau 1..<29 pentru februarie într-un an non-bisect. Aceasta este modalitatea corectă de a afla numărul de zile dintr-o lună, nu utilizarea valorilor hardcodate.

Adăugarea lunilor prin Calendar.date(byAdding:value:to:) gestionează corect datele limită. Dacă la 31 ianuarie se adaugă 1 lună, Calendar returnează 28 februarie (sau 29 într-un an bisect), nu 3 martie, cum s-ar întâmpla la adăugarea simplă a 30 de zile prin TimeInterval. Acesta este un alt motiv pentru a nu folosi TimeInterval pentru calcule calendaristice.

Metoda CalendarDestinațieExemplu
dateIntervalLimitele perioadeiÎnceputul și sfârșitul lunii
range(of:in:for:)Intervalul componenteiZile în luna curentă
date(byAdding:)Deplasarea datei+1 lună de astăzi
isDateInTodayVerificare dacă este astăziData este de astăzi
compare(toGranularity:)Comparare cu precizieAceeași zi fără timp

Întrebări frecvente

Care este diferența dintre Calendar.current și Calendar(identifier: .gregorian)?

Calendar.current returnează calendarul din setările de sistem ale utilizatorului — poate să nu fie gregorian (de exemplu, budist în Thailanda). Calendar(identifier: .gregorian) creează întotdeauna un calendar gregorian indiferent de setări. Pentru afișarea datelor, utilizați Calendar.current, pentru logica de afaceri — identificatorul ales explicit.

De ce Calendar.date(byAdding: .month, value: 1) returnează uneori aceeași dată?

Aceasta se datorează lungimii diferite a lunilor. Dacă data curentă este 31 ianuarie, adăugarea unei luni dă 28 februarie, deoarece februarie nu are 31 de zile. Calendar completează automat data până la ultima zi permisă a lunii. Pentru control precis, utilizați DateComponents cu day: 1 pentru a trece la prima zi a lunii.

Ce calendar folosește DateFormatter în mod implicit?

DateFormatter utilizează Calendar.current — calendarul de sistem al utilizatorului. Dacă aplicația trebuie să afișeze întotdeauna datele în calendarul gregorian indiferent de setări, setați formatter.calendar = Calendar(identifier: .gregorian). Aceasta garantează o afișare uniformă pentru toți utilizatorii.

Cum verific dacă un an este bisect prin Calendar?

Calendar.range(of: .day, in: .year, for: date) returnează 365 sau 366 de zile. Mai simplu: Calendar.date(from: DateComponents(year: an, month: 2, day: 29)) != nil — dacă 29 februarie există, anul este bisect. Calendar ține cont singur de regulile pentru sistemul calendaristic specific.

Pot schimba firstWeekday după crearea Calendar?

Da, proprietatea firstWeekday este disponibilă pentru scriere. Modificarea afectează weekOfMonth, weekOfYear și toate calculele legate de numerele săptămânilor. La setarea locale = Locale(identifier: "ro_RO"), firstWeekday devine automat 2 (luni). Setarea manuală suprascrie valoarea din locale.

Concluzii

  • Calendar — clasa Foundation pentru calcule calendaristice, care leagă Date de componente lizibile pentru om prin DateComponents.
  • 17 sisteme calendaristice sunt suportate de Foundation — de la gregorian la budist și japonez, cu luarea automată în considerare a regulilor regionale.
  • Calendar.current corespunde calendarului de sistem al utilizatorului — utilizați-l pentru UI și DateFormatter.
  • Calendar.dateInterval și Calendar.range — metode cheie pentru lucrul cu limitele perioadelor și intervalele componentelor.
  • Calendar.date(byAdding:) gestionează corect lungimea diferită a lunilor și anii bisecți — nu îl înlocuiți cu aritmetica TimeInterval.
  • TimeZone și Locale ca proprietăți ale Calendar afectează toate calculele calendaristice — setați-le explicit pentru un comportament previzibil.
  • firstWeekday este determinat de locale și afectează numerele săptămânilor — pentru aplicații globale, setați-l explicit sau utilizați Calendar.current.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și