Calendar — шта је то, календар Date и израчунавања у Swift

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

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

Главно

  • Calendar — класа Foundation за календарска израчунавања: издвајања компоненти, поређења и померања датума.
  • Calendar.current — системски календар корисника, аутоматски узима у обзир регионална подешавања.
  • 17 календарских система — Foundation подржава грегоријански, будистички, јапански, хебрејски, исламски и друге.
  • Calendar.dateComponents издваја компоненте (година, месец, дан) из Date узимајући у обзир timezone.
  • Calendar.dateInterval враћа почетни и крајњи датум наведеног периода (дан, недеља, месец).

Шта је Calendar у Foundation?

Calendar — је класа Foundation која имплементира календарска израчунавања на основу ICU (International Components for Unicode). Календар одређује како се апсолутно време (Date) мапира на календарске компоненте: година, месец, дан, сат, минут, секунд. Без Calendar немогуће је одредити која је данас година, месец и дан — Date сам по себи не садржи ове информације.

Календар узима у обзир три групе параметара: календарски систем (грегоријански, будистички, јапански), временску зону и локал. Calendar.current их комбинује све три из системских подешавања корисника. Calendar.autoupdatingCurrent — специјална верзија која се аутоматски ажурира при промени подешавања без поновног покретања апликације преко NotificationCenter.

Календар је вредносни тип (value type) у Foundation. Calendar(identifier:) креира нову инстанцу са фиксним параметрима. Календар се може копирати, упоређивати путем == и користити као кључ у речнику. Ово омогућава креирање календара са одређеним timeZone и locale подешавањима за тестирање.

Calendar и NSCalendar

Calendar — Swift верзија Objective-C NSCalendar, са мостом as Calendar / as NSCalendar. У модерном Swift-у свуда се користи Calendar. NSCalendar остаје за повратну компатибилност са Objective-C API-јем. Calendar има пун скуп метода без NS префикса, са type-safe аргументима и Swift опционалношћу.

Thread Safety — Calendar је thread-safe за читање. Креирана инстанца се може безбедно читати из више нити. Модификација својстава (timeZone, locale) није thread-safe — за различите конфигурације креирајте различите инстанце Calendar.

Типови календара у Foundation

Foundation подржава 17 календарских система кроз енумерацију Calendar.Identifier. Сваки систем има своја правила за преступне године, број месеци и почетак ере. Избор календара утиче на сва израчунавања: dateComponents, dateInterval, nextDate.

Основни календарски системи:

  • .gregorian — међународни стандард, 12 месеци, 365/366 дана, ера од Христовог рођења.
  • .buddhist — будистички календар, користи се на Тајланду, Камбоџи, Лаосу, ера је 543 године испред грегоријанске.
  • .japanese — јапански календар по ерама владавине царева, 12 месеци као у грегоријанском.
  • .hebrew — хебрејски календар, 12/13 месеци, преступни месец Адар II.
  • .islamic — исламски календар, 12 лунарних месеци, 354/355 дана.
  • .indian — индијски национални календар (Saka), 12 месеци.

Calendar(identifier: .gregorian) — најчешће коришћен. Одговара међународном стандарду ISO 8601 и подразумевани је календар у већини земаља. За апликације са међународном публиком користите Calendar.current — аутоматски одговара системском календару корисника.

ИдентификаторТипРегион употребе
.gregorianСоларниМеђународни
.buddhistСоларниТајланд, Камбоџа
.japaneseСоларниЈапан
.hebrewЛунарно-соларниИзраел
.islamicЛунарниИсламске земље
.chineseЛунарно-соларниКина

Calendar и DateComponents

DateComponents и Calendar — нераздвојни пар. Calendar.dateComponents(_:from:) издваја компоненте из Date узимајући у обзир временску зону календара. Calendar.date(from:) саставља Date из DateComponents, попуњавајући недостајућа поља подразумеваним вредностима: дан = 1, сат = 0, минут = 0, секунд = 0.

Метода Calendar.component издваја једну компоненту, што је згодно за брзу проверу. Calendar.dateComponents издваја скуп компоненти у једном позиву — ово је ефикасније јер Calendar врши календарска израчунавања једном, а не за сваку компоненту посебно. За листу од 3+ компоненти увек користите dateComponents.

Calendar.compare упоређује два Date са задатом прецизношћу. Параметар toGranularity одређује до које компоненте се врши поређење: .year упоређује само годину, .month — годину и месец, .day — годину, месец, дан. Ово је згодно за проверу да ли два датума припадају истом дану, без узимања у обзир времена.

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

// Издвајање једне компоненте
let year = calendar.component(.year, from: now)

// Издвајање скупа компоненти
let comps = calendar.dateComponents(
    [.year, .month, .day], from: now
)

// Поређење са прецизношћу дана
let isSameDay = calendar.compare(date1, to: date2,
                                  toGranularity: .day) == .orderedSame

// Провери да ли је датум данас
let isToday = calendar.isDateInToday(someDate)

Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — методе за релативне провере. Calendar.isDate(_:inSameDayAs:) проверава да ли два датума падају на исти календарски дан узимајући у обзир временску зону календара. Ове методе користе Calendar.compare интерно и оптимизоване су за честе позиве.

Calendar израчунавања

Calendar.dateInterval — једна од најкориснијих метода за аналитику и UI. Враћа DateInterval за наведену компоненту: почетак и крај дана, недеље, месеца, године. DateInterval садржи start (Date) и end (Date) — границе периода. На пример, dateInterval(of: .weekOfYear, for: Date()) враћа почетак понедељка и крај недеље текуће недеље.

Calendar.date са byAdding — метода за померање датума. Calendar.date(byAdding: .day, value: 7, to: Date()) враћа датум за недељу дана. Calendar.date(byAdding: DateComponents) — флексибилнија верзија која омогућава померање више компоненти одједном: +1 месец +3 дана. Calendar аутоматски узима у обзир различиту дужину месеци и преступне године.

Calendar.nextDate тражи следећи датум који се поклапа са задатим DateComponents. Параметар matchingPolicy одређује понашање при непоклапању: .nextTime — следеће поклапање по времену, .nextTimePreservingSmallerComponents — задржава минуте и секунде из оригиналног датума, .strict — захтева тачно поклапање.

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

// Почетак и крај недеље
let weekInterval = calendar.dateInterval(
    of: .weekOfYear, for: today
)!

// Померање за 1 месец
let nextMonth = calendar.date(
    byAdding: .month, value: 1, to: today
)!

// Померање кроз DateComponents
var delta = DateComponents()
delta.month = 1
delta.day = 3
let shifted = calendar.date(byAdding: delta, to: today)!

// Следећи петак 13.
let friday13Components = DateComponents(
    weekday: 6, day: 13
)
let nextFriday13 = calendar.nextDate(
    after: today, matching: friday13Components,
    matchingPolicy: .nextTime
)

EnumerateDates — моћна метода за пребирање датума по шаблону. Calendar.enumerateDates(startingAfter:matching:matchingPolicy:using:) позива блок за свако поклапање док блок не врати stop = true. Користи се за генерисање понављајућих догађаја у календарима и распоредима. Метода је ефикаснија од ручне петље са nextDate јер је оптимизована од стране ICU.

TimeZone и Locale

TimeZone — неодвојиви део Calendar-а. Временска зона одређује ком календарском времену одговара апсолутни Date. Исти Date у UTC и у Москви даје различите компоненте: Date() у UTC може показивати 10:00, а у MSK — 13:00. Calendar.timeZone подразумевано је једнак TimeZone.current.

Locale утиче на први дан недеље, минималан број дана у првој недељи године (minDaysInFirstWeek) и називе месеци/дана недеље (при конверзији кроз DateFormatter). Calendar.locale подразумевано је једнак Locale.current. У српској локализацији недеља почиње понедељком, у америчкој — недељом.

Calendar.availableIdentifiers враћа листу свих подржаних календарских идентификатора. static property Calendar.availableCalendarIdentifiers — низ стрингова са истим идентификаторима. Користи се за изградњу UI-ја за избор календара и за проверу доступности одређеног календарског система на уређају.

swift
// Календар са одређеном временском зоном
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(identifier: "UTC")!

// Календар са руским локалом
var russianCalendar = Calendar(identifier: .gregorian)
russianCalendar.locale = Locale(identifier: "ru_RU")

// Први дан недеље зависи од локала
let firstWeekday = russianCalendar.firstWeekday
// 2 = понедељак (у sr_RS)

// Листа доступних календара
for identifier in Calendar.availableIdentifiers {
    print(identifier)
}

firstWeekday — својство Calendar-а које одређује који се дан недеље сматра првим. У српској локализацији Sunday = 2 (понедељак први). У америчкој Sunday = 1. Ово утиче на рад weekOfMonth и weekOfYear: исти датум може бити придружен различитим бројевима недеље у различитим локализацијама. За апликације са датумима користите Calendar.current или експлицитно подесите firstWeekday.

Примери рада са Calendar

Размотримо практичне сценарије који демонстрирају могућности Calendar. Сваки пример решава конкретан задатак iOS развоја и показује правилан начин коришћења календарских израчунавања.

Провера: датум у овом месецу?

Calendar.dateInterval(of: .month, for:) враћа границе текућег месеца. Провера припадања Date овом интервалу — најбржи начин да се утврди да ли датум припада текућем месецу. Алтернативни начин — Calendar.compare са granularity .month: ако је резултат .orderedSame, месец се поклапа.

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

// Број дана у месецу
func daysInMonth(for date: Date) -> Int {
    let calendar = Calendar.current
    return calendar.range(
        of: .day, in: .month, for: date
    )?.count ?? 0
}

// Додавање месеци са коректним завршетком
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:) враћа опсег дозвољених вредности за наведену компоненту у контексту друге компоненте. На пример, range(of: .day, in: .month, for: date) враћа 1..<32 за месеце са 31 даном или 1..<29 за фебруар непреступне године. Ово је прави начин да се сазна број дана у месецу, а не коришћење хардкодованих вредности.

Додавање месеци кроз Calendar.date(byAdding:value:to:) коректно обрађује граничне датуме. Ако се 31. јануара дода 1 месец, Calendar враћа 28. фебруар (или 29. у преступној години), а не 3. март, како би се добило једноставним додавањем 30 дана кроз TimeInterval. Ово је још један разлог да се не користи TimeInterval за календарска израчунавања.

Метода CalendarНаменаПример
dateIntervalГранице периодаПочетак и крај месеца
range(of:in:for:)Опсег компонентеДани у текућем месецу
date(byAdding:)Померање датума+1 месец од данас
isDateInTodayПровера да ли је данасДа ли је датум данашњи
compare(toGranularity:)Поређење са прецизношћуИсти дан без времена

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

Која је разлика између Calendar.current и Calendar(identifier: .gregorian)?

Calendar.current враћа календар из системских подешавања корисника — може бити негрегоријански (на пример, будистички на Тајланду). Calendar(identifier: .gregorian) увек креира грегоријански календар независно од подешавања. За приказ датума користите Calendar.current, за пословну логику — експлицитно изабрани идентификатор.

Зашто Calendar.date(byAdding: .month, value: 1) понекад враћа исти датум?

Ово је повезано са различитом дужином месеци. Ако је текући датум 31. јануар, додавање 1 месеца даје 28. фебруар, јер фебруар нема 31 дан. Calendar аутоматски завршава датум до последњег дозвољеног дана месеца. За прецизну контролу користите DateComponents са day: 1 за прелазак на први дан месеца.

Који календар подразумевано користи DateFormatter?

DateFormatter користи Calendar.current — системски календар корисника. Ако апликација увек треба да приказује датуме у грегоријанском календару без обзира на подешавања, подесите formatter.calendar = Calendar(identifier: .gregorian). Ово гарантује једнообразни приказ за све кориснике.

Како проверити да ли је година преступна кроз Calendar?

Calendar.range(of: .day, in: .year, for: date) враћа 365 или 366 дана. Једноставније: Calendar.date(from: DateComponents(year: година, month: 2, day: 29)) != nil — ако 29. фебруар постоји, година је преступна. Calendar сам узима у обзир правила за одређени календарски систем.

Може ли се firstWeekday променити након креирања Calendar?

Да, својство firstWeekday је доступно за писање. Промена утиче на weekOfMonth, weekOfYear и сва израчунавања повезана са бројевима недеља. При постављању locale = Locale(identifier: "sr_RS") firstWeekday аутоматски постаје 2 (понедељак). Ручно подешавање замењује вредност из locale.

Закључак

  • Calendar — класа Foundation за календарска израчунавања, која повезује Date са људски читљивим компонентама кроз DateComponents.
  • 17 календарских система подржава Foundation — од грегоријанског до будистичког и јапанског, са аутоматским узимањем у обзир регионалних правила.
  • Calendar.current одговара системском календару корисника — користите га за UI и DateFormatter.
  • Calendar.dateInterval и Calendar.range — кључне методе за рад са границама периода и опсезима компоненти.
  • Calendar.date(byAdding:) коректно обрађује различиту дужину месеци и преступне године — не замењујте га TimeInterval аритметиком.
  • TimeZone и Locale као својства Calendar утичу на сва календарска израчунавања — подесите их експлицитно за предвидљиво понашање.
  • firstWeekday се одређује локалом и утиче на бројеве недеља — за глобалне апликације подесите га експлицитно или користите Calendar.current.

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

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

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

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