DateIntervalFormatter — основи форматування інтервалів дат

Автор: IT Sectr Опубліковано: 2026-07-13 Час читання: 11 хв

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 — клас Foundation для форматування діапазонів дат (iOS 8+)
  • Автоматичне групування — повторювані компоненти (місяць, рік) виводяться один раз
  • Локалізовані розділювачі — врахування граматичних правил: «по» (українська), тире (англійська)
  • П'ять стилів дати — .none, .short, .medium, .long, .full для кожного кінця діапазону
  • Чотири стилі часу — ті ж рівні деталізації для часової частини діапазону

Що таке DateIntervalFormatter?

DateIntervalFormatter — це підклас Formatter в Foundation, який приймає об'єкт DateInterval (діапазон між двома датами) і повертає локалізований рядок з описом цього діапазону. Наприклад, для діапазону з 21 по 25 липня 2024 року результат буде «21–25 липня 2024 р.» для uk_UA. Клас розумно групує повторювані елементи: якщо обидві дати в одному місяці, назва місяця виводиться один раз.

Основна цінність DateIntervalFormatter — автоматична обробка граматики діапазонів. При ручному форматуванні розробнику довелося б порівнювати місяць/рік початку та закінчення, вибирати розділювач (тире, «по», «to», «bis») і слідкувати за відмінюванням. DateIntervalFormatter робить це автоматично на основі даних CLDR (Common Locale Data Repository), що зменшує кількість помилок в інтернаціональних додатках, особливо для мов зі складною граматикою.

За даними Unicode CLDR v44 (2024), правила форматування інтервалів дат сильно відрізняються між мовами. Німецька використовує прийменник «bis» (21.–25. Juli 2024), французька — «au» (du 21 au 25 juillet 2024), японська — через дефіс (2024 Jul 21–25). DateIntervalFormatter покриває всі ці варіації без додаткового коду з боку розробника.

Як працює DateIntervalFormatter в Foundation?

Принцип роботи DateIntervalFormatter заснований на аналізі двох дат, що утворюють діапазон, і виборі оптимального рядкового представлення з урахуванням локалі. Клас порівнює компоненти дат (рік, місяць, день) і приймає рішення про групування: якщо рік однаковий — виводиться один раз; якщо місяць однаковий — виводиться один раз; якщо дні різняться — виводиться діапазон днів.

Діапазонuk_UA
Один день21 липня 2024 р.
В межах місяця21–25 липня 2024 р.
Різні місяці21 липня – 5 серпня 2024 р.
Різні роки25 грудня 2024 р. – 5 січня 2025 р.
З часом21 липня 2024 р., 14:30–16:45

Логіка групування реалізована на основі шаблонів CLDR. Форматувальник перевіряє рівність кожного компонента дати (Calendar.Component: year, month, day) в порядку від старшого до молодшого. Як тільки компонент відрізняється, всі молодші компоненти виводяться для обох дат. Наприклад, для 21–25 липня: рік збігається, місяць збігається, день відрізняється → місяць виводиться один раз, дні — для кожної дати.

Важливий нюанс: DateIntervalFormatter не підтримує налаштування розділювача через API. Розділювач визначається локаллю і не може бути перевизначений. Якщо потрібен нестандартний розділювач (наприклад, «до» замість «по»), доведеться форматувати дати вручну через DateFormatter і склеювати рядки з кастомним розділювачем.

Стилі форматування інтервалів

DateIntervalFormatter надає два набори стилів: dateStyle та timeStyle для кожного кінця діапазону. Ці стилі працюють аналогічно DateFormatter: .none приховує компонент, .short дає короткий формат (21.07.2024), .medium — середній (21 лип. 2024 р.), .long — повний (21 липня 2024 р.), .full — максимально детальний (неділя, 21 липня 2024 р.). Комбінуючи dateStyle та timeStyle, можна отримати різні рівні деталізації.

Приклади комбінацій стилів

  • dateStyle = .medium, timeStyle = .none — лише дата: «21–25 липня 2024 р.»
  • dateStyle = .short, timeStyle = .short — дата та час: «21.07.2024, 14:30 – 25.07.2024, 16:45»
  • dateStyle = .none, timeStyle = .short — лише час: «14:30–16:45» (якщо дати однакові)
  • dateStyle = .long, timeStyle = .none — довга дата: «21–25 липня 2024 року»
  • dateStyle = .full, timeStyle = .short — повний формат: «неділя, 21 липня 2024 р. – четвер, 25 липня 2024 р.»

Важливо: dateStyle та timeStyle застосовуються до обох кінців діапазону однаково. Не можна задати різний стиль для початку та кінця (наприклад, .medium для початку та .short для кінця). Якщо потрібен різний стиль, необхідно форматувати кожну дату окремим DateFormatter і склеювати результати.

swift
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 в Swift: приклади

Базове використання DateIntervalFormatter включає створення екземпляра, налаштування стилів і виклик string(from:). Метод приймає DateInterval — структуру з властивостями start та end. DateInterval можна створити як з двох Date, так і ініціалізувати з Duration (iOS 16+). Після форматування результат готовий до відображення в UI без додаткової обробки.

swift
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 — найбільш читабельний формат для дат без часу.

swift
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)")

// Використання з різними локалями
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 явно. На відміну від DateFormatter, DateIntervalFormatter не вимагає встановлення Locale для серверних даних — він завжди використовує свою внутрішню логіку групування на основі CLDR.

Мовні відмінності у форматуванні інтервалів дат значно складніші, ніж для одиночних дат. Англійська використовує просте тире: Jul 21–25. Українська — прийменник «по»: з 21 по 25 липня. Французька — прийменник «au»: du 21 au 25 juillet. Німецька — крапка після числа та тире: 21.–25. Juli. DateIntervalFormatter покриває всі ці варіанти.

swift
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)

// Демонстрація різних локалей
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 86012024-07-21T14:30:00Z

Коли використовувати DateIntervalFormatter: для відображення діапазонів дат в UI — бронювання готелів, подій, фільтрація за датами, історія операцій. Для підрахунку тривалості між датами використовуйте DateComponentsFormatter, а не DateIntervalFormatter — другий не призначений для відображення тривалості. DateFormatter слід використовувати лише для одиночних дат, а не для склеювання двох відформатованих дат через рядкову конкатенацію — це призводить до втрати локалізації розділювача.

Edge case: DateIntervalFormatter не підтримує відображення open-ended інтервалів (без дати закінчення). Якщо кінець діапазону невідомий (наприклад, «з 21 липня»), використовуйте DateFormatter з прийменником «з» для української мови або «from» для англійської. Також DateIntervalFormatter не підтримує інтервали із зазначенням часу для різних днів — час застосовується до кожної дати окремо, що може виглядати надмірно для коротких інтервалів.

Часті запитання

Що таке DateIntervalFormatter?

DateIntervalFormatter — клас Foundation для форматування діапазонів дат у локалізовані рядки. Доступний з iOS 8, автоматично групує повторювані компоненти (місяць, рік) та вибирає правильний розділювач для мови.

Як DateIntervalFormatter групує дати?

Порівнює компоненти від року до дня. Якщо рік збігається — виводиться один раз. Якщо місяць збігається — виводиться один раз. Різні дні виводяться як діапазон. Це дає «21–25 липня 2024» замість «21 липня 2024 – 25 липня 2024».

Чи можна змінити розділювач діапазону?

Ні, розділювач визначається локаллю і не налаштовується через API. Для кастомного розділювача (наприклад, «до» замість «по») форматуйте кожну дату окремим DateFormatter і склеюйте рядки вручну.

Чим DateIntervalFormatter відрізняється від DateFormatter?

DateIntervalFormatter форматує діапазон дат (дві дати) як єдине ціле з групуванням компонентів. DateFormatter форматує одну дату. Для діапазонів завжди використовуйте DateIntervalFormatter — це дає коректну локалізацію розділювача.

Як відформатувати інтервал з різними роками?

Автоматично — DateIntervalFormatter визначає, що роки різні, і виводить повні дати для обох кінців: «25 грудня 2024 р. – 5 січня 2025 р.». Жодних додаткових налаштувань не потрібно, достатньо встановити dateStyle.

Підсумки

  • DateIntervalFormatter — спеціалізований клас для форматування діапазонів дат (iOS 8+)
  • Автоматичне групування — повторювані компоненти (рік, місяць) виводяться один раз для всього діапазону
  • Локалізовані розділювачі — «по» (українська), тире (англійська), «bis» (німецька) — автоматично
  • Стилі дати та часу — комбінації .none, .short, .medium, .long, .full для кожного кінця діапазону
  • Не підходить для тривалості — для підрахунку тривалості використовуйте DateComponentsFormatter
  • Не підтримує кастомні розділювачі — для нестандартних випадків потрібне ручне форматування
  • Інтеграція з DateInterval — структура DateInterval надає перевірку contains та intersection

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також