RelativeDateTimeFormatter: mahiyyəti, nisbi tarixlər və Swift

Müəllif: IT Sectr Dərc olunub: 2026-07-13 Oxuma vaxtı: 10 dəq

RelativeDateTimeFormatter — iOS və macOS-da Foundation sinfi olub, mütləq tarixləri insanlar üçün oxunaqlı nisbi ifadələrə çevirir: “5 dəqiqə əvvəl”, “dünən”, “3 gün sonra”. Apple Developer Documentation, 2024 məlumatlarına görə, RelativeDateTimeFormatter avtomatik olaraq uyğun vahidi (saniyələr, dəqiqələr, saatlar, günlər) seçir və nəticəni cihazın cari lokalının dilində lokallaşdırır. Calendar vasitəsilə tarixlər arasındakı fərqi əl ilə hesablamaqdan fərqli olaraq, bu sinif hər dilin linqvistik xüsusiyyətlərini nəzərə alır: bəzi dillərdə saylar hallanır, bəzilərində isə “dünən” sözü üçün xüsusi forma istifadə olunur. Sinif iOS 13 və macOS 10.15-dən etibarən mövcuddur.

Əsas məqamlar

  • RelativeDateTimeFormatter — iOS və macOS-da nisbi tarixləri göstərmək üçün sinif (iOS 13+)
  • Lokallaşdırılmış nəticə — cari lokalın dilində ifadələri avtomatik seçir
  • Üç kontekst növü — past (əvvəl), future (sonra), present (indi) müxtəlif ifadələrlə
  • Vahidin avtomatik seçimi — saniyələr, dəqiqələr, saatlar, günlər, həftələr, aylar, illər
  • Stilin konfiqurasiyası — numeric (3 gün sonra) və ya abbreviated (3 gün sonra)

RelativeDateTimeFormatter nədir?

RelativeDateTimeFormatter — Foundation-da Formatter-in alt sinfi olub, Date-i (və ya saniyələrdəki fərqi) qəbul edir və nisbi zamanla lokallaşdırılmış sətir qaytarır. Məsələn, cari vaxtdan 5 dəqiqə əvvəlki tarix üçün ru_RU üçün “5 dəqiqə əvvəl” və ya en_US üçün “5 minutes ago” qaytaracaq. Sinif üç zaman kontekstini dəstəkləyir: keçmiş (past), gələcək (future) və indiki (present).

RelativeDateTimeFormatter-in daxili məntiqi tarixlər arasındakı fərqi hesablamaq və düzgün qrammatik formanı seçmək üçün Calendar və Locale-dən istifadə edir. Azərbaycan dili üçün sinif sayları düzgün hallandırır: “1 dəqiqə əvvəl”, “2 dəqiqə əvvəl”, “5 dəqiqə əvvəl”. İngilis dili üçün isə “minute ago” və “minutes ago” arasında seçim edir. Bu funksionallıq ICU (International Components for Unicode) məlumatlarına əsaslanır və tərtibatçıdan əlavə konfiqurasiya tələb etmir.

Apple WWDC 2019 məlumatlarına görə, RelativeDateTimeFormatter lokallaşdırmanı sadələşdirmək üçün framework-un bir hissəsi oldu — onun yaranmasından əvvəl tərtibatçılar tarix fərqini əl ilə hesablamalı və String.localizedStringWithFormat vasitəsilə lokallaşdırılmış sətirləri yerləşdirməli idilər. Bu, hallanmada (xüsusilə slavyan və ərəb dilləri üçün) səhvlərə və ölçü vahidlərinin səhv seçilməsinə gətirib çıxarırdı.

RelativeDateTimeFormatter “5 dəqiqə əvvəl” necə göstərir?

İş alqoritmi RelativeDateTimeFormatter üç addımdan ibarətdir: verilən tarixlə cari an arasındakı fərqin hesablanması, uyğun vahidin (sıfır verməyən ən böyüyün) seçilməsi və lokal nəzərə alınmaqla formatlaşdırma. Məsələn, 3720 saniyəlik fərq üçün (1 saat 2 dəqiqə) “saat” vahidi seçiləcək və nəticə “1 saat əvvəl” olacaq, “62 dəqiqə əvvəl” yox.

Vahidlər “ən böyük sıfırdan fərqli” prinsipi ilə seçilir: fərq 86400 saniyədən (1 gün) böyükdürsə, günlər istifadə olunur; 604800-dən (1 həftə) böyükdürsə — həftələr və s. Bu alqoritm nəticənin həmişə təbii oxunmasını təmin edir: “518400 saniyə əvvəl” əvəzinə istifadəçi “6 gün əvvəl” görür. Vahidlərin dəqiq sərhədlərini cari lokalın təqvimi müəyyən edir.

Fərq diapazonuVahidru_RU üçün nümunə
0–59 saniyəSeconds30 saniyə əvvəl
1–59 dəqiqəMinutes5 dəqiqə əvvəl
1–23 saatHours3 saat əvvəl
1–6 günDays2 gün əvvəl
7–27 günWeeks1 həftə əvvəl
28 gün–11 ayMonths3 ay əvvəl
12+ ayYears1 il əvvəl

Formatlaşdırma konteksti ifadənin sonunu müəyyən edir. Keçmiş üçün: “əvvəl” (azərbaycan), “ago” (ingilis). Gələcək üçün: “3 gün sonra” (azərbaycan), “in 3 days” (ingilis). İndiki üçün: “indi” (azərbaycan), “now” (ingilis). Kontekst localizeString(fromTimeInterval:) metodu və ya birbaşa string(from: Date) vasitəsilə təyin edilir.

Vahidlərin və stillərin parametrləri

RelativeDateTimeFormatter nəticəyə nəzarət üçün bir neçə parametr təqdim edir: unitsStyle xassəsi formatlaşdırma stilini (numeric, abbreviated, full, spellOut) müəyyən edir, maximumUnitCount isə göstərilən vahidlərin sayını məhdudlaşdırır. Məsələn, maximumUnitCount = 1 ilə 1 saat 30 dəqiqəlik fərq “1 saat 30 dəqiqə əvvəl” əvəzinə “1 saat əvvəl” kimi göstəriləcək.

Formatlaşdırma stilləri

  • .numeric — tam ədədi dəyər: “3 gün əvvəl”, “2 həftə sonra”. Default olaraq UI üçün tövsiyə olunur
  • .abbreviated — qısaldılmış forma: “3 gün əvvəl”, “2 həftə sonra”. Cədvəl və siyahılarda kompakt göstərmək üçün
  • .full — rəqəmsiz sözlü forma: “üç gün əvvəl”. Accessibility və səs interfeysləri üçün
  • .spellOut — alternativ yazılışla hərf forması: “three days ago”. Nadir hallarda, əsasən xüsusi istifadə üçün

Vahid məhdudiyyəti: default olaraq RelativeDateTimeFormatter yalnız bir (ən böyük) vahidi göstərir. maximumUnitCount = 2 təyin edilməsi daha dəqiq təsvir üçün növbəti vahidi də əlavə edir: “1 saat 30 dəqiqə əvvəl”. Lakin bu, qısa mesajlar (push, bildirişlər) üçün sətri həddindən artıq uzun edə bilər. UI üçün maximumUnitCount = 1-in saxlanması tövsiyə olunur.

swift
import Foundation

let formatter = RelativeDateTimeFormatter()

// Stilleri konfiqurasiya edin
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1

// Müxtəlif tarixlərlə nümunələr
let fiveMinAgo = Date().addingTimeInterval(-300)
print("5 dəq əvvəl: \(formatter.localizedString(for: fiveMinAgo, relativeTo: Date()))")

let twoDaysLater = Date().addingTimeInterval(172800)
print("2 gün sonra: \(formatter.localizedString(for: twoDaysLater, relativeTo: Date()))")

// Qısaldılmış stil
formatter.unitsStyle = .abbreviated
let oneWeekAgo = Date().addingTimeInterval(-604800)
print("Qısaldılmış: \(formatter.localizedString(for: oneWeekAgo, relativeTo: Date()))")

// Tam stil (sözlə)
formatter.unitsStyle = .full
let threeHours = Date().addingTimeInterval(10800)
print("Tam: \(formatter.localizedString(for: threeHours, relativeTo: Date()))")

Müxtəlif kontekstlər üçün stil seçimi: xəbər lentləri üçün maximumUnitCount = 1 ilə .numeric istifadə edin — bu, Twitter, Instagram və Facebook üçün standartdır. Accessibility (VoiceOver) üçün .full istifadə edin — sözlə yazılmış rəqəmlər daha təbii oxunur. Kompakt elementlər (bildiriş küncü, status sətri) üçün yerə qənaət etmək üçün .abbreviated istifadə edin.

Swift-də RelativeDateTimeFormatter: nümunələr

Əsas istifadə RelativeDateTimeFormatter nümunə yaratmaq, xassələri konfiqurasiya etmək və formatlaşdırma metodlarından birini çağırmaqdan ibarətdir. Əsas metodlar: localizedString(for:relativeTo:) — bir cüt tarix üçün, localizedString(fromTimeInterval:) — saniyələrdəki fərq üçün və string(for:) — avtomatik kontekstlə (keçmiş/gələcək) Date üçün.

swift
import Foundation

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

// Sosial şəbəkə UI nümunələri
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)")
}

// Gələcək tarixlər
let reminderFormatter = RelativeDateTimeFormatter()
reminderFormatter.unitsStyle = .abbreviated
let inOneHour = Date().addingTimeInterval(3600)
let reminderText = reminderFormatter.localizedString(
    for: inOneHour,
    relativeTo: Date()
)
print("Xatırlatma: \(reminderText)")

“İndicə” ssenarisinin işlənməsi — RelativeDateTimeFormatter çox kiçik intervallar üçün “indicə” ifadəsinə daxili dəstəyə malik deyil. 5 saniyədən az fərq üçün “0 saniyə əvvəl” qaytaracaq, bu da UI-da gözəl görünmür. Formatter çağırışını şərti məntiqlə bükmək tövsiyə olunur: fərq müəyyən edilmiş həddən (məs. 5 saniyə) azdırsa — “indicə” əl ilə göstərin, əks halda tarixi formatterə ötürün.

swift
import Foundation

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

    // “İndicə” həddi
    if interval < 5 {
        return "just now"
    }

    // “Bu gün” həddi
    if interval < 60 {
        return "just now"
    }

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

    // “əvvəl” şəkilçisi olmadan göstərmək
    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:) metodu saniyələrdəki fərqi qəbul edir və konteksti avtomatik müəyyən edir (müsbət dəyər — gələcək, mənfi — keçmiş). Bu, fərq artıq məlum olduqda əlverişlidir (məs. serverdən unix timestamp kimi alınmışdır). Bu halda Date yaratmaq lazım deyil — fərq birbaşa ötürülür.

Nisbi tarixlərin lokallaşdırılması

RelativeDateTimeFormatter nəticəni Locale.current əsasında avtomatik lokallaşdırır. Formatlaşdırma dilini dəyişmək üçün locale xassəsini təyin edin — DateFormatter-dən fərqli olaraq, RelativeDateTimeFormatter üçün locale sabit deyil və hər çağırış üçün dəyişdirilə bilər. Bu, nisbi tarixləri interfeys dilindən fərqli dildə (məs. orijinal dildəki məzmun) göstərməyə imkan verir.

Nisbi tarixlərin lokallaşdırılmasının mürəkkəbliyi müxtəlif dillərin qrammatik xüsusiyyətlərindədir. Rus dili müxtəlif say formaları tələb edir: “1 dəqiqə”, “2 dəqiqə”, “5 dəqiqə”. Ərəb dili — 3-dən 10-a qədər ədədlər üçün cəm formasından və 11+ üçün xüsusi formalardan istifadə edir. Çin dilində isə heç bir hallanma yoxdur, bu da vəzifəni sadələşdirir. RelativeDateTimeFormatter bütün bu halları ICU qaydaları ilə əlavə kod olmadan əhatə edir.

swift
import Foundation

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

let targetDate = Date().addingTimeInterval(-7200) // 2 saat əvvəl

// Müxtəlif 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)")
}

// Rus dilinin hallanmasını yoxlayın
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)) dəq: \(formatter.localizedString(for: date, relativeTo: Date()))")
}

Vacib nüans: RelativeDateTimeFormatter .numeric parametrləri üçün fərq hesablayarkən TimeZone-u nəzərə almır — saniyələrdəki mütləq fərqdən istifadə edir. Lakin .full stil üçün (sözlə yazılmış rəqəmlərlə) və xüsusi hallar (dünən, bu gün) üçün TimeZone nəzərə alınır. Ardıcıllıq üçün həmişə TimeZone-u aydın şəkildə təyin edin, xüsusən də proqram server tarixləri ilə UTC-də işləyirsə.

Formatlaşdırma zamanı tipik səhvlər

Nisbi tarixlər hesablanarkən TimeZone-un nəzərə alınmaması — server tarixləri ilə işləyərkən geniş yayılmış səhvdir. Server Date-i UTC-də göndərir, RelativeDateTimeFormatter isə TimeZone.current istifadə edirsə, cari an yaxınlığındakı tarixlər üçün fərq səhv hesablana bilər. Server məlumatları üçün həmişə formatter.timeZone = TimeZone(secondsFromGMT: 0) təyin etmək tövsiyə olunur.

Qısa intervallar üçün vahidin səhv seçilməsi — RelativeDateTimeFormatter fərqi ən böyük vahidə yuvarlaqlaşdırır. 25 saat üçün nəticə “1 gün əvvəl” olacaq, bu da istifadəçini çaşdıra bilər. Yüksək dəqiqlik tələb olunarsa (məs. geri sayım taymerləri üçün), RelativeDateTimeFormatter əvəzinə DateComponentsFormatter istifadə edin — o, bir neçə vahidi eyni anda göstərməyə imkan verir.

Mənfi TimeInterval üçün yoxlamanın olmaması — gələcəkdəki tarix keçmiş kimi ötürülürsə (string(fromTimeInterval:) də mənfi dəyər), formatter səhv sətir qaytara bilər. Formatterə ötürməzdən əvvəl həmişə intervalın işarəsini yoxlayın, xüsusən də saat qurşağının hesablamanı təhrif edə biləcəyi server məlumatları ilə işləyərkən.

Hacker News (2024) məlumatlarına görə, RelativeDateTimeFormatter-in ən çox müzakirə olunan problemlərindən biri ingilis dili üçün “dünən” və “bu gün”-in daxili dəstəyinin olmamasıdır. “dünən” əvəzinə formatter 90000 saniyəlik fərq üçün “1 gün əvvəl” qaytaracaq. Rus dili üçün belə problem yoxdur — “1 gün əvvəl” təbii səslənir, lakin ingilis UI üçün “yesterday” daha üstündür. Bu funksionallıq dəstəklənmir və Calendar.isDateInToday/Yesterday vasitəsilə əl ilə yoxlama tələb edir.

Tez-tez verilən suallar

RelativeDateTimeFormatter nədir?

RelativeDateTimeFormatter — tarixləri nisbi formatda göstərmək üçün Foundation sinfi: “5 dəqiqə əvvəl”, “2 gün sonra”. iOS 13 və macOS 10.15-dən etibarən mövcuddur.

RelativeDateTimeFormatter vahidləri necə seçir?

Ən böyük sıfırdan fərqli vahid prinsipi ilə — saniyələr, dəqiqələr, saatlar, günlər, həftələr, aylar və ya illər. Məsələn, 3720 saniyəlik fərq (1 saat 2 dəqiqə) üçün “saat” vahidi seçiləcək, “dəqiqələr” yox.

Nəticənin dilini necə dəyişmək olar?

locale xassəsini istədiyiniz Locale nümunəsinə təyin edin. Default olaraq Locale.current istifadə olunur. Nümunə: formatter.locale = Locale(identifier: "de_DE") alman dili üçün.

.numeric ilə .abbreviated arasında nə fərq var?

.numeric — tam forma (“3 gün əvvəl”), .abbreviated — qısaldılmış (“3 gün əvvəl”). Seçim kontekstdən asılıdır: numeric əsas UI üçün, abbreviated kompakt elementlər üçün.

“0 saniyə əvvəl” əvəzinə “indicə” necə göstərmək olar?

Əl ilə yoxlama əlavə edin 5–10 saniyədən az interval üçün. RelativeDateTimeFormatter “indicə”-ni dəstəkləmir — kiçik intervallar üçün “0 saniyə əvvəl” qaytarır. Həddi olan şərti məntiqdən istifadə edin.

Nəticələr

  • RelativeDateTimeFormatter — iOS 13+ üçün nisbi tarixləri göstərmək üçün rahat sinif
  • Avtomatik lokallaşdırma — ICU vasitəsilə bütün dəstəklənən dillər üçün düzgün hallanma
  • Üç stil — .numeric (standart), .abbreviated (kompakt), .full (sözlə)
  • Vahid seçimi — ən böyük sıfırdan fərqli dəyər prinsipi ilə avtomatik
  • TimeZone konfiqurasiyası — server tarixləri ilə işləyərkən ardıcıllıq üçün mütləqdir
  • “İndicə” həddi — daxili dəstəklənmir; intervalın əl ilə yoxlanması tələb olunur
  • “Dünən” dəstəyi yoxdur — ingilis dili üçün formatter yesterday formasından istifadə etmir

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun