DateComponents — cosa sono, componenti del calendario e NSCalendar

Autore: IT Sectr Pubblicato: 2026-07-12 Tempo di lettura: 7 min

DateComponents è una struttura di Foundation che memorizza i componenti di una data calendario come campi separati: anno, mese, giorno, ora, minuto, secondo e altri. A differenza di Date, che rappresenta un momento assoluto nel tempo, DateComponents contiene valori leggibili dall'uomo che dipendono dal calendario e dal fuso orario. Secondo la documentazione Apple Developer (2025), DateComponents viene utilizzata come collegamento intermedio tra Date e Calendar — attraverso di essa, le date calendario vengono estratte e costruite, i calcoli e gli spostamenti di data vengono eseguiti senza aritmetica manuale.

Punti chiave

  • DateComponents — una struttura per memorizzare i componenti della data (anno, mese, giorno) come campi interi opzionali.
  • Calendar.dateComponents — un metodo che estrae i componenti specificati da Date tenendo conto del fuso orario.
  • Calendar.date(from:) — conversione inversa di DateComponents in Date con riempimento automatico dei campi mancanti.
  • Campi opzionali — ogni campo di DateComponents può essere nil, consentendo di specificare date parziali.
  • Range e componenti — DateComponents viene utilizzata in Calendar per calcolare la differenza tra le date e trovare date in un intervallo.

Cosa sono DateComponents?

DateComponents è un tipo valore di Foundation progettato per memorizzare i componenti temporali del calendario. Ogni componente è rappresentato da un campo Int opzionale: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear e altri.

La differenza principale da Date è il vincolo al calendario. Date memorizza il tempo assoluto (numero di secondi dalla data di riferimento), mentre DateComponents è una rappresentazione leggibile che ha senso solo nel contesto di un Calendar specifico. La stessa Date può essere rappresentata da diversi DateComponents in diversi calendari e fusi orari.

DateComponents non è un tipo di tempo indipendente, ma un contenitore di dati. Per interpretare DateComponents come una data, è necessario un Calendar che capisca come i componenti si relazionano al sistema calendario. Calendar.dateComponents(from: Date) esegue l'estrazione dei componenti, Calendar.date(from: DateComponents) esegue l'assemblaggio inverso.

Opzionalità dei campi

Ogni campo di DateComponents è opzionale (Int?), il che è fondamentale per lavorare con date parziali. Se si specificano solo anno e mese, Calendar riempie i campi mancanti con valori predefiniti: giorno = 1, ora = 0, minuto = 0. Questo è comodo per creare date di inizio periodo — basta specificare i componenti rilevanti.

Quando si confrontano DateComponents con l'operatore ==, vengono confrontati solo i campi specificati (non nil). Due strutture DateComponents con lo stesso anno 2026 ma mesi diversi sono considerate distinte. isEqual di NSObjectProtocol non si applica a DateComponents — DateComponents non eredita da NSObject.

Componenti della data: anno, mese, giorno

Campi principali di DateComponents includono year, month, day, hour, minute, second, nanosecond. Ogni campo memorizza un valore numerico nell'unità corrispondente: anno — 2026, mese — 1..12, giorno — 1..31, ora — 0..23, minuto — 0..59, secondo — 0..59. I nanosecondi possono variare da 0 a 999999999.

Campi della settimana — weekday (1..7, dove 1 = domenica nel calendario gregoriano), weekOfMonth, weekOfYear. Questi campi dipendono da Calendar e non hanno significato al di fuori del suo contesto. weekday dipende dall'impostazione firstWeekday del calendario: nelle impostazioni regionali russe la settimana inizia di lunedì (weekday = 2 nel sistema gregoriano), mentre in quelle americane inizia di domenica (weekday = 1).

Campi specializzati — quarter (1..4), yearForWeekOfYear (l'anno a cui appartiene la settimana), isLeapMonth (un indicatore booleano per i mesi intercalari nei calendari ebraico o cinese). I campi calendar e timeZone memorizzano riferimenti agli oggetti corrispondenti con cui la struttura è stata creata.

CategoriaCampiIntervallo
Calendarioyear, month, day1..∞, 1..12, 1..31
Tempohour, minute, second, nanosecond0..23, 0..59, 0..59, 0..999999999
Settimanaweekday, weekOfMonth, weekOfYear1..7, 1..5, 1..53
Specialiquarter, yearForWeekOfYear1..4, dipendente

Quando si estraggono componenti tramite Calendar.dateComponents, è importante richiedere solo i campi necessari per le prestazioni. Calendar estrae tutti i campi richiesti in un unico passaggio — questo è significativamente più veloce che chiamare Calendar.component per ogni singolo campo.

Creare DateComponents

Inizializzare DateComponents — il modo più semplice: creare una struttura vuota e riempire i campi necessari. Tutti i campi non specificati ricevono automaticamente nil. Una data creata da componenti parziali non viene convalidata all'inizializzazione — un errore può verificarsi solo quando si converte in Date tramite Calendar.

L'inizializzatore DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) consente di impostare tutti i campi in una singola chiamata. Questo inizializzatore è comodo per creare una data completa da valori già pronti, ma viene usato raramente con più di 5-6 argomenti a causa della leggibilità.

Calendar.dateComponents(_:from:) — il modo principale per ottenere DateComponents da un Date esistente. Il secondo argomento è l'insieme dei componenti da estrarre. Calendar esegue i calcoli calendari tenendo conto del fuso orario e restituisce una struttura solo con i campi richiesti; i campi rimanenti rimangono nil.

swift
import Foundation

// Creazione tramite inizializzatore di campi
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21

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

// Creazione tramite inizializzatore esteso
let birthday = DateComponents(
    calendar: Calendar.current,
    year: 1990, month: 5, day: 15
)

Quando si creano DateComponents impostando manualmente i campi, controlla sempre Calendar prima di convertire in Date. Durante la conversione date(from:), Calendar può restituire nil se i componenti formano una data inesistente — ad esempio, 31 febbraio o 30 febbraio in un anno non bisestile. La convalida della data è responsabilità di Calendar, non di DateComponents.

Convertire DateComponents in Date

Calendar.date(from:) — il metodo principale per convertire DateComponents in Date. Calendar interpreta i componenti secondo il proprio calendario e fuso orario. Se alcuni campi non sono impostati (nil), Calendar utilizza valori predefiniti: giorno = 1, ora = 0, minuto = 0, secondo = 0.

Il metodo restituisce una Date opzionale — nil si verifica se i componenti si contraddicono a vicenda o formano una data non valida. Cause tipiche di nil: data inesistente (32 gennaio, 29 febbraio 2023), campi contraddittori (weekday=1, day=5 nello stesso insieme), anno impossibile per il calendario dato (anno 0 nel calendario gregoriano).

DateComponents con timeZone — se DateComponents contiene un timeZone, Calendar lo usa durante la conversione. Se timeZone non è specificato, Calendar usa il proprio timeZone corrente. Se Calendar.timeZone non corrisponde al fuso orario previsto della data, il risultato può differire di alcune ore — assicurati che timeZone sia impostato esplicitamente in uno degli oggetti.

swift
let calendar = Calendar(identifier: .gregorian)

// Creazione di Date da 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)")
}

// Creazione con specifica di 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 per la differenza di date — un altro caso d'uso di DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) restituisce la differenza in anni, mesi e giorni tra due date. Questo è il modo corretto per calcolare l'età invece di dividere TimeInterval per il numero di secondi in un anno, poiché Calendar tiene conto degli anni bisestili.

Calendar e DateComponents

Calendar — la classe centrale che lavora con DateComponents. Tutte le operazioni di estrazione, assemblaggio e confronto delle date passano attraverso Calendar. Senza Calendar, DateComponents è solo un insieme di numeri senza significato temporale. Calendar dà ai componenti la loro interpretazione: determina che il mese 2 è febbraio e che weekday 2 è lunedì.

Calendar.nextDate e Calendar.enumerateDates — due metodi basati su DateComponents. nextDate(after: Date(), matching: DateComponents) trova la prossima data corrispondente ai componenti specificati — ad esempio, il prossimo lunedì dopo oggi. enumerateDates(startingAfter:matching:matchingPolicy:using:) scorre tutte le date che corrispondono al modello fino al limite specificato.

Calendar.dateInterval — un metodo che restituisce un DateInterval per il componente specificato. dateInterval(of: .month, for: Date()) restituisce l'inizio e la fine del mese corrente. Internamente, questo metodo utilizza DateComponents per trovare i limiti del periodo: crea DateComponents con il primo e l'ultimo giorno del mese e li converte in Date tramite Calendar.

swift
let calendar = Calendar.current

// Prossimo lunedì
let nextMonday = calendar.nextDate(
    after: Date(),
    matching: DateComponents(weekday: 2),
    matchingPolicy: .nextTime
)!

// Differenza tra date in giorni
let diff = calendar.dateComponents(
    [.day], from: Date(), to: nextMonday
)

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

MatchingPolicy — un parametro importante dei metodi di Calendar quando si lavora con DateComponents. strictPolicy richiede una corrispondenza esatta di tutti i componenti, nextTimePolicy seleziona la corrispondenza temporale successiva, nextTimePreservingSmallerComponents preserva i componenti più piccoli (minuti, secondi) dalla data di origine. La scelta della politica influenza il risultato della ricerca di date, specialmente quando ci si sposta attraverso i cambi dell'ora legale.

Esempi di DateComponents

Esploriamo i casi d'uso pratici di DateComponents in un'applicazione. Ogni esempio dimostra un'attività tipica che uno sviluppatore iOS affronta quando lavora con le date del calendario.

Promemoria il primo giorno di ogni mese

Calendar.nextDate con DateComponents(day: 1) trova il primo giorno del mese successivo. Calendar determina automaticamente il numero di giorni nel mese corrente e passa a quello successivo. Per notifiche ricorrenti, utilizza enumerateDates o Combine.Timer con una chiave 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
    )!
}

// Calcolo dell'età in anni
func ageInYears(from birthDate: Date) -> Int {
    let calendar = Calendar.current
    let ageComponents = calendar.dateComponents(
        [.year], from: birthDate, to: Date()
    )
    return ageComponents.year ?? 0
}

// Raggruppamento di eventi per anno e mese
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!)"
    }
}

Calcolo dell'età tramite Calendar.dateComponents([.year], from:to:) — l'unico modo corretto che tiene conto degli anni bisestili. Il calcolo basato su TimeInterval (secondi / 31536000) dà errore per le persone nate il 29 febbraio. Calendar determina correttamente se il compleanno è avvenuto nell'anno corrente e restituisce l'età esatta.

Raggruppamento per anno e mese — un'attività comune per schermate di cronologia o calendario. DateComponents funge da chiave di raggruppamento: estrai anno e mese dalla data dell'evento, forma una chiave stringa e raggruppa tramite Dictionary(grouping:). Per la visualizzazione, utilizza DateFormatter con il modello "LLLL yyyy" per un nome di mese localizzato.

AttivitàMetodo CalendarRuolo DateComponents
Primo giorno del mesenextDate(after:matching:)day: 1
Calcolo etàdateComponents(from:to:)[.year] dalla differenza
Raggruppamento datedateComponents(_:from:)chiave year + month
Ricerca giorno settimananextDate(after:matching:)weekday: N

Domande frequenti

Perché Calendar.date(from:) restituisce nil per DateComponents?

Cause: data inesistente (31 aprile), campi contraddittori (weekday=1 con day=5), combinazione non valida di campi per il calendario selezionato. Calendar tenta di interpretare i componenti nel proprio sistema — se la combinazione è impossibile, il risultato è nil. Utilizza sempre guard let o if let durante la conversione.

Si possono confrontare DateComponents tra loro?

, tramite l'operatore ==. DateComponents implementa Equatable, confrontando tutti i campi. Due strutture sono uguali se tutti i loro campi sono uguali (nil == nil è considerato vero). Per confrontare solo un sottoinsieme di campi — estrai lo stesso insieme tramite Calendar.dateComponents.

In che cosa DateComponents differisce da Date?

Date è un momento assoluto nel tempo senza vincolo al calendario. DateComponents è un insieme di numeri leggibili (anno, mese, giorno) che hanno senso solo nel contesto di un Calendar. Date può essere confrontata, sottratta, serializzata in ISO 8601. DateComponents è una rappresentazione intermedia per interagire con il calendario.

Come specificare solo anno e mese in DateComponents?

Imposta solo i campi year e month, lasciando gli altri come nil. Durante la conversione in Date tramite Calendar.date(from:), Calendar imposterà automaticamente giorno = 1, ora = 0, minuto = 0. Il risultato è un Date corrispondente al primo giorno del mese specificato a mezzanotte.

Come gestisce DateComponents i fusi orari?

DateComponents non memorizza informazioni sul fuso orario nei suoi campi — i valori dei campi (anno, mese, giorno) dipendono essi stessi dal timeZone in cui sono stati estratti. I componenti "21 luglio 2026 14:00 MSK" e "21 luglio 2026 10:00 UTC" rappresentano la stessa Date, ma i campi DateComponents sono diversi.

Riepilogo

  • DateComponents — una struttura Foundation per memorizzare componenti del calendario (anno, mese, giorno, ora) come campi opzionali Int?.
  • Calendar.dateComponents estrae componenti da Date tenendo conto del fuso orario e del sistema calendario.
  • Calendar.date(from:) assembla una Date da DateComponents, usando valori predefiniti per i campi mancanti.
  • Campi opzionali consentono di specificare date parziali — Calendar completa i valori mancanti.
  • Calendar.nextDate trova la prossima data corrispondente a DateComponents — per promemoria ed eventi ricorrenti.
  • Calcolo dell'età tramite Calendar.dateComponents([.year], from:to:) — l'unico modo corretto che tiene conto degli anni bisestili.
  • MatchingPolicy controlla il comportamento di Calendar quando non tutti i componenti corrispondono — un parametro importante per la ricerca di date.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche