RelativeDateTimeFormatter: mohiyati, nisbiy sanalar va Swift

Muallif: IT Sectr Nashr etilgan: 2026-07-13 O'qish vaqti: 10 daq

RelativeDateTimeFormatter — bu iOS va macOS-dagi Foundation sinfi bo'lib, mutlaq sanalarni odam o'qiy oladigan nisbiy iboralarga aylantiradi: “5 daqiqa oldin”, “kecha”, “3 kundan keyin”. Apple Developer Documentation, 2024 ma'lumotlariga ko'ra, RelativeDateTimeFormatter mos birlikni (soniyalar, daqiqalar, soatlar, kunlar) avtomatik tanlaydi va natijani qurilmaning joriy lokali tilida lokalizatsiya qiladi. Calendar orqali sanalar orasidagi farqni qo'lda hisoblashdan farqli o'laroq, bu sinf har bir tilning lingvistik xususiyatlarini hisobga oladi: ba'zi tillarda sonlar tuslanadi, boshqalarida — “kecha” so'zi uchun alohida shakl ishlatiladi. Sinf iOS 13 va macOS 10.15 dan boshlab mavjud.

Asosiy narsa

  • RelativeDateTimeFormatter — iOS va macOS-da nisbiy sanalarni ko'rsatish uchun sinf (iOS 13+)
  • Lokalizatsiya qilingan natija — joriy lokali tilida iboralarni avtomatik tanlaydi
  • Kontekstning uch turi — past (oldinga), future (keyin), present (hozir) turli iboralar bilan
  • Birlikni avtomatik tanlash — soniyalar, daqiqalar, soatlar, kunlar, haftalar, oylar, yillar
  • Uslubni sozlash — numeric (3 kundan keyin) yoki abbreviated (3 kundan keyin)

RelativeDateTimeFormatter nima?

RelativeDateTimeFormatter — Foundation-dagi Formatter ning kichik sinfi bo'lib, u Date (yoki soniyalardagi farq) ni qabul qiladi va nisbiy vaqt bilan lokalizatsiya qilingan satrni qaytaradi. Masalan, joriy vaqtdan 5 daqiqa oldingi sana uchun ru_RU uchun “5 daqiqa oldin” yoki en_US uchun “5 minutes ago” qaytaradi. Sinf uchta vaqt kontekstini qo'llab-quvvatlaydi: o'tmish (past), kelajak (future) va hozirgi (present).

RelativeDateTimeFormatter ning ichki mantig'i sanalar orasidagi farqni hisoblash va to'g'ri grammatik shaklni tanlash uchun Calendar va Locale dan foydalanadi. O'zbek tili uchun sinf sonlarni to'g'ri tuslaydi: “1 daqiqa oldin”, “2 daqiqa oldin”, “5 daqiqa oldin”. Ingliz tili uchun esa “minute ago” va “minutes ago” o'rtasida tanlaydi. Bu funksional ICU (International Components for Unicode) ma'lumotlariga asoslangan va dasturchidan qo'shimcha sozlashni talab qilmaydi.

Apple WWDC 2019 ma'lumotlariga ko'ra, RelativeDateTimeFormatter lokalizatsiyani soddalashtirish uchun freymvorkning bir qismiga aylandi — paydo bo'lishidan oldin dasturchilar sana farqini qo'lda hisoblashga va String.localizedStringWithFormat orqali lokalizatsiya qilingan satrlarni kiritishga majbur edilar. Bu tuslashda (ayniqsa slavyan va arab tillari uchun) xatolarga va o'lchov birliklarini noto'g'ri tanlashga olib kelardi.

RelativeDateTimeFormatter “5 daqiqa oldin” ni qanday ko'rsatadi?

