DateComponents – co to je, komponenty kalendáře a NSCalendar

Autor: IT Sectr Publikováno: 2026-07-12 Doba čtení: 7 min

DateComponents je struktura Foundation, která ukládá komponenty kalendářního data jako samostatná pole: rok, měsíc, den, hodina, minuta, sekunda a další. Na rozdíl od Date, které představuje absolutní okamžik v čase, DateComponents obsahuje člověkem čitelné hodnoty závislé na kalendáři a časovém pásmu. Podle Apple Developer Documentation (2025) se DateComponents používá jako mezičlánek mezi Date a Calendar – prostřednictvím něj se extrahují a konstruují kalendářní data, provádějí se výpočty a posuny dat bez ruční aritmetiky.

Hlavní body

  • DateComponents – struktura pro ukládání komponent data (rok, měsíc, den) jako volitelných celočíselných polí.
  • Calendar.dateComponents – metoda, která extrahuje zadané komponenty z Date s ohledem na časové pásmo.
  • Calendar.date(from:) – zpětný převod DateComponents na Date s automatickým doplněním chybějících polí.
  • Volitelná pole – každé pole DateComponents může být nil, což umožňuje zadávání neúplných dat.
  • Range a komponenty – DateComponents se používá v Calendar pro výpočet rozdílu mezi daty a hledání dat v rozsahu.

Co je DateComponents?

DateComponents je hodnotový typ Foundation určený pro ukládání kalendářních komponent času. Každá komponenta je reprezentována jako volitelné pole Int: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear a další.

Hlavní rozdíl oproti Date je vazba na kalendář. Date ukládá absolutní čas (počet sekund od referenčního data), zatímco DateComponents je člověkem čitelná reprezentace, která má smysl pouze v kontextu konkrétního Calendar. Stejné Date může být reprezentováno různými DateComponents v různých kalendářích a časových pásmech.

DateComponents není samostatný typ času, ale kontejner dat. Pro interpretaci DateComponents jako data je vyžadován Calendar, který rozumí tomu, jak komponenty souvisejí s kalendářním systémem. Calendar.dateComponents(from: Date) provádí extrakci komponent, Calendar.date(from: DateComponents) – zpětné sestavení.

Volitelnost polí

Každé pole DateComponents je volitelné (Int?), což je zásadní pro práci s neúplnými daty. Pokud zadáte pouze rok a měsíc, Calendar doplní chybějící pole výchozími hodnotami: den = 1, hodina = 0, minuta = 0. To je vhodné pro vytváření dat začátku období – stačí zadat pouze relevantní komponenty.

Při porovnávání DateComponents operátorem == se porovnávají pouze zadaná (ne nil) pole. Dvě struktury DateComponents s rokem 2026, ale různými měsíci, jsou považovány za různé. isEqual z NSObjectProtocol se pro DateComponents nepoužívá – DateComponents nedědí z NSObject.

Komponenty data: rok, měsíc, den

Základní pole DateComponents zahrnují year, month, day, hour, minute, second, nanosecond. Každé pole ukládá číselnou hodnotu v odpovídající jednotce: rok – 2026, měsíc – 1..12, den – 1..31, hodina – 0..23, minuta – 0..59, sekunda – 0..59. Nanosekundy mohou nabývat hodnot 0..999999999.

Pole týdne – weekday (1..7, kde 1 = neděle v gregoriánském kalendáři), weekOfMonth, weekOfYear. Tato pole závisí na Calendar a nemají smysl mimo jeho kontext. weekday závisí na nastavení firstWeekday kalendáře: v české lokalizaci týden začíná pondělím (weekday = 2 v gregoriánském systému), v americké – nedělí (weekday = 1).

Specializovaná pole – quarter (1..4), yearForWeekOfYear (rok, ke kterému týden patří), isLeapMonth (logický příznak pro přestupné měsíce v hebrejském nebo čínském kalendáři). Pole calendar a timeZone ukládají odkazy na odpovídající objekty, se kterými byla struktura vytvořena.

KategoriePoleRozsah
Kalendářníyear, month, day1..∞, 1..12, 1..31
Časovéhour, minute, second, nanosecond0..23, 0..59, 0..59, 0..999999999
Týdenníweekday, weekOfMonth, weekOfYear1..7, 1..5, 1..53
Speciálníquarter, yearForWeekOfYear1..4, závislé

Při extrakci komponent prostřednictvím Calendar.dateComponents je důležité žádat pouze potřebná pole kvůli výkonu. Calendar extrahuje všechna požadovaná pole v jednom průchodu – to je výrazně rychlejší než volat Calendar.component pro každé pole zvlášť.

Vytvoření DateComponents

Inicializace DateComponents – nejjednodušší způsob: vytvoříte prázdnou strukturu a vyplníte potřebná pole. Všechna neuvedená pole automaticky obdrží nil. Datum vytvořené z částečných komponent není validováno ve fázi inicializace – chyba může nastat pouze při převodu na Date přes Calendar.

Inicializátor DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) umožňuje nastavit všechna pole v jednom volání. Tento inicializátor je vhodný pro vytvoření úplného data z hotových hodnot, ale zřídka se používá s více než 5-6 argumenty kvůli čitelnosti.

Calendar.dateComponents(_:from:) – hlavní způsob získání DateComponents z existujícího Date. Druhým argumentem je sada komponent, které mají být extrahovány. Calendar provádí kalendářní výpočty s ohledem na časové pásmo a vrací strukturu pouze s požadovanými poli, ostatní pole zůstávají nil.

swift
import Foundation

// Vytvoření přes inicializátor polí
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21

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

// Vytvoření přes rozšířený inicializátor
let birthday = DateComponents(
    calendar: Calendar.current,
    year: 1990, month: 5, day: 15
)

Při vytváření DateComponents ručním nastavením polí vždy před převodem na Date zkontrolujte Calendar. Calendar při převodu date(from:) může vrátit nil, pokud komponenty tvoří neexistující datum – například 31. února nebo 30. února v nepřestupném roce. Validace data je odpovědností Calendar, nikoli DateComponents.

Převod DateComponents na Date

Calendar.date(from:) – hlavní metoda převodu DateComponents na Date. Calendar interpretuje komponenty podle svého kalendáře a časového pásma. Pokud některá pole nejsou nastavena (nil), Calendar použije výchozí hodnoty: den = 1, hodina = 0, minuta = 0, sekunda = 0.

Metoda vrací volitelný Date – nil nastává, když si komponenty odporují nebo tvoří neplatné datum. Typické příčiny nil: neexistující datum (32. ledna, 29. února 2023), protichůdná pole (weekday=1, day=5 v jedné sadě), nemožný rok pro daný kalendář (rok 0 v gregoriánském kalendáři).

DateComponents s timeZone – pokud DateComponents obsahuje timeZone, Calendar jej použije při převodu. Pokud timeZone není uvedena, Calendar použije svou vlastní aktuální timeZone. Pokud Calendar.timeZone neodpovídá očekávanému časovému pásmu data, výsledek se může lišit o několik hodin – ujistěte se, že je timeZone explicitně nastavena v jednom z objektů.

swift
let calendar = Calendar(identifier: .gregorian)

// Vytvoření Date z 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)")
}

// Vytvoření s uvedením 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 pro rozdíl dat – další scénář použití DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) vrací rozdíl v letech, měsících a dnech mezi dvěma daty. Toto je správný způsob výpočtu věku namísto dělení TimeInterval počtem sekund v roce, protože Calendar zohledňuje přestupné roky.

Calendar a DateComponents

Calendar – centrální třída, která pracuje s DateComponents. Všechny operace extrakce, sestavení a porovnávání dat procházejí přes Calendar. Bez Calendar je DateComponents pouze sbírkou čísel bez časového významu. Calendar dává komponentám interpretaci: určuje, že měsíc 2 je únor a weekday 2 je pondělí.

Calendar.nextDate a Calendar.enumerateDates – dvě metody založené na DateComponents. nextDate(after: Date(), matching: DateComponents) najde následující datum odpovídající zadaným komponentám – například příští pondělí po dnešku. enumerateDates(startingAfter:matching:matchingPolicy:using:) prochází všechna data odpovídající vzoru až do zadaného limitu.

Calendar.dateInterval – metoda vracející DateInterval pro zadanou komponentu. dateInterval(of: .month, for: Date()) vrací začátek a konec aktuálního měsíce. Interně tato metoda používá DateComponents k nalezení hranic období: vytvoří DateComponents s prvním a posledním dnem měsíce, převede je na Date přes Calendar.

swift
let calendar = Calendar.current

// Příští pondělí
let nextMonday = calendar.nextDate(
    after: Date(),
    matching: DateComponents(weekday: 2),
    matchingPolicy: .nextTime
)!

// Rozdíl mezi daty ve dnech
let diff = calendar.dateComponents(
    [.day], from: Date(), to: nextMonday
)

// Rozsah měsíce
let monthInterval = calendar.dateInterval(
    of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end

MatchingPolicy – důležitý parametr metod Calendar při práci s DateComponents. strictPolicy vyžaduje přesnou shodu všech komponent, nextTimePolicy vybírá další časovou shodu, nextTimePreservingSmallerComponents zachovává menší komponenty (minuty, sekundy) z původního data. Volba politiky ovlivňuje výsledek vyhledávání dat, zejména při posunu přes změnu letního/zimního času.

Příklady DateComponents

Prozkoumáme praktické scénáře použití DateComponents v aplikaci. Každý příklad demonstruje typický úkol, se kterým se iOS vývojář setkává při práci s kalendářními daty.

Připomínka na první den každého měsíce

Calendar.nextDate s DateComponents(day: 1) najde první den následujícího měsíce. Calendar automaticky určí počet dní v aktuálním měsíci a přejde k dalšímu měsíci. Pro opakovaná upozornění použijte enumerateDates nebo Combine.Timer s klíčem 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
    )!
}

// Výpočet věku v letech
func ageInYears(from birthDate: Date) -> Int {
    let calendar = Calendar.current
    let ageComponents = calendar.dateComponents(
        [.year], from: birthDate, to: Date()
    )
    return ageComponents.year ?? 0
}

// Seskupování událostí podle roku a měsíce
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!)"
    }
}

Výpočet věku prostřednictvím Calendar.dateComponents([.year], from:to:) – jediný správný způsob, který zohledňuje přestupné roky. Výpočet založený na TimeInterval (sekundy / 31536000) dává chybu pro osoby narozené 29. února. Calendar správně určuje, zda byly narozeniny v aktuálním roce, a vrací přesný věk.

Seskupování podle roku a měsíce – běžný úkol pro obrazovky s historií nebo kalendářem. DateComponents slouží jako klíč seskupení: extrahujete rok a měsíc z data události, vytvoříte řetězcový klíč a seskupíte přes Dictionary(grouping:). Pro zobrazení použijte DateFormatter se šablonou „LLLL yyyy‟ pro lokalizovaný název měsíce.

ÚkolMetoda CalendarRole DateComponents
První den měsícenextDate(after:matching:)day: 1
Výpočet věkudateComponents(from:to:)[.year] z rozdílu
Seskupování datdateComponents(_:from:)year + month klíč
Hledání dne v týdnunextDate(after:matching:)weekday: N

Často kladené otázky

Proč Calendar.date(from:) vrací nil pro DateComponents?

Příčiny: neexistující datum (31. dubna), protichůdná pole (weekday=1 s day=5), neplatná kombinace polí pro vybraný kalendář. Calendar se pokouší interpretovat komponenty ve svém systému – pokud je kombinace nemožná, výsledkem je nil. Vždy používejte guard let nebo if let při převodu.

Lze DateComponents vzájemně porovnávat?

Ano, pomocí operátoru ==. DateComponents implementuje Equatable, porovnávající všechna pole. Dvě struktury jsou si rovny, pokud jsou všechna jejich pole stejná (nil == nil se považuje za pravdu). Pro porovnání pouze části polí – extrahujte stejnou sadu pomocí Calendar.dateComponents.

Čím se DateComponents liší od Date?

Date – absolutní okamžik v čase bez vazby na kalendář. DateComponents – sada člověkem čitelných čísel (rok, měsíc, den), která mají smysl pouze v kontextu Calendar. Date lze porovnávat, odečítat, serializovat do ISO 8601. DateComponents – zprostředkující reprezentace pro interakci s kalendářem.

Jak zadat pouze rok a měsíc v DateComponents?

Nastavte pouze pole year a month, ostatní ponechte jako nil. Při převodu na Date přes Calendar.date(from:) Calendar automaticky nastaví den = 1, hodina = 0, minuta = 0. Výsledkem je Date odpovídající prvnímu dni zadaného měsíce o půlnoci.

Jak DateComponents zpracovává časová pásma?

DateComponents neukládá informaci o časovém pásmu v polích – hodnoty polí (rok, měsíc, den) samy závisí na timeZone, ve které byly extrahovány. Komponenty „21. července 2026 14:00 MSK‟ a „21. července 2026 10:00 UTC‟ představují stejné Date, ale pole DateComponents jsou různá.

Shrnutí

  • DateComponents – struktura Foundation pro ukládání kalendářních komponent (rok, měsíc, den, hodina) jako volitelných polí Int?.
  • Calendar.dateComponents extrahuje komponenty z Date s ohledem na časové pásmo a kalendářní systém.
  • Calendar.date(from:) sestaví Date z DateComponents pomocí výchozích hodnot pro chybějící pole.
  • Volitelnost polí umožňuje zadávat neúplná data – Calendar doplňuje chybějící hodnoty.
  • Calendar.nextDate hledá následující datum odpovídající DateComponents – pro připomínky a opakující se události.
  • Výpočet věku prostřednictvím Calendar.dateComponents([.year], from:to:) – jediný správný způsob zohledňující přestupné roky.
  • MatchingPolicy řídí chování Calendar při neshodě všech komponent – důležitý parametr pro vyhledávání dat.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také