DateIntervalFormatter је класа Foundation у iOS и macOS намењена за форматирање опсега датума у локализоване низове: „21–25. јул 2024.“, „од 21. до 25. јула 2024.“ или „Jul 21–25, 2024“. Према Apple Developer Documentation, 2024, DateIntervalFormatter аутоматски одређује које компоненте датума треба понављати (ако је опсег у оквиру једног месеца — месец се приказује једном) и локализује сепараторе и редослед речи. За разлику од ручног лепљења две форматиране датума, ова класа узима у обзир граматичка правила језика: за српски — предлог „до“, за енглески — цртица без предлога. Класа је доступна од iOS 8 и macOS 10.10.
Главно
DateIntervalFormatter је подкласа Formatter-а у Foundation-у која прима објекат DateInterval (опсег између два датума) и враћа локализовани низ са описом овог опсега. На пример, за опсег од 21. до 25. јула 2024. резултат ће бити „21–25. јул 2024.“ за sr_RS и „Jul 21–25, 2024“ за en_US. Класа интелигентно групише елементе који се понављају: ако су оба датума у истом месецу, назив месеца се приказује једном.
Основна вредност DateIntervalFormatter-а је аутоматска обрада граматике опсега. Код ручног форматирања, програмер би морао да упореди месец/годину почетка и краја, изабере сепаратор (цртица, „од–до“, „to“, „bis“) и прати деклинацију. DateIntervalFormatter то ради аутоматски на основу CLDR (заједничког репозиторијума локалних података), што смањује број грешака у међународним апликацијама, посебно за језике са сложеном граматиком.
Према Unicode CLDR v44 (2024), правила форматирања опсега датума се значајно разликују између језика. Немачки користи предлог „bis“ (21.–25. Juli 2024), француски — „au“ (du 21 au 25 juillet 2024), јапански — кроз цртицу (2024 Jul 21–25). DateIntervalFormatter покрива све ове варијације без додатног кода на страни програмера.
Принцип рада DateIntervalFormatter-а заснива се на анализи два датума који чине опсег и избору оптималног текстуалног приказа узимајући у обзир locale. Класа упоређује компоненте датума (годину, месец, дан) и доноси одлуку о груписању: ако је година иста — приказује се једном; ако је месец исти — приказује се једном; ако се дани разликују — приказује се опсег дана.
| Опсег | sr_RS | en_US |
|---|---|---|
| Један дан | 21. јул 2024. | Jul 21, 2024 |
| У оквиру месеца | 21–25. јул 2024. | Jul 21–25, 2024 |
| Различити месеци | 21. јул – 5. авг 2024. | Jul 21 – Aug 5, 2024 |
| Различите године | 25. дец 2024. – 5. јан 2025. | Dec 25, 2024 – Jan 5, 2025 |
| Са временом | 21. јул 2024, 14:30–16:45 | Jul 21, 2024, 2:30–4:45 PM |
Логика груписања је имплементирана на основу CLDR образаца. Форматер проверава једнакост сваке компоненте датума (Calendar.Component: year, month, day) редом од највеће ка најмањој. Чим компонента постане различита, све мање компоненте се приказују за оба датума. На пример, за 21–25. јул: година се поклапа, месец се поклапа, дан се разликује → месец једном, дани — за сваки датум посебно.
Важан нијанс: DateIntervalFormatter не подржава подешавање сепаратора кроз API. Сепаратор је одређен locale-ом и не може бити прегазан. Ако је потребан прилагођен сепаратор (на пример, „до“ уместо „–“), мораћете да форматирате датуме ручно преко DateFormatter-а и лепите низове са прилагођеним сепаратором.
DateIntervalFormatter пружа два скупа стилова: dateStyle и timeStyle — за сваки крај опсега. Ови стилови раде слично DateFormatter-у: .none сакрива компоненту, .short даје кратак формат (21.07.2024), .medium — средњи (21. јул 2024.), .long — пуни (21. јула 2024.), .full — максимално детаљан (недеља, 21. јул 2024.). Комбиновањем dateStyle и timeStyle могу се добити различити нивои детаља.
Важно: dateStyle и timeStyle се примењују на оба краја опсега једнако. Не може се поставити различит стил за почетак и крај (на пример, .medium за почетак и .short за крај). Ако је потребан различит стил, мораћете да форматирате сваки датум посебним DateFormatter-ом и лепите резултате.
import Foundation
let formatter = DateIntervalFormatter()
// Различите комбинације стилова
let startDate = Date()
let endDate = Date().addingTimeInterval(345600) // +4 дана
let interval = DateInterval(start: startDate, end: endDate)
// Само датум, средњи формат
formatter.dateStyle = .medium
formatter.timeStyle = .none
print("Само датум: \(formatter.string(from: interval))")
// Кратак формат са временом
formatter.dateStyle = .short
formatter.timeStyle = .short
print("Кратак са временом: \(formatter.string(from: interval))")
// Пуни формат
formatter.dateStyle = .full
formatter.timeStyle = .none
print("Пуни датум: \(formatter.string(from: interval))")
Основно коришћење DateIntervalFormatter-а укључује креирање инстанце, конфигурисање стилова и позив методе string(from:). Метода прима DateInterval — структуру са start и end особинама. DateInterval се може креирати и од два Date, и иницијализовати са Duration (iOS 16+). Након форматирања, резултат је спреман за приказ у UI-ју без додатне обраде.
import Foundation
let calendar = Calendar.current
let now = Date()
// Примери конкретних интервала
let examples: [(title: String, start: Date, end: Date)] = [
(
"2-hour event",
now,
now.addingTimeInterval(7200)
),
(
"Week-long vacation",
now,
now.addingTimeInterval(604800)
),
(
"Cross-year period",
calendar.date(from: DateComponents(
year: 2024, month: 12, day: 25
))!,
calendar.date(from: DateComponents(
year: 2025, month: 1, day: 5
))!
)
]
let intervalFormatter = DateIntervalFormatter()
intervalFormatter.dateStyle = .medium
intervalFormatter.timeStyle = .short
for (title, start, end) in examples {
let interval = DateInterval(start: start, end: end)
let result = intervalFormatter.string(from: interval)
print("\(title): \(result)")
}
// Форматирање преко Calendar (iOS 16+)
if let nextWeek = calendar.date(
byAdding: .day, value: 7, to: now
) {
let weekInterval = DateInterval(start: now, end: nextWeek)
print("Следећих 7 дана: \(intervalFormatter.string(from: weekInterval))")
}
DateIntervalFormatter и Calendar Booking: у апликацијама за резервације (хотели, карте) опсези датума су кључни елемент UI-ја. DateIntervalFormatter исправно обрађује међугодишње опсеге (на пример, од 28. децембра до 3. јануара), групишући месец и годину за сваки датум посебно. За овакве сценарије препоручује се коришћење dateStyle = .medium и timeStyle = .none — најчитљивији формат за датуме без времена.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
// Примери резервација
struct Booking {
let checkIn: Date
let checkOut: Date
var formattedInterval: String {
let interval = DateInterval(start: checkIn, end: checkOut)
return formatter.string(from: interval)
}
}
let booking = Booking(
checkIn: calendar.date(from: DateComponents(
year: 2024, month: 7, day: 21
))!,
checkOut: calendar.date(from: DateComponents(
year: 2024, month: 7, day: 25
))!
)
print("Резервација: \(booking.formattedInterval)")
// Коришћење са различитим locale
let enFormatter = DateIntervalFormatter()
enFormatter.dateStyle = .medium
enFormatter.timeStyle = .none
enFormatter.locale = Locale(identifier: "en_US")
print("Енглески: \(enFormatter.string(from: interval))")
DateInterval vs DateIntervalFormatter: DateInterval — структура која представља опсег датума (почетак и крај). DateIntervalFormatter — форматер који претвара ову структуру у низ. DateInterval такође подржава провере contains(Date) и intersection(with:), што је корисно за логику резервација (провера преклапања датума).
DateIntervalFormatter локализује излаз кроз својство locale. Подразумевано се користи Locale.current — locale уређаја. За приказ интервала на другом језику (на пример, енглески садржај у српском интерфејсу), поставите locale експлицитно. За разлику од DateFormatter-а, DateIntervalFormatter не захтева постављање Locale за серверске податке — увек користи сопствену интерну логику груписања засновану на CLDR.
Језичке разлике у форматирању опсега датума значајно су сложеније него за појединачне датуме. Енглески користи једноставну цртицу: Jul 21–25. Српски — предлог „од–до“: од 21. до 25. јула. Француски — предлог „au“: du 21 au 25 juillet. Немачки — тачка након броја и цртица: 21.–25. Juli. Јапански — кроз цртицу без предлога: Jul 21–25. DateIntervalFormatter покрива све ове варијанте.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
let start = Date()
let end = Date().addingTimeInterval(259200) // +3 дана
let interval = DateInterval(start: start, end: end)
// Приказ различитих locale
let localeIds = ["ru_RU", "en_US", "de_DE", "fr_FR", "ja_JP", "zh_CN"]
for localeId in localeIds {
formatter.locale = Locale(identifier: localeId)
print("\(localeId): \(formatter.string(from: interval))")
}
// Локализација за временске интервале
formatter.dateStyle = .none
formatter.timeStyle = .short
let todayStart = Date()
let todayEnd = Date().addingTimeInterval(3600)
let timeInterval = DateInterval(start: todayStart, end: todayEnd)
for localeId in ["ru_RU", "en_US", "de_DE"] {
formatter.locale = Locale(identifier: localeId)
print("\(localeId) време: \(formatter.string(from: timeInterval))")
}
Карактеристике локализације: за српски језик DateIntervalFormatter користи предлоге „од“ и „до“ за дугачке формате датума. За кратак (short) формат — само цртица: 21.07–25.07.2024. За пуни формат (full) — са навођењем дана у недељи. Избор формата зависи од контекста: за листу резервација користите .medium, за детаљан преглед — .long или .full.
DateIntervalFormatter заузима нишу форматирања опсега датума коју друге класе Foundation-а не покривају. DateFormatter форматира појединачне датуме, RelativeDateTimeFormatter — односне датуме (пре/за), DateComponentsFormatter — трајање (2 сата 30 минута). Свака од ових класа решава сопствени задатак и не могу се замењивати.
| Класа | Намена | Пример излаза |
|---|---|---|
| DateIntervalFormatter | Опсег датума | 21–25. јул 2024. |
| DateFormatter | Појединачни датум | 21. јул 2024. |
| RelativeDateTimeFormatter | Односно време | Пре 3 дана |
| DateComponentsFormatter | Трајање | 2 сата 30 минута |
| ISO8601DateFormatter | ISO 8601 формат | 2024-07-21T14:30:00Z |
Када користити DateIntervalFormatter: за приказ опсега датума у UI-ју — резервација хотела, догађаја, филтрирање по датумима, историја операција. За рачунање трајања између датума користите DateComponentsFormatter, а не DateIntervalFormatter — други није намењен за приказ трајања. DateFormatter користите само за појединачне датуме, а не за лепљење две форматиране датума путем конкатенације низа — то доводи до губитка локализације сепаратора.
Гранични случај: DateIntervalFormatter не подржава приказ отворених опсега (без крајњег датума). Ако је крај опсега непознат (на пример, „од 21. јула“), користите DateFormatter са предлогом „од“ за српски или „from“ за енглески. DateIntervalFormatter такође не подржава опсеге са наводом времена за различите дане — време се примењује на сваки датум посебно, што може изгледати сувишно за кратке опсеге.
Често постављана питања
DateIntervalFormatter — класа Foundation за форматирање опсега датума у локализоване низове. Доступна од iOS 8, аутоматски групише компоненте које се понављају (месец, година) и бира прави сепаратор за језик.
Пореди компоненте од године ка дану. Ако се година поклапа — приказује се једном. Ако се месец поклапа — приказује се једном. Различити дани се приказују као опсег. То даје „21–25. јул 2024.“ уместо „21. јул 2024. – 25. јул 2024.“
Не, сепаратор је одређен locale-ом и не може се подесити кроз API. За прилагођен сепаратор (на пример, „до“ уместо „–“), форматирајте сваки датум посебним DateFormatter-ом и лепите низове ручно.
DateIntervalFormatter форматира опсег датума (два датума) као једну целину са груписањем компонената. DateFormatter форматира један датум. За опсеге увек користите DateIntervalFormatter — то осигурава исправну локализацију сепаратора.
Аутоматски — DateIntervalFormatter открива да су године различите и приказује пуне датуме за оба краја: „25. децембар 2024. – 5. јануар 2025.“. Никаква додатна подешавања нису потребна, довољно је поставити dateStyle.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође