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 г.“ за bg_BG и „Jul 21–25, 2024“ за en_US. Класът интелигентно групира повтарящите се елементи: ако и двете дати са в един и същ месец, името на месеца се показва веднъж.

Основната стойност на 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 се основава на анализ на две дати, образуващи диапазона, и избор на оптимално текстово представяне, като се взема предвид locale. Класът сравнява компонентите на датата (година, месец, ден) и взема решение за групиране: ако годината е същата — показва се веднъж; ако месецът е същият — показва се веднъж; ако дните се различават — показва се диапазонът от дни.

Диапазонbg_BGen_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:45Jul 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 = .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 — структура с properties 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)")

// Използване с различни locale
let enFormatter = DateIntervalFormatter()
enFormatter.dateStyle = .medium
enFormatter.timeStyle = .none
enFormatter.locale = Locale(identifier: "en_US")
print("Английски: \(enFormatter.string(from: interval))")

DateInterval срещу 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 покрива всички тези варианти.

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)

// Демонстрация на различни 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 минути
ISO8601DateFormatterISO 8601 формат2024-07-21T14:30:00Z

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

Граничен случай: DateIntervalFormatter не поддържа показване на отворени диапазони (без крайна дата). Ако краят на диапазона е неизвестен (например „от 21 юли“), използвайте DateFormatter с предлог „от“ за български или „from“ за английски. DateIntervalFormatter също не поддържа диапазони с посочване на час за различни дни — часът се прилага към всяка дата поотделно, което може да изглежда излишно за кратки диапазони.

Често задавани въпроси

Какво е DateIntervalFormatter?

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

Как DateIntervalFormatter групира дати?

Сравнява компоненти от година до ден. Ако годината съвпада — показва се веднъж. Ако месецът съвпада — показва се веднъж. Различните дни се показват като диапазон. Това дава „21–25 юли 2024 г.“ вместо „21 юли 2024 г. – 25 юли 2024 г.“

Може ли да се промени разделителят на диапазона?

Не, разделителят се определя от locale и не може да бъде конфигуриран чрез 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също