DateComponents – ce este, componentele calendarului și NSCalendar

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

DateComponents este o structură Foundation care stochează componentele unei date calendaristice ca câmpuri separate: an, lună, zi, oră, minut, secundă și altele. Spre deosebire de Date, care reprezintă un moment absolut în timp, DateComponents conține valori lizibile pentru om, dependente de calendar și fus orar. Conform Apple Developer Documentation (2025), DateComponents este utilizată ca verigă intermediară între Date și Calendar – prin ea se extrag și se construiesc date calendaristice, se efectuează calcule și deplasări de date fără aritmetică manuală.

Puncte principale

  • DateComponents – structură pentru stocarea componentelor datei (an, lună, zi) ca câmpuri opționale de tip întreg.
  • Calendar.dateComponents – metodă care extrage componentele specificate din Date ținând cont de fusul orar.
  • Calendar.date(from:) – conversia inversă a DateComponents în Date cu completarea automată a câmpurilor lipsă.
  • Câmpuri opționale – fiecare câmp DateComponents poate fi nil, permițând specificarea datelor incomplete.
  • Range și componente – DateComponents este utilizată în Calendar pentru calcularea diferenței între date și găsirea datelor într-un interval.

Ce sunt DateComponents?

DateComponents este un tip valoric Foundation destinat stocării componentelor calendaristice ale timpului. Fiecare componentă este reprezentată ca un câmp opțional Int: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear și altele.

Diferența principală față de Date este legătura cu calendarul. Date stochează timpul absolut (numărul de secunde de la reference date), iar DateComponents – o reprezentare lizibilă pentru om, care are sens doar în contextul unui Calendar specific. Același Date poate fi reprezentat prin DateComponents diferite în calendare și fuse orare diferite.

DateComponents nu este un tip de timp independent, ci un container de date. Pentru interpretarea DateComponents ca dată este necesar un Calendar care înțelege cum se raportează componentele la sistemul calendaristic. Calendar.dateComponents(from: Date) efectuează extragerea componentelor, Calendar.date(from: DateComponents) – asamblarea inversă.

Opcionalitatea câmpurilor

Fiecare câmp DateComponents este opțional (Int?), ceea ce este fundamental pentru lucrul cu date incomplete. Dacă specificați doar anul și luna, Calendar va completa câmpurile lipsă cu valori implicite: zi = 1, oră = 0, minut = 0. Acest lucru este convenabil pentru crearea datelor de început de perioadă – trebuie să specificați doar componentele de interes.

La compararea DateComponents prin operatorul == se compară doar câmpurile specificate (non-nil). Două structuri DateComponents cu anul 2026, dar luni diferite, sunt considerate diferite. isEqual din NSObjectProtocol nu se aplică pentru DateComponents – DateComponents nu moștenește NSObject.

Componentele datei: an, lună, zi

Câmpurile de bază DateComponents includ year, month, day, hour, minute, second, nanosecond. Fiecare câmp stochează o valoare numerică în unitatea corespunzătoare: an – 2026, lună – 1..12, zi – 1..31, oră – 0..23, minut – 0..59, secundă – 0..59. Nanosecundele pot lua valori 0..999999999.

Câmpurile săptămânii – weekday (1..7, unde 1 = duminică în calendarul gregorian), weekOfMonth, weekOfYear. Aceste câmpuri depind de Calendar și nu au sens în afara contextului său. weekday depinde de setarea firstWeekday a calendarului: în locala românească săptămâna începe lunea (weekday = 2 în sistemul gregorian), iar în cea americană – duminica (weekday = 1).

Câmpuri specializate – quarter (1..4), yearForWeekOfYear (anul căruia îi aparține săptămâna), isLeapMonth (flag logic pentru lunile bisecte în calendarul ebraic sau chinezesc). Câmpurile calendar și timeZone stochează referințe la obiectele corespunzătoare cu care structura a fost creată.

CategorieCâmpuriInterval
Calendaristiceyear, month, day1..∞, 1..12, 1..31
Temporalehour, minute, second, nanosecond0..23, 0..59, 0..59, 0..999999999
Săptămânaleweekday, weekOfMonth, weekOfYear1..7, 1..5, 1..53
Specialequarter, yearForWeekOfYear1..4, dependent

La extragerea componentelor prin Calendar.dateComponents este important să solicitați doar câmpurile necesare pentru performanță. Calendar extrage toate câmpurile solicitate într-o singură trecere – acest lucru este semnificativ mai rapid decât a apela Calendar.component pentru fiecare câmp în parte.

Crearea DateComponents

Inițializarea DateComponents – cel mai simplu mod: creați o structură goală și completați câmpurile necesare. Toate câmpurile nespecificate primesc automat nil. Data creată din componente parțiale nu este validată la etapa de inițializare – eroarea poate apărea doar la conversia în Date prin Calendar.

Inițializatorul DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) permite setarea tuturor câmpurilor într-o singură apelare. Acest inițializator este convenabil pentru crearea unei date complete din valori gata pregătite, dar este rar folosit cu mai mult de 5-6 argumente din cauza lizibilității.

Calendar.dateComponents(_:from:) – modul principal de obținere a DateComponents dintr-un Date existent. Al doilea argument este setul de componente care trebuie extrase. Calendar efectuează calcule calendaristice ținând cont de fusul orar și returnează o structură doar cu câmpurile solicitate, restul câmpurilor rămânând nil.

swift
import Foundation

// Crearea prin inițializatorul de câmpuri
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21

// Extragerea din Date
let now = Date()
let extracted = Calendar.current.dateComponents(
    [.year, .month, .day],
    from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")

// Crearea prin inițializator extins
let birthday = DateComponents(
    calendar: Calendar.current,
    year: 1990, month: 5, day: 15
)

La crearea DateComponents prin câmpuri manual, verificați întotdeauna Calendar înainte de conversia în Date. Calendar la conversia date(from:) poate returna nil dacă componentele formează o dată inexistentă – de exemplu, 31 februarie sau 30 februarie într-un an nebisect. Validarea datei este responsabilitatea Calendar, nu a DateComponents.

Convertirea DateComponents în Date

Calendar.date(from:) – metoda principală de conversie a DateComponents în Date. Calendar interpretează componentele conform calendarului și fusului său orar. Dacă unele câmpuri nu sunt setate (nil), Calendar utilizează valori implicite: zi = 1, oră = 0, minut = 0, secundă = 0.

Metoda returnează un Date opțional – nil apare atunci când componentele se contrazic reciproc sau formează o dată invalidă. Cauze tipice de nil: dată inexistentă (32 ianuarie, 29 februarie 2023), câmpuri contradictorii (weekday=1, day=5 în același set), an imposibil pentru calendarul dat (anul 0 în calendarul gregorian).

DateComponents cu timeZone – dacă DateComponents conține timeZone, Calendar îl folosește la conversie. Dacă timeZone nu este specificat, Calendar folosește propriul timeZone curent. Dacă Calendar.timeZone nu coincide cu fusul orar așteptat al datei, rezultatul poate diferi cu câteva ore – asigurați-vă că timeZone este setat explicit într-unul dintre obiecte.

swift
let calendar = Calendar(identifier: .gregorian)

// Crearea Date din 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)")
}

// Crearea cu specificarea 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 pentru diferența de date – un alt scenariu de utilizare a DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) returnează diferența în ani, luni și zile între două date. Aceasta este modalitatea corectă de calculare a vârstei în loc de împărțirea TimeInterval la numărul de secunde dintr-un an, deoarece Calendar ține cont de anii bisecți.

Calendar și DateComponents

Calendar – clasa centrală care lucrează cu DateComponents. Toate operațiile de extragere, asamblare și comparare a datelor trec prin Calendar. Fără Calendar, DateComponents este doar un set de numere fără sens temporal. Calendar dă componentelor o interpretare: stabilește că luna 2 este februarie, iar weekday 2 este luni.

Calendar.nextDate și Calendar.enumerateDates – două metode bazate pe DateComponents. nextDate(after: Date(), matching: DateComponents) găsește următoarea dată care corespunde componentelor specificate – de exemplu, următoarea luni după astăzi. enumerateDates(startingAfter:matching:matchingPolicy:using:) iterează toate datele care corespund modelului până la o limită specificată.

Calendar.dateInterval – metodă care returnează DateInterval pentru componenta specificată. dateInterval(of: .month, for: Date()) returnează începutul și sfârșitul lunii curente. Intern, această metodă folosește DateComponents pentru a găsi granițele perioadei: creează DateComponents cu prima și ultima zi a lunii, le convertește în Date prin Calendar.

swift
let calendar = Calendar.current

// Următoarea luni
let nextMonday = calendar.nextDate(
    after: Date(),
    matching: DateComponents(weekday: 2),
    matchingPolicy: .nextTime
)!

// Diferența între date în zile
let diff = calendar.dateComponents(
    [.day], from: Date(), to: nextMonday
)

// Intervalul lunii
let monthInterval = calendar.dateInterval(
    of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end

MatchingPolicy – un parametru important al metodelor Calendar la lucrul cu DateComponents. strictPolicy necesită potrivirea exactă a tuturor componentelor, nextTimePolicy selectează următoarea potrivire în timp, nextTimePreservingSmallerComponents păstrează componentele mai mici (minute, secunde) din data originală. Alegerea politicii influențează rezultatul căutării datelor, în special la deplasarea prin trecerea la ora de vară/iarnă.

Exemple DateComponents

Vom analiza scenarii practice de utilizare a DateComponents în aplicație. Fiecare exemplu demonstrează o sarcină tipică cu care se confruntă un dezvoltator iOS la lucrul cu date calendaristice.

Memento pentru prima zi a fiecărei luni

Calendar.nextDate cu DateComponents(day: 1) găsește prima zi a lunii următoare. Calendar determină automat numărul de zile din luna curentă și trece la luna următoare. Pentru notificări recurente, utilizați enumerateDates sau Combine.Timer cu cheia 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
    )!
}

// Calcularea vârstei în ani
func ageInYears(from birthDate: Date) -> Int {
    let calendar = Calendar.current
    let ageComponents = calendar.dateComponents(
        [.year], from: birthDate, to: Date()
    )
    return ageComponents.year ?? 0
}

// Gruparea evenimentelor după an și lună
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!)"
    }
}

Calcularea vârstei prin Calendar.dateComponents([.year], from:to:) – singura modalitate corectă care ține cont de anii bisecți. Calculul bazat pe TimeInterval (secunde / 31536000) dă eroare pentru persoanele născute pe 29 februarie. Calendar determină corect dacă ziua de naștere a fost în anul curent și returnează vârsta exactă.

Gruparea după an și lună – o sarcină frecventă pentru ecranele cu istoric sau calendar. DateComponents servește drept cheie de grupare: extrageți anul și luna din data evenimentului, formați o cheie de tip string și grupați prin Dictionary(grouping:). Pentru afișare, utilizați DateFormatter cu șablonul „LLLL yyyy” pentru numele localizat al lunii.

SarcinăMetoda CalendarRolul DateComponents
Prima zi a luniinextDate(after:matching:)day: 1
Calcularea vârsteidateComponents(from:to:)[.year] din diferență
Gruparea datelordateComponents(_:from:)year + month cheie
Găsirea zilei săptămâniinextDate(after:matching:)weekday: N

Întrebări frecvente

De ce Calendar.date(from:) returnează nil pentru DateComponents?

Cauze: dată inexistentă (31 aprilie), câmpuri contradictorii (weekday=1 cu day=5), combinație invalidă de câmpuri pentru calendarul selectat. Calendar încearcă să interpreteze componentele în sistemul său – dacă combinația este imposibilă, rezultatul este nil. Folosiți întotdeauna guard let sau if let la conversie.

Putem compara DateComponents între ele?

Da, prin operatorul ==. DateComponents implementează Equatable, comparând toate câmpurile. Două structuri sunt egale dacă toate câmpurile lor sunt egale (nil == nil este considerat adevărat). Pentru a compara doar o parte din câmpuri – extrageți același set prin Calendar.dateComponents.

Cu ce diferă DateComponents de Date?

Date – un moment absolut în timp fără legătură cu un calendar. DateComponents – un set de numere lizibile pentru om (an, lună, zi) care au sens doar în contextul Calendar. Date poate fi comparat, scăzut, serializat în ISO 8601. DateComponents – o reprezentare intermediară pentru interacțiunea cu calendarul.

Cum specific doar anul și luna în DateComponents?

Setați doar câmpurile year și month, lăsând restul nil. La conversia în Date prin Calendar.date(from:), Calendar va seta automat zi = 1, oră = 0, minut = 0. Rezultatul – un Date corespunzător primei zile a lunii specificate la miezul nopții.

Cum gestionează DateComponents fusele orare?

DateComponents nu stochează informații despre fusul orar în câmpuri – valorile câmpurilor (an, lună, zi) depind ele însele de timeZone în care au fost extrase. Componentele „21 iulie 2026 14:00 MSK” și „21 iulie 2026 10:00 UTC” reprezintă același Date, dar câmpurile DateComponents sunt diferite.

Rezumat

  • DateComponents – structură Foundation pentru stocarea componentelor calendaristice (an, lună, zi, oră) ca câmpuri opționale Int?.
  • Calendar.dateComponents extrage componentele din Date ținând cont de fusul orar și sistemul calendaristic.
  • Calendar.date(from:) assemblează Date din DateComponents, utilizând valori implicite pentru câmpurile lipsă.
  • Opcionalitatea câmpurilor permite specificarea datelor incomplete – Calendar completează valorile lipsă.
  • Calendar.nextDate caută următoarea dată corespunzătoare DateComponents – pentru mementouri și evenimente recurente.
  • Calcularea vârstei prin Calendar.dateComponents([.year], from:to:) – singura modalitate corectă care ține cont de anii bisecți.
  • MatchingPolicy controlează comportamentul Calendar la nepotrivirea tuturor componentelor – parametru important pentru căutarea datelor.

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