Ish algoritmi RelativeDateTimeFormatter uch bosqichdan iborat: uzatilgan sana bilan joriy vaqt orasidagi farqni hisoblash, mos birlikni (nol bermaydigan eng kattasini) tanlash va lokalni hisobga olgan holda formatlash. Masalan, 3720 soniya farq (1 soat 2 daqiqa) uchun “soat” birligi tanlanadi va natija “1 soat oldin” bo'ladi, “62 daqiqa oldin” emas.

Birliklar “eng katta nolga teng bo'lmagan” tamoyili bo'yicha tanlanadi: agar farq 86400 soniyadan (1 kun) katta bo'lsa, kunlar ishlatiladi; agar 604800 dan (1 hafta) katta bo'lsa — haftalar va hokazo. Bu algoritm natija doimo tabiiy o'qilishini kafolatlaydi: “518400 soniya oldin” o'rniga foydalanuvchi “6 kun oldin” ni ko'radi. Birliklarning aniq chegaralarini joriy lokali taqvimi belgilaydi.

Farq diapazoniBirlikru_RU uchun misol
0–59 soniyaSeconds30 soniya oldin
1–59 daqiqaMinutes5 daqiqa oldin
1–23 soatHours3 soat oldin
1–6 kunDays2 kun oldin
7–27 kunWeeks1 hafta oldin
28 kun–11 oyMonths3 oy oldin
12+ oyYears1 yil oldin

Formatlash konteksti iboraning oxirini belgilaydi. O'tmish uchun: “oldin” (o'zbek), “ago” (ingliz). Kelajak uchun: “3 kundan keyin” (o'zbek), “in 3 days” (ingliz). Hozirgi uchun: “hozir” (o'zbek), “now” (ingliz). Kontekst localizeString(fromTimeInterval:) metodi yoki to'g'ridan-to'g'ri string(from: Date) orqali o'rnatiladi.

Birliklar va uslublar sozlamalari

RelativeDateTimeFormatter natijani boshqarish uchun bir nechta sozlashlarni taqdim etadi: unitsStyle xossasi formatlash uslubini (numeric, abbreviated, full, spellOut) belgilaydi, maximumUnitCount esa ko'rsatiladigan birliklar sonini cheklaydi. Masalan, maximumUnitCount = 1 bilan 1 soat 30 daqiqalik farq “1 soat 30 daqiqa oldin” o'rniga “1 soat oldin” sifatida ko'rsatiladi.

Formatlash uslublari

  • .numeric — to'liq sonli qiymat: “3 kun oldin”, “2 haftadan keyin”. Odatiy holda UI uchun tavsiya etiladi
  • .abbreviated — qisqartirilgan shakl: “3 kun oldin”, “2 haftadan keyin”. Jadvallar va ro'yxatlarda ixcham ko'rsatish uchun
  • .full — raqamsiz so'z shakli: “uch kun oldin”. Accessibility va ovozli interfeyslar uchun
  • .spellOut — muqobil yozilishli harf shakli: “three days ago”. Kamdan-kam, asosan maxsus maqsadlar uchun ishlatiladi

Birliklarni cheklash: odatiy holda RelativeDateTimeFormatter faqat bitta (eng katta) birlikni ko'rsatadi. maximumUnitCount = 2 o'rnatish aniqroq tavsif uchun keyingi birlikni qo'shadi: “1 soat 30 daqiqa oldin”. Biroq bu qisqa xabarlar (push, bildirishnomalar) uchun satrni haddan tashqari uzun qilishi mumkin. UI uchun maximumUnitCount = 1 ni qoldirish tavsiya etiladi.

swift
import Foundation

let formatter = RelativeDateTimeFormatter()

// Uslublarni sozlang
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1

// Turli sanalar bilan misollar
let fiveMinAgo = Date().addingTimeInterval(-300)
print("5 daqiqa oldin: \(formatter.localizedString(for: fiveMinAgo, relativeTo: Date()))")

let twoDaysLater = Date().addingTimeInterval(172800)
print("2 kundan keyin: \(formatter.localizedString(for: twoDaysLater, relativeTo: Date()))")

// Qisqartirilgan uslub
formatter.unitsStyle = .abbreviated
let oneWeekAgo = Date().addingTimeInterval(-604800)
print("Qisqartirilgan: \(formatter.localizedString(for: oneWeekAgo, relativeTo: Date()))")

// To'liq uslub (so'z bilan)
formatter.unitsStyle = .full
let threeHours = Date().addingTimeInterval(10800)
print("To'liq: \(formatter.localizedString(for: threeHours, relativeTo: Date()))")

Turli kontekstlar uchun uslub tanlash: yangiliklar lentasi uchun maximumUnitCount = 1 bilan .numeric dan foydalaning — bu Twitter, Instagram va Facebook uchun standartdir. Accessibility (VoiceOver) uchun .full dan foydalaning — so'z bilan yozilgan raqamlar tabiiyroq o'qiladi. Ixcham elementlar (bildirishnoma burchagi, holat qatori) uchun joyni tejash maqsadida .abbreviated dan foydalaning.

Swift-da RelativeDateTimeFormatter: misollar

Asosiy foydalanish RelativeDateTimeFormatter namunani yaratish, xossalarni sozlash va formatlash metodlaridan birini chaqirishdan iborat. Asosiy metodlar: localizedString(for:relativeTo:) — sanalar juftligi uchun, localizedString(fromTimeInterval:) — soniyalardagi farq uchun va string(for:) — avtomatik kontekstli (o'tmish/kelajak) Date uchun.

swift
import Foundation

let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1

// Ijtimoiy tarmoq UI misollari
let postDates: [(title: String, date: Date)] = [
    ("Just now", Date().addingTimeInterval(-30)),
    ("5 min ago", Date().addingTimeInterval(-300)),
    ("Yesterday", Date().addingTimeInterval(-90000)),
    ("Last week", Date().addingTimeInterval(-700000)),
    ("Last year", Date().addingTimeInterval(-32000000))
]

for (title, postDate) in postDates {
    let relative = formatter.localizedString(
        for: postDate,
        relativeTo: Date()
    )
    print("\(title): \(relative)")
}

// Kelajak sanalari
let reminderFormatter = RelativeDateTimeFormatter()
reminderFormatter.unitsStyle = .abbreviated
let inOneHour = Date().addingTimeInterval(3600)
let reminderText = reminderFormatter.localizedString(
    for: inOneHour,
    relativeTo: Date()
)
print("Eslatma: \(reminderText)")

“hozirgina” ssenariysini qayta ishlash — RelativeDateTimeFormatter juda kichik intervallar uchun “hozirgina” iborasini o'rnatilgan qo'llab-quvvatlashga ega emas. 5 soniyadan kam farq uchun “0 soniya oldin” qaytaradi, bu UI da chiroyli ko'rinmaydi. Formatter chaqiruvini shartli mantiqqa o'rash tavsiya etiladi: agar farq belgilangan chegaradan (masalan, 5 soniya) kam bo'lsa — “hozirgina” ni qo'lda ko'rsating, aks holda sanani formatterga uzating.

swift
import Foundation

func relativeTimeString(from date: Date) -> String {
    let interval = Date().timeIntervalSince(date)

    // “Hozirgina” chegarasi
    if interval < 5 {
        return "just now"
    }

    // “Bugun” chegarasi
    if interval < 60 {
        return "just now"
    }

    let formatter = RelativeDateTimeFormatter()
    formatter.unitsStyle = .numeric
    formatter.maximumUnitCount = 1

    // “oldin” qo'shimchasiz ko'rsatish
    return formatter.localizedString(
        for: date,
        relativeTo: Date()
    )
}

print(relativeTimeString(from: Date().addingTimeInterval(-3)))
print(relativeTimeString(from: Date().addingTimeInterval(-120)))
print(relativeTimeString(from: Date().addingTimeInterval(-3600)))

string(fromTimeInterval:) metodi soniyalardagi farqni qabul qiladi va kontekstni avtomatik aniqlaydi (musbat qiymat — kelajak, manfiy — o'tmish). Bu farq allaqachon ma'lum bo'lganda qulay (masalan, serverdan unix timestamp sifatida olingan). Bu holda Date yaratish shart emas — farq to'g'ridan-to'g'ri uzatiladi.

Nisbiy sanalarni lokalizatsiya qilish

RelativeDateTimeFormatter natijani Locale.current asosida avtomatik lokalizatsiya qiladi. Formatlash tilini o'zgartirish uchun locale xossasini o'rnating — DateFormatter dan farqli o'laroq, RelativeDateTimeFormatter uchun locale qat'iy emas va uni har bir chaqiruv uchun o'zgartirish mumkin. Bu nisbiy sanalarni interfeys tilidan boshqa tilda (masalan, asl tildagi kontent) ko'rsatishga imkon beradi.

Nisbiy sanalarni lokalizatsiya qilishning murakkabligi turli tillarning grammatik xususiyatlaridadir. Rus tili sonlarning turli shakllarini talab qiladi: “1 daqiqa”, “2 daqiqa”, “5 daqiqa”. Arab tili — 3 dan 10 gacha bo'lgan sonlar uchun ko'plik shaklini va 11+ uchun maxsus shakllarni ishlatadi. Xitoy tilida — umuman tuslanish yo'q, bu vazifani soddalashtiradi. RelativeDateTimeFormatter barcha bu holatlarni ICU qoidalari orqali qo'shimcha kodsiz qamrab oladi.

swift
import Foundation

let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1

let targetDate = Date().addingTimeInterval(-7200) // 2 soat oldin

// Turli lokallar
let locales: [String] = ["ru_RU", "en_US", "de_DE", "fr_FR", "ja_JP", "ar_SA"]

for identifier in locales {
    formatter.locale = Locale(identifier: identifier)
    let result = formatter.localizedString(
        for: targetDate,
        relativeTo: Date()
    )
    print("\(identifier): \(result)")
}

// Ruscha tuslanishni tekshiring
formatter.locale = Locale(identifier: "ru_RU")
let intervals: [TimeInterval] = [-60, -120, -180, -300]
for interval in intervals {
    let date = Date().addingTimeInterval(interval)
    print("\(-Int(interval / 60)) daqiqa: \(formatter.localizedString(for: date, relativeTo: Date()))")
}

Muhim nuance: RelativeDateTimeFormatter .numeric sozlamalari uchun farqni hisoblashda TimeZone ni e'tiborsiz qoldiradi — u soniyalardagi mutlaq farqdan foydalanadi. Biroq .full uslubi (so'z bilan yozilgan raqamlar bilan) va maxsus holatlar (kecha, bugun) uchun TimeZone hisobga olinadi. Izchillik uchun doim TimeZone ni aniq o'rnating, ayniqsa ilova server sanalari bilan UTC da ishlasa.

Formatlashdagi odatiy xatolar

Nisbiy sanalarni hisoblashda TimeZone ni e'tiborsiz qoldirish — server sanalari bilan ishlashda keng tarqalgan xato. Agar server Date ni UTC da yuborsa, RelativeDateTimeFormatter esa TimeZone.current dan foydalansa, joriy vaqtga yaqin sanalar uchun farq noto'g'ri hisoblanishi mumkin. Server ma'lumotlari uchun doim formatter.timeZone = TimeZone(secondsFromGMT: 0) o'rnatish tavsiya etiladi.

Qisqa intervallar uchun birlikni noto'g'ri tanlash — RelativeDateTimeFormatter farqni eng katta birlikka yaxlitlaydi. 25 soat uchun natija “1 kun oldin” bo'ladi, bu foydalanuvchini chalg'itishi mumkin. Agar yuqori aniqlik kerak bo'lsa (masalan, ortga hisoblagichlar uchun), RelativeDateTimeFormatter o'rniga DateComponentsFormatter dan foydalaning — u bir vaqtning o'zida bir nechta birlikni ko'rsatishga imkon beradi.

Manfiy TimeInterval ni tekshirmaslik — agar kelajakdagi sana o'tmish sifatida uzatilsa (string(fromTimeInterval:) da manfiy qiymat), formatter noto'g'ri satr qaytarishi mumkin. Formatterga uzatishdan oldin doim interval belgisini tekshiring, ayniqsa vaqt mintaqasi hisobni buzishi mumkin bo'lgan server ma'lumotlari bilan ishlashda.

Hacker News (2024) ma'lumotlariga ko'ra, RelativeDateTimeFormatter ning eng ko'p muhokama qilinadigan muammolaridan biri ingliz tili uchun “kecha” va “bugun” ning o'rnatilgan qo'llab-quvvatlanmasligidir. “kecha” o'rniga formatter 90000 soniya farq uchun “1 kun oldin” qaytaradi. Rus tili uchun bunday muammo yo'q — “1 kun oldin” tabiiy eshitiladi, lekin ingliz UI uchun “yesterday” afzalroq. Bu funksional qo'llab-quvvatlanmaydi va Calendar.isDateInToday/Yesterday orqali qo'lda tekshirishni talab qiladi.

Ko'p so'raladigan savollar

RelativeDateTimeFormatter nima?

RelativeDateTimeFormatter — sanalarni nisbiy formatda ko'rsatish uchun Foundation sinfi: “5 daqiqa oldin”, “2 kundan keyin”. iOS 13 va macOS 10.15 dan boshlab mavjud.

RelativeDateTimeFormatter birliklarni qanday tanlaydi?

Eng katta nolga teng bo'lmagan birlik tamoyili bo'yicha — soniyalar, daqiqalar, soatlar, kunlar, haftalar, oylar yoki yillar. Masalan, 3720 soniya farq (1 soat 2 daqiqa) uchun “soat” birligi tanlanadi, “daqiqalar” emas.

Natija tilini qanday o'zgartirish mumkin?

locale xossasini kerakli Locale namunasiga o'rnating. Odatiy holda Locale.current ishlatiladi. Misol: formatter.locale = Locale(identifier: "de_DE") nemis tili uchun.

.numeric va .abbreviated o'rtasidagi farq nima?

.numeric — to'liq shakl (“3 kun oldin”), .abbreviated — qisqartirilgan (“3 kun oldin”). Tanlov kontekstga bog'liq: numeric asosiy UI uchun, abbreviated ixcham elementlar uchun.

“0 soniya oldin” o'rniga “hozirgina” ni qanday ko'rsatish mumkin?

Qo'lda tekshirish qo'shing 5–10 soniyadan kam interval uchun. RelativeDateTimeFormatter “hozirgina” ni qo'llab-quvvatlamaydi — kichik intervallar uchun “0 soniya oldin” qaytaradi. Chegarali shartli mantiqdan foydalaning.

Xulosalar

  • RelativeDateTimeFormatter — iOS 13+ da nisbiy sanalarni ko'rsatish uchun qulay sinf
  • Avtomatik lokalizatsiya — ICU orqali barcha qo'llab-quvvatlanadigan tillar uchun to'g'ri tuslash
  • Uch uslub — .numeric (standart), .abbreviated (ixcham), .full (so'z bilan)
  • Birlik tanlash — eng katta nolga teng bo'lmagan qiymat tamoyili bo'yicha avtomatik
  • TimeZone sozlash — server sanalari bilan ishlashda izchillik uchun majburiy
  • “Hozirgina” chegarasi — o'rnatilgan qo'llab-quvvatlanmaydi; intervalni qo'lda tekshirish talab qilinadi
  • “Kecha” ni qo'llab-quvvatlamaydi — ingliz tili uchun formatter yesterday shaklidan foydalanmaydi

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing