Calendar — cos'è, calendario Date e calcoli in Swift

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

Calendar è una classe Foundation che definisce un sistema calendario e fornisce metodi per calcoli calendari: estrazione di componenti di data, calcolo delle differenze tra date, ricerca di limiti di periodi e spostamento di date. Il calendario collega il tempo assoluto (Date) a componenti leggibili dall'uomo e tiene conto delle caratteristiche regionali: inizio della settimana, fuso orario e ora legale. Secondo la Documentazione per Sviluppatori Apple (2025), Foundation supporta 17 sistemi calendario — dal gregoriano al buddista e giapponese — rendendo Calendar uno strumento universale per applicazioni internazionalizzate.

Punti chiave

  • Calendar — una classe Foundation per calcoli calendari: estrazione di componenti, confronto e spostamento di date.
  • Calendar.current — il calendario di sistema dell'utente, che incorpora automaticamente le impostazioni regionali.
  • 17 sistemi calendario — Foundation supporta gregoriano, buddista, giapponese, ebraico, islamico e altri.
  • Calendar.dateComponents estrae componenti (anno, mese, giorno) da Date considerando il fuso orario.
  • Calendar.dateInterval restituisce la data di inizio e fine di un periodo specificato (giorno, settimana, mese).

Cos'è Calendar in Foundation?

Calendar è una classe Foundation che implementa calcoli calendari basati su ICU (International Components for Unicode). Il calendario definisce come il tempo assoluto (Date) corrisponde ai componenti del calendario: anno, mese, giorno, ora, minuto, secondo. Senza Calendar è impossibile sapere che anno, mese e giorno sono — Date stesso non contiene queste informazioni.

Il calendario tiene conto di tre gruppi di parametri: il sistema calendario (gregoriano, buddista, giapponese), il fuso orario e le impostazioni regionali. Calendar.current combina tutti e tre dalle impostazioni di sistema dell'utente. Calendar.autoupdatingCurrent è una versione speciale che si aggiorna automaticamente al cambiamento delle impostazioni senza riavviare l'applicazione tramite NotificationCenter.

Calendar è un tipo valore (value type) in Foundation. Calendar(identifier:) crea una nuova istanza con parametri fissi. Calendar può essere copiato, confrontato con == e usato come chiave in un dizionario. Ciò consente di creare calendari con impostazioni specifiche di timeZone e locale per i test.

Calendar e NSCalendar

Calendar è la versione Swift di NSCalendar di Objective-C, con ponte tramite as Calendar / as NSCalendar. Nello Swift moderno, Calendar è usato ovunque. NSCalendar rimane per compatibilità all'indietro con le API Objective-C. Calendar ha un set completo di metodi senza il prefisso NS, con argomenti type-safe e opzionali Swift.

Sicurezza dei thread — Calendar è thread-safe per la lettura. Un'istanza creata può essere letta in sicurezza da più thread. La modifica delle proprietà (timeZone, locale) non è thread-safe — create istanze separate di Calendar per configurazioni diverse.

Tipi di calendari in Foundation

Foundation supporta 17 sistemi calendario tramite l'enumerazione Calendar.Identifier. Ogni sistema ha le proprie regole per anni bisestili, numero di mesi e inizio dell'era. La scelta del calendario influenza tutti i calcoli: dateComponents, dateInterval, nextDate.

Principali sistemi calendario:

  • .gregorian — standard internazionale, 12 mesi, 365/366 giorni, era dalla nascita di Cristo.
  • .buddhist — calendario buddista, usato in Thailandia, Cambogia, Laos, l'era è 543 anni avanti rispetto al gregoriano.
  • .japanese — calendario giapponese per ere di regno imperiale, 12 mesi come il gregoriano.
  • .hebrew — calendario ebraico, 12/13 mesi, mese bisestile Adar II.
  • .islamic — calendario islamico, 12 mesi lunari, 354/355 giorni.
  • .indian — calendario nazionale indiano (Saka), 12 mesi.

Calendar(identifier: .gregorian) — il più utilizzato. È conforme allo standard internazionale ISO 8601 ed è il calendario predefinito nella maggior parte dei paesi. Per applicazioni con pubblico internazionale, usa Calendar.current — corrisponde automaticamente al calendario di sistema dell'utente.

IdentificatoreTipoRegione di utilizzo
.gregorianSolareInternazionale
.buddhistSolareThailandia, Cambogia
.japaneseSolareGiappone
.hebrewLunisolareIsraele
.islamicLunarePaesi islamici
.chineseLunisolareCina

Calendar e DateComponents

DateComponents e Calendar sono una coppia inscindibile. Calendar.dateComponents(_:from:) estrae componenti da Date rispettando il fuso orario del calendario. Calendar.date(from:) assembla un Date da DateComponents, riempiendo i campi mancanti con valori predefiniti: giorno = 1, ora = 0, minuto = 0, secondo = 0.

Il metodo Calendar.component estrae un singolo componente, comodo per controlli rapidi. Calendar.dateComponents estrae più componenti in una singola chiamata — è più efficiente poiché Calendar esegue i calcoli calendari una sola volta invece che per ogni componente separatamente. Per una lista di 3+ componenti, usa sempre dateComponents.

Calendar.compare confronta due Date con una precisione determinata. Il parametro toGranularity definisce la precisione del componente: .year confronta solo l'anno, .month — anno e mese, .day — anno, mese, giorno. Utile per verificare se due date cadono nello stesso giorno, ignorando l'ora.

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

// Estrarre un singolo componente
let year = calendar.component(.year, from: now)

// Estrarre un insieme di componenti
let comps = calendar.dateComponents(
    [.year, .month, .day], from: now
)

// Confrontare con granularità di giorno
let isSameDay = calendar.compare(date1, to: date2,
                                  toGranularity: .day) == .orderedSame

// Verificare se la data è oggi
let isToday = calendar.isDateInToday(someDate)

Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — metodi per controlli relativi. Calendar.isDate(_:inSameDayAs:) verifica se due date cadono nello stesso giorno calendario considerando il fuso orario del calendario. Questi metodi usano Calendar.compare internamente e sono ottimizzati per chiamate frequenti.

Calcoli con Calendar

Calendar.dateInterval è uno dei metodi più utili per analisi e interfaccia utente. Restituisce un DateInterval per il componente specificato: inizio e fine di un giorno, settimana, mese, anno. DateInterval contiene start (Date) e end (Date) — i limiti del periodo. Ad esempio, dateInterval(of: .weekOfYear, for: Date()) restituisce l'inizio di lunedì e la fine di domenica della settimana corrente.

Calendar.date con byAdding — un metodo per spostare le date. Calendar.date(byAdding: .day, value: 7, to: Date()) restituisce la data una settimana dopo. Calendar.date(byAdding: DateComponents) è una versione più flessibile che consente di spostare più componenti contemporaneamente: +1 mese +3 giorni. Calendar tiene automaticamente conto delle diverse lunghezze dei mesi e degli anni bisestili.

Calendar.nextDate cerca la data successiva corrispondente ai DateComponents specificati. Il parametro matchingPolicy definisce il comportamento in caso di mancata corrispondenza: .nextTime — la prossima corrispondenza oraria, .nextTimePreservingSmallerComponents — conserva minuti e secondi dalla data originale, .strict — richiede una corrispondenza esatta.

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

// Inizio e fine della settimana
let weekInterval = calendar.dateInterval(
    of: .weekOfYear, for: today
)!

// Spostare di 1 mese
let nextMonth = calendar.date(
    byAdding: .month, value: 1, to: today
)!

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

// Prossimo venerdì 13
let friday13Components = DateComponents(
    weekday: 6, day: 13
)
let nextFriday13 = calendar.nextDate(
    after: today, matching: friday13Components,
    matchingPolicy: .nextTime
)

EnumerateDates — un metodo potente per iterare sulle date per modello. Calendar.enumerateDates(startingAfter:matching:matchingPolicy:using:) chiama un blocco per ogni corrispondenza finché il blocco restituisce stop = true. Utilizzato per generare eventi ricorrenti in calendari e pianificazioni. Questo metodo è più efficiente di un ciclo manuale con nextDate, poiché è ottimizzato da ICU.

TimeZone e Locale

TimeZone è parte integrante di Calendar. Il fuso orario determina a quale ora calendario corrisponde un Date assoluto. Lo stesso Date in UTC e a Mosca produce componenti diversi: Date() in UTC può mostrare le 10:00, mentre in MSK — le 13:00. Calendar.timeZone per impostazione predefinita è TimeZone.current.

Locale influisce sul primo giorno della settimana, sul numero minimo di giorni nella prima settimana dell'anno (minDaysInFirstWeek) e sui nomi dei mesi/giorni della settimana (durante la conversione tramite DateFormatter). Calendar.locale per impostazione predefinita è Locale.current. Nelle impostazioni regionali russe la settimana inizia lunedì, in quelle americane — domenica.

Calendar.availableIdentifiers restituisce un elenco di tutti gli identificatori di calendario supportati. La proprietà statica Calendar.availableCalendarIdentifiers è un array di stringhe con gli stessi identificatori. Utilizzato per costruire un'interfaccia di selezione del calendario e per verificare la disponibilità di un sistema calendario specifico sul dispositivo.

swift
// Calendar con fuso orario specifico
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(identifier: "UTC")!

// Calendar con impostazioni regionali russe
var russianCalendar = Calendar(identifier: .gregorian)
russianCalendar.locale = Locale(identifier: "ru_RU")

// Il primo giorno feriale dipende dalle impostazioni regionali
let firstWeekday = russianCalendar.firstWeekday
// 2 = lunedì (in ru_RU)

// Elenco dei calendari disponibili
for identifier in Calendar.availableIdentifiers {
    print(identifier)
}

firstWeekday — una proprietà di Calendar che determina quale giorno della settimana è considerato il primo. Nelle impostazioni regionali russe Sunday = 2 (lunedì è il primo). Nelle impostazioni regionali americane Sunday = 1. Ciò influisce su weekOfMonth e weekOfYear: la stessa data può appartenere a diversi numeri di settimana in diverse impostazioni regionali. Per applicazioni che lavorano con le date, usa Calendar.current o imposta esplicitamente firstWeekday.

Esempi di lavoro con Calendar

Consideriamo scenari pratici che dimostrano le capacità di Calendar. Ogni esempio risolve un compito specifico di sviluppo iOS e mostra il modo corretto di utilizzare i calcoli calendari.

Verifica: la data è in questo mese?

Calendar.dateInterval(of: .month, for:) restituisce i limiti del mese corrente. Verificare se un Date cade all'interno di questo intervallo è il modo più veloce per determinare se una data appartiene al mese corrente. Un'alternativa è Calendar.compare con granularità .month: se il risultato è .orderedSame, il mese corrisponde.

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

// Numero di giorni in un mese
func daysInMonth(for date: Date) -> Int {
    let calendar = Calendar.current
    return calendar.range(
        of: .day, in: .month, for: date
    )?.count ?? 0
}

// Aggiunta di mesi con corretta gestione
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:) restituisce l'intervallo di valori validi per un componente specificato nel contesto di un altro componente. Ad esempio, range(of: .day, in: .month, for: date) restituisce 1..<32 per mesi con 31 giorni o 1..<29 per febbraio di un anno non bisestile. Questo è il modo corretto per ottenere il numero di giorni in un mese, senza usare valori fissi.

Aggiunta di mesi tramite Calendar.date(byAdding:value:to:) gestisce correttamente le date limite. Se si aggiunge 1 mese al 31 gennaio, Calendar restituisce il 28 febbraio (o 29 in anno bisestile), invece del 3 marzo che risulterebbe dalla semplice aggiunta di 30 giorni tramite TimeInterval. Questa è un'ulteriore ragione per non usare TimeInterval per calcoli calendari.

Metodo CalendarScopoEsempio
dateIntervalLimiti di periodoInizio e fine di un mese
range(of:in:for:)Intervallo di componenteGiorni nel mese corrente
date(byAdding:)Spostamento di data+1 mese da oggi
isDateInTodayVerifica di oggiLa data è di oggi?
compare(toGranularity:)Confronto con precisioneStesso giorno ignorando l'ora

Domande frequenti

Qual è la differenza tra Calendar.current e Calendar(identifier: .gregorian)?

Calendar.current restituisce il calendario dalle impostazioni di sistema dell'utente — potrebbe non essere gregoriano (ad esempio, buddista in Thailandia). Calendar(identifier: .gregorian) crea sempre un calendario gregoriano indipendentemente dalle impostazioni. Usa Calendar.current per visualizzare le date e un identificatore esplicitamente scelto per la logica di business.

Perché Calendar.date(byAdding: .month, value: 1) a volte restituisce la stessa data?

Ciò è dovuto alle diverse lunghezze dei mesi. Se la data corrente è il 31 gennaio, l'aggiunta di 1 mese produce il 28 febbraio, poiché febbraio non ha 31 giorni. Calendar regola automaticamente la data all'ultimo giorno valido del mese. Per un controllo preciso, usa DateComponents con day: 1 per passare al primo giorno del mese.

Quale calendario usa DateFormatter per impostazione predefinita?

DateFormatter usa Calendar.current — il calendario di sistema dell'utente. Se un'applicazione deve sempre visualizzare le date nel calendario gregoriano indipendentemente dalle impostazioni, imposta formatter.calendar = Calendar(identifier: .gregorian). Ciò garantisce una visualizzazione uniforme per tutti gli utenti.

Come verificare se un anno è bisestile tramite Calendar?

Calendar.range(of: .day, in: .year, for: date) restituisce 365 o 366 giorni. Più semplice: Calendar.date(from: DateComponents(year: year, month: 2, day: 29)) != nil — se il 29 febbraio esiste, l'anno è bisestile. Calendar gestisce automaticamente le regole del sistema calendario specifico.

Si può modificare firstWeekday dopo aver creato un Calendar?

, la proprietà firstWeekday è modificabile. La modifica influisce su weekOfMonth, weekOfYear e tutti i calcoli relativi ai numeri di settimana. Impostando locale = Locale(identifier: “ru_RU”), firstWeekday diventa automaticamente 2 (lunedì). L'impostazione manuale sovrascrive il valore dalle impostazioni regionali.

Riepilogo

  • Calendar — una classe Foundation per calcoli calendari, che collega Date a componenti leggibili dall'uomo tramite DateComponents.
  • 17 sistemi calendario sono supportati da Foundation — dal gregoriano al buddista e giapponese, con gestione automatica delle regole regionali.
  • Calendar.current corrisponde al calendario di sistema dell'utente — usalo per l'interfaccia utente e DateFormatter.
  • Calendar.dateInterval e Calendar.range sono metodi chiave per lavorare con limiti di periodi e intervalli di componenti.
  • Calendar.date(byAdding:) gestisce correttamente diverse lunghezze dei mesi e anni bisestili — non sostituirlo con l'aritmetica di TimeInterval.
  • TimeZone e Locale come proprietà di Calendar influenzano tutti i calcoli calendari — impostali esplicitamente per un comportamento prevedibile.
  • firstWeekday è determinato dalle impostazioni regionali e influisce sui numeri di settimana — per applicazioni globali, impostalo esplicitamente o usa Calendar.current.

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