DateComponents – шта је то, компоненте календара и NSCalendar

Аутор: IT Sectr Објављено: 2026-07-12 Време читања: 7 мин

DateComponents је структура Foundation-а која чува компоненте календарског датума као засебна поља: година, месец, дан, сат, минут, секунд и друга. За разлику од Date-а, који представља апсолутни тренутак у времену, DateComponents садржи људима читљиве вредности, зависне од календара и временске зоне. Према Apple Developer Documentation (2025), DateComponents се користи као посредна веза између Date-а и Calendar-а – преко ње се извлаче и конструишу календарски датуми, врше израчунавања и померања датума без ручне аритметике.

Главно

  • DateComponents – структура за чување компонената датума (година, месец, дан) као опционих целобројних поља.
  • Calendar.dateComponents – метода која извлачи наведене компоненте из Date-а узимајући у обзир временску зону.
  • Calendar.date(from:) – обрнута конверзија DateComponents-а у Date са аутоматским попуњавањем недостајућих поља.
  • Опциона поља – свако поље DateComponents-а може бити nil, што омогућава задавање непотпуног датума.
  • Range и компоненте – DateComponents се користи у Calendar-у за израчунавање разлике између датума и проналажење датума у опсегу.

Шта су DateComponents?

DateComponents је вредносни тип Foundation-а намењен чувању календарских компоненти времена. Свака компонента је представљена као опционо Int поље: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear и друга.

Главна разлика у односу на Date је повезаност са календаром. Date чува апсолутно време (број секунди од reference date-а), а DateComponents – људима читљиву репрезентацију која има смисла само у контексту одређеног Calendar-а. Исти Date може бити представљен различитим DateComponents-има у различитим календарима и временским зонама.

DateComponents није самосталан тип времена, већ контејнер података. За интерпретацију DateComponents-а као датума потребан је Calendar који разуме како се компоненте односе на календарски систем. Calendar.dateComponents(from: Date) врши извлачење компоненти, Calendar.date(from: DateComponents) – обрнуто састављање.

Опционалност поља

Свако поље DateComponents-а је опционо (Int?), што је принципијелно за рад са непотпуним датумима. Ако наведете само годину и месец, Calendar ће допунити недостајућа поља подразумеваним вредностима: дан = 1, сат = 0, минут = 0. Ово је згодно за креирање датума почетка периода – потребно је задати само интересантне компоненте.

При поређењу DateComponents-а оператором == пореде се само задата (не nil) поља. Две структуре DateComponents са годином 2026, али различитим месецима, сматрају се различитим. isEqual из NSObjectProtocol-а се не примењује за DateComponents – DateComponents не наслеђује NSObject.

Компоненте датума: година, месец, дан

Основна поља DateComponents-а укључују year, month, day, hour, minute, second, nanosecond. Свако поље чува нумеричку вредност у одговарајућој јединици: година – 2026, месец – 1..12, дан – 1..31, сат – 0..23, минут – 0..59, секунд – 0..59. Наносекунде могу узимати вредности 0..999999999.

Поља недеље – weekday (1..7, где 1 = недеља у грегоријанском календару), weekOfMonth, weekOfYear. Ова поља зависе од Calendar-а и немају смисла ван његовог контекста. weekday зависи од подешавања firstWeekday календара: у српској локализацији недеља почиње понедељком (weekday = 2 у грегоријанском систему), а у америчкој – недељом (weekday = 1).

Специјализована поља – quarter (1..4), yearForWeekOfYear (година којој припада недеља), isLeapMonth (логичка заставица за преступне месеце у хебрејском или кинеском календару). Поља calendar и timeZone чувају референце на одговарајуће објекте са којима је структура креирана.

КатегоријаПољаОпсег
Календарскаyear, month, day1..∞, 1..12, 1..31
Временскаhour, minute, second, nanosecond0..23, 0..59, 0..59, 0..999999999
Недељнаweekday, weekOfMonth, weekOfYear1..7, 1..5, 1..53
Специјалнаquarter, yearForWeekOfYear1..4, зависно

При извлачењу компоненти путем Calendar.dateComponents важно је захтевати само потребна поља ради перформанси. Calendar извлачи сва захтевана поља у једном пролазу – то је значајно брже од позивања Calendar.component за свако поље појединачно.

Креирање DateComponents-а

Иницијализација DateComponents-а – најједноставнији начин: креирате празну структуру и попуните потребна поља. Сва ненаведена поља аутоматски добијају nil. Датум креиран из делимичних компоненти се не валидира у фази иницијализације – грешка може настати само при конверзији у Date путем Calendar-а.

Иницијализатор DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) омогућава постављање свих поља у једном позиву. Овај иницијализатор је згодан за креирање пуног датума из готових вредности, али се ретко користи са више од 5-6 аргумената због читљивости.

Calendar.dateComponents(_:from:) – основни начин добијања DateComponents-а из постојећег Date-а. Други аргумент је скуп компоненти које треба извући. Calendar врши календарска израчунавања узимајући у обзир временску зону и враћа структуру само са захтеваним пољима, остала поља остају nil.

swift
import Foundation

// Креирање преко иницијализатора поља
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21

// Извлачење из Date-а
let now = Date()
let extracted = Calendar.current.dateComponents(
    [.year, .month, .day],
    from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")

// Креирање преко проширеног иницијализатора
let birthday = DateComponents(
    calendar: Calendar.current,
    year: 1990, month: 5, day: 15
)

При креирању DateComponents-а кроз ручно постављање поља, увек проверите Calendar пре конверзије у Date. Calendar при конверзији date(from:) може вратити nil ако компоненте чине непостојећи датум – на пример, 31. фебруар или 30. фебруар у непреступној години. Валидација датума је одговорност Calendar-а, не DateComponents-а.

Претварање DateComponents-а у Date

Calendar.date(from:) – основни метод конверзије DateComponents-а у Date. Calendar интерпретира компоненте према свом календару и временској зони. Ако нека поља нису постављена (nil), Calendar користи подразумеване вредности: дан = 1, сат = 0, минут = 0, секунд = 0.

Метод враћа опциони Date – nil настаје када су компоненте у међусобној противречности или чине неважећи датум. Типични узроци nil-а: непостојећи датум (32. јануар, 29. фебруар 2023), противречна поља (weekday=1, day=5 у истом скупу), немогућа година за дати календар (година 0 у грегоријанском календару).

DateComponents са timeZone – ако DateComponents садржи timeZone, Calendar га користи при конверзији. Ако timeZone није наведена, Calendar користи своју тренутну timeZone. Ако Calendar.timeZone не одговара очекиваној временској зони датума, резултат се може разликовати неколико сати – уверите се да је timeZone експлицитно постављена у једном од објеката.

swift
let calendar = Calendar(identifier: .gregorian)

// Креирање Date-а из 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)")
}

// Креирање са навођењем 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 за разлику датума – још један сценариј употребе DateComponents-а. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) враћа разлику у годинама, месецима и данима између два датума. Ово је исправан начин израчунавања старости уместо дељења TimeInterval-а бројем секунди у години, јер Calendar узима у обзир преступне године.

Calendar и DateComponents

Calendar – централна класа која ради са DateComponents-има. Све операције извлачења, састављања и поређења датума пролазе кроз Calendar. Без Calendar-а, DateComponents је само скуп бројева без временског смисла. Calendar даје интерпретацију компонентама: одређује да је месец 2 – фебруар, а weekday 2 – понедељак.

Calendar.nextDate и Calendar.enumerateDates – две методе засноване на DateComponents-има. nextDate(after: Date(), matching: DateComponents) проналази следећи датум који одговара задатим компонентама – на пример, следећи понедељак после данас. enumerateDates(startingAfter:matching:matchingPolicy:using:) прегледа све датуме који одговарају шаблону до наведене границе.

Calendar.dateInterval – метода која враћа DateInterval за наведену компоненту. dateInterval(of: .month, for: Date()) враћа почетак и крај текућег месеца. Унутар себе, ова метода користи DateComponents за проналажење граница периода: креира DateComponents са првим и последњим даном месеца, претвара их у Date путем Calendar-а.

swift
let calendar = Calendar.current

// Следећи понедељак
let nextMonday = calendar.nextDate(
    after: Date(),
    matching: DateComponents(weekday: 2),
    matchingPolicy: .nextTime
)!

// Разлика између датума у данима
let diff = calendar.dateComponents(
    [.day], from: Date(), to: nextMonday
)

// Опсег месеца
let monthInterval = calendar.dateInterval(
    of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end

MatchingPolicy – важан параметар Calendar метода при раду са DateComponents-има. strictPolicy захтева тачно поклапање свих компоненти, nextTimePolicy бира следеће поклапање у времену, nextTimePreservingSmallerComponents чува мање компоненте (минуте, секунде) из оригиналног датума. Избор политике утиче на резултат претраге датума, посебно при померању кроз прелазак на летње/зимско време.

Примери DateComponents-а

Размотрићемо практичне сценаријe примене DateComponents-а у апликацији. Сваки пример демонстрира типичан задатак са којим се суочава iOS програмер при раду са календарским датумима.

Подсетник за први дан сваког месеца

Calendar.nextDate са DateComponents(day: 1) проналази први дан следећег месеца. Calendar аутоматски одређује број дана у текућем месецу и прелази на следећи. За понављајућа обавештења користите enumerateDates или Combine.Timer са 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
    )!
}

// Израчунавање старости у годинама
func ageInYears(from birthDate: Date) -> Int {
    let calendar = Calendar.current
    let ageComponents = calendar.dateComponents(
        [.year], from: birthDate, to: Date()
    )
    return ageComponents.year ?? 0
}

// Груписање догађаја по години и месецу
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!)"
    }
}

Израчунавање старости путем Calendar.dateComponents([.year], from:to:) – једини исправан начин који узима у обзир преступне године. TimeInterval-базирано израчунавање (секунди / 31536000) даје грешку за особе рођене 29. фебруара. Calendar исправно одређује да ли је рођендан био у текућој години и враћа тачну старост.

Груписање по години и месецу – уобичајен задатак за екране са историјом или календаром. DateComponents служи као кључ за груписање: извлачите годину и месец из датума догађаја, формирате кључ у виду стринга и групишете путем Dictionary(grouping:). За приказ користите DateFormatter са шаблоном „LLLL yyyy” за локализовано име месеца.

ЗадатакCalendar методаУлога DateComponents
Први дан месецаnextDate(after:matching:)day: 1
Израчунавање старостиdateComponents(from:to:)[.year] из разлике
Груписање датумаdateComponents(_:from:)year + month кључ
Проналажење дана у недељиnextDate(after:matching:)weekday: N

Често постављана питања

Зашто Calendar.date(from:) враћа nil за DateComponents?

Узроци: непостојећи датум (31. април), противречна поља (weekday=1 са day=5), неважећа комбинација поља за изабрани календар. Calendar покушава да интерпретира компоненте у свом систему – ако је комбинација немогућа, резултат је nil. Увек користите guard let или if let при конверзији.

Могу ли се DateComponents поредити међусобно?

Да, путем оператора ==. DateComponents имплементира Equatable, поредећи сва поља. Две структуре су једнаке ако су сва њихова поља једнака (nil == nil се сматра тачним). За поређење само дела поља – извуците исти скуп путем Calendar.dateComponents.

Чиме се DateComponents разликује од Date-а?

Date – апсолутни тренутак у времену без везе са календаром. DateComponents – скуп људима читљивих бројева (година, месец, дан) који имају смисла само у контексту Calendar-а. Date се може поредити, одузети, серијализовати у ISO 8601. DateComponents – посредна репрезентација за интеракцију са календаром.

Како навести само годину и месец у DateComponents-има?

Поставите само поља year и month, остављајући остала nil. При конверзији у Date путем Calendar.date(from:), Calendar ће аутоматски поставити дан = 1, сат = 0, минут = 0. Резултат – Date који одговара првом дану наведеног месеца у поноћ.

Како DateComponents обрађује временске зоне?

DateComponents не чува информацију о временској зони у пољима – вредности поља (година, месец, дан) саме зависе од timeZone у којој су извучене. Компоненте „21. јул 2026. 14:00 MSK” и „21. јул 2026. 10:00 UTC” представљају исти Date, али су поља DateComponents-а различита.

Резиме

  • DateComponents – структура Foundation-а за чување календарских компоненти (година, месец, дан, сат) као опционих поља Int?.
  • Calendar.dateComponents извлачи компоненте из Date-а узимајући у обзир временску зону и календарски систем.
  • Calendar.date(from:) саставља Date из DateComponents-а, користећи подразумеване вредности за недостајућа поља.
  • Опционалност поља омогућава задавање непотпуног датума – Calendar допуњује недостајуће вредности.
  • Calendar.nextDate тражи следећи датум који одговара DateComponents-има – за подсетнике и понављајуће догађаје.
  • Израчунавање старости путем Calendar.dateComponents([.year], from:to:) – једини исправан начин који узима у обзир преступне године.
  • MatchingPolicy контролише понашање Calendar-а при непоклапању свих компоненти – важан параметар за претрагу датума.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође