RelativeDateTimeFormatter: ang diwa, mga relative na petsa at Swift

May-akda: IT Sectr Nai-publish: 2026-07-13 Oras ng pagbabasa: 10 min

Ang RelativeDateTimeFormatter ay isang klase ng Foundation sa iOS at macOS na nagko-convert ng mga absolute na petsa sa madaling basahin na mga relative na pahayag: “5 minutong nakalipas”, “kahapon”, “sa loob ng 3 araw”. Ayon sa Apple Developer Documentation, 2024, ang RelativeDateTimeFormatter ay awtomatikong pumipili ng angkop na unit (segundo, minuto, oras, araw) at naglo-localize ng output sa wika ng kasalukuyang locale ng device. Hindi tulad ng manu-manong pag-compute ng pagkakaiba sa pagitan ng mga petsa sa pamamagitan ng Calendar, isinasaalang-alang ng klase na ito ang mga lingguwistikong katangian ng bawat wika: para sa ilang wika, ang mga numeral ay binabanghay, para sa iba — ginagamit ang espesyal na anyo para sa salitang “kahapon”. Available ang klase mula sa iOS 13 at macOS 10.15.

Ang pangunahing

  • RelativeDateTimeFormatter — klase para sa pagpapakita ng mga relative na petsa sa iOS at macOS (iOS 13+)
  • Naka-localize na output — awtomatikong pumipili ng mga pahayag sa wika ng kasalukuyang locale
  • Tatlong uri ng konteksto — past (nakalipas), future (sa loob), present (ngayon) na may iba't ibang pahayag
  • Awtomatikong pagpili ng unit — segundo, minuto, oras, araw, linggo, buwan, taon
  • Pag-configure ng estilo — numeric (sa loob ng 3 araw) o abbreviated (sa loob ng 3 araw)

Ano ang RelativeDateTimeFormatter?

RelativeDateTimeFormatter ay isang subklase ng Formatter sa Foundation na tumatanggap ng Date (o ang pagkakaiba sa segundo) at nagbabalik ng naka-localize na string na may relative na oras. Halimbawa, para sa petsang 5 minuto mas maaga kaysa sa kasalukuyan, babalik ito ng “5 minutong nakalipas” para sa ru_RU o “5 minutes ago” para sa en_US. Sinusuportahan ng klase ang tatlong temporal na konteksto: nakaraan (past), hinaharap (future) at kasalukuyan (present).

Ang panloob na lohika ng RelativeDateTimeFormatter ay gumagamit ng Calendar at Locale upang kalkulahin ang pagkakaiba sa pagitan ng mga petsa at piliin ang tamang gramatikal na anyo. Para sa Filipino, tamang binabanghay ng klase ang mga numeral: “1 minutong nakalipas”, “2 minutong nakalipas”, “5 minutong nakalipas”. Para sa Ingles — pumipili sa pagitan ng “minute ago” at “minutes ago”. Ang functionality na ito ay batay sa data ng ICU (International Components for Unicode) at hindi nangangailangan ng karagdagang configuration mula sa developer.

Ayon sa Apple WWDC 2019, ang RelativeDateTimeFormatter ay naging bahagi ng framework upang pasimplehin ang lokalisasyon — bago ang paglitaw nito, napilitan ang mga developer na manu-manong kalkulahin ang pagkakaiba ng mga petsa at magsingit ng mga naka-localize na string sa pamamagitan ng String.localizedStringWithFormat. Ito ay nagdulot ng mga error sa pagbabanghay (lalo na para sa mga Slavic at Arabic na wika) at hindi tamang pagpili ng mga yunit ng sukat.

Paano ipinapakita ng RelativeDateTimeFormatter ang “5 minutong nakalipas”?

Ang algorithm ng pagpapatakbo ng RelativeDateTimeFormatter ay binubuo ng tatlong hakbang: pagkalkula ng pagkakaiba sa pagitan ng ibinigay na petsa at kasalukuyang sandali, pagpili ng angkop na unit (ang pinakamalaki na hindi nagbibigay ng zero) at pag-format na isinasaalang-alang ang locale. Halimbawa, para sa pagkakaibang 3720 segundo (1 oras 2 minuto) pipiliin ang unit na “oras”, at ang resulta ay “1 oras na nakalipas”, hindi “62 minutong nakalipas”.

Ang mga unit ay pinipili ayon sa prinsipyong “pinakamalaking hindi zero”: kung ang pagkakaiba ay mas malaki sa 86400 segundo (1 araw), ginagamit ang mga araw; kung mas malaki sa 604800 (1 linggo) — mga linggo, at iba pa. Ginagarantiyahan ng algorithm na ito na ang resulta ay palaging natural na nababasa: sa halip na “518400 segundong nakalipas”, nakikita ng user ang “6 araw na nakalipas”. Ang mga eksaktong hangganan ng mga unit ay tinutukoy ng kalendaryo ng kasalukuyang locale.

Saklaw ng pagkakaibaUnitHalimbawa para sa ru_RU
0–59 segundoSeconds30 segundong nakalipas
1–59 minutoMinutes5 minutong nakalipas
1–23 orasHours3 oras na nakalipas
1–6 arawDays2 araw na nakalipas
7–27 arawWeeks1 linggong nakalipas
28 araw–11 buwanMonths3 buwang nakalipas
12+ buwanYears1 taong nakalipas

Ang konteksto ng pag-format ay tumutukoy sa dulo ng parirala. Para sa nakaraan: “nakalipas” (Filipino), “ago” (Ingles). Para sa hinaharap: “sa loob ng 3 araw” (Filipino), “in 3 days” (Ingles). Para sa kasalukuyan: “ngayon” (Filipino), “now” (Ingles). Ang konteksto ay itinatakda sa pamamagitan ng paraang localizeString(fromTimeInterval:) o direkta sa pamamagitan ng string(from: Date).

Mga setting ng unit at estilo

RelativeDateTimeFormatter ay nagbibigay ng ilang mga setting upang kontrolin ang output: ang property na unitsStyle ay tumutukoy sa estilo ng pag-format (numeric, abbreviated, full, spellOut), at nililimitahan ng maximumUnitCount ang bilang ng mga ipinapakitang unit. Halimbawa, sa maximumUnitCount = 1, ang pagkakaibang 1 oras 30 minuto ay ipapakita bilang “1 oras na nakalipas” sa halip na “1 oras 30 minutong nakalipas”.

Mga estilo ng pag-format

  • .numeric — kumpletong numerikong halaga: “3 araw na nakalipas”, “sa loob ng 2 linggo”. Inirerekomenda para sa UI bilang default
  • .abbreviated — pinaikling anyo: “3 araw na nakalipas”, “sa loob ng 2 linggo”. Para sa compact na pagpapakita sa mga talahanayan at listahan
  • .full — anyong salita nang walang numero: “tatlong araw na nakalipas”. Para sa Accessibility at mga voice interface
  • .spellOut — anyong titik na may alternatibong pagbaybay: “three days ago”. Bihirang ginagamit, pangunahin para sa mga espesyal na layunin

Limitasyon ng unit: bilang default, ang RelativeDateTimeFormatter ay nagpapakita lamang ng isang (pinakamalaking) unit. Ang pagtatakda ng maximumUnitCount = 2 ay nag-a-activate ng susunod na unit para sa mas tumpak na paglalarawan: “1 oras 30 minutong nakalipas”. Gayunpaman, maaari nitong gawing masyadong mahaba ang string para sa mga maikling mensahe (push, mga abiso). Para sa UI, inirerekomendang panatilihin ang maximumUnitCount = 1.

swift
import Foundation

let formatter = RelativeDateTimeFormatter()

// I-configure ang mga estilo
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1

// Mga halimbawang may iba't ibang petsa
let fiveMinAgo = Date().addingTimeInterval(-300)
print("5 min ang nakalipas: \(formatter.localizedString(for: fiveMinAgo, relativeTo: Date()))")

let twoDaysLater = Date().addingTimeInterval(172800)
print("sa loob ng 2 araw: \(formatter.localizedString(for: twoDaysLater, relativeTo: Date()))")

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

// Buong estilo (nasasalita)
formatter.unitsStyle = .full
let threeHours = Date().addingTimeInterval(10800)
print("Buong: \(formatter.localizedString(for: threeHours, relativeTo: Date()))")

Pagpili ng estilo para sa iba't ibang konteksto: para sa feed ng balita gumamit ng .numeric na may maximumUnitCount = 1 — ito ang pamantayan para sa Twitter, Instagram at Facebook. Para sa Accessibility (VoiceOver) gumamit ng .full — mas natural na nababasa ang mga numero sa salita. Para sa mga compact na elemento (sulok ng abiso, status bar) gumamit ng .abbreviated upang makatipid ng espasyo.

RelativeDateTimeFormatter sa Swift: mga halimbawa

Pangunahing paggamit ng RelativeDateTimeFormatter ay bumababa sa paggawa ng instance, pag-configure ng mga property at pagtawag sa isa sa mga paraan ng pag-format. Ang mga pangunahing paraan: localizedString(for:relativeTo:) — para sa isang pares ng mga petsa, localizedString(fromTimeInterval:) — para sa pagkakaiba sa segundo, at string(for:) — para sa Date na may awtomatikong konteksto (nakaraan/hinaharap).

swift
import Foundation

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

// Mga halimbawa ng UI ng social network
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)")
}

// Mga petsa sa hinaharap
let reminderFormatter = RelativeDateTimeFormatter()
reminderFormatter.unitsStyle = .abbreviated
let inOneHour = Date().addingTimeInterval(3600)
let reminderText = reminderFormatter.localizedString(
    for: inOneHour,
    relativeTo: Date()
)
print("Paalala: \(reminderText)")

Paghawak sa sitwasyong “kakabigay lang” — ang RelativeDateTimeFormatter ay walang built-in na suporta para sa pariralang “kakabigay lang” para sa napakaliit na mga interval. Para sa pagkakaibang mas mababa sa 5 segundo, babalik ito ng “0 segundong nakalipas”, na hindi maganda sa UI. Inirerekomendang balutin ang tawag sa formatter sa conditional na lohika: kung ang pagkakaiba ay mas mababa sa itinakdang hangganan (hal. 5 segundo) — ipakita ang “kakabigay lang” nang manu-mano, kung hindi, ibigay ang petsa sa formatter.

swift
import Foundation

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

    // Hangganan ng “kakabigay lang”
    if interval < 5 {
        return "just now"
    }

    // Hangganan ng “ngayon”
    if interval < 60 {
        return "just now"
    }

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

    // Ipakita nang walang suffix na “nakalipas”
    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)))

Ang paraang string(fromTimeInterval:) ay tumatanggap ng pagkakaiba sa segundo at awtomatikong tinutukoy ang konteksto (positibong halaga — hinaharap, negatibo — nakaraan). Maginhawa ito kapag ang pagkakaiba ay alam na (hal. natanggap mula sa server bilang unix timestamp). Sa kasong ito, hindi na kailangang gumawa ng Date — ang pagkakaiba ay direktang ibinibigay.

Lokalisasyon ng mga relative na petsa

RelativeDateTimeFormatter ay awtomatikong naglo-localize ng output batay sa Locale.current. Upang baguhin ang wika ng pag-format, itakda ang property na locale — hindi tulad ng DateFormatter, para sa RelativeDateTimeFormatter ang locale ay hindi fixed at maaaring baguhin para sa bawat tawag. Ito ay nagpapahintulot na ipakita ang mga relative na petsa sa wikang naiiba sa wika ng interface (hal. nilalaman sa orihinal na wika).

Ang pagiging kumplikado ng lokalisasyon ng mga relative na petsa ay nasa mga katangiang gramatikal ng iba't ibang wika. Ang wikang Ruso ay nangangailangan ng iba't ibang anyo ng mga numeral: “1 minuto”, “2 minuto”, “5 minuto”. Ang Arabic — ay gumagamit ng plural na anyo para sa mga numerong 3 hanggang 10 at mga espesyal na anyo para sa 11+. Ang Chinese — ay walang banghay, na nagpapasimple sa gawain. Sinasaklaw ng RelativeDateTimeFormatter ang lahat ng mga kasong ito sa pamamagitan ng mga panuntunan ng ICU, nang walang karagdagang code.

swift
import Foundation

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

let targetDate = Date().addingTimeInterval(-7200) // 2 oras na nakalipas

// Iba't ibang locale
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)")
}

// Suriin ang pagbabanghay ng Ruso
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)) min: \(formatter.localizedString(for: date, relativeTo: Date()))")
}

Mahalagang detalye: ang RelativeDateTimeFormatter ay nag-iiwan ng TimeZone kapag kinakalkula ang pagkakaiba para sa mga setting ng .numeric — gumagamit ito ng absolute na pagkakaiba sa segundo. Gayunpaman, para sa estilo ng .full (na may mga numerong nasa salita) at mga espesyal na kaso (kahapon, ngayon), isinasaalang-alang ang TimeZone. Palaging itakda nang tahasan ang TimeZone para sa consistency, lalo na kung gumagana ang app sa mga petsa ng server sa UTC.

Mga karaniwang error sa pag-format

Pag-iiwan sa TimeZone kapag kinakalkula ang mga relative na petsa — karaniwang error sa pagtatrabaho sa mga petsa ng server. Kung ang server ay nagpapadala ng Date sa UTC, at ang RelativeDateTimeFormatter ay gumagamit ng TimeZone.current, ang pagkakaiba ay maaaring kalkulahin nang hindi tama para sa mga petsang malapit sa kasalukuyang sandali. Inirerekomendang palaging itakda ang formatter.timeZone = TimeZone(secondsFromGMT: 0) para sa data ng server.

Maling pagpili ng unit para sa mga maikling interval — ang RelativeDateTimeFormatter ay nag-round ng pagkakaiba sa pinakamalaking unit. Para sa 25 oras, ang resulta ay “1 araw na nakalipas”, na maaaring magpaligaw sa user. Kung kinakailangan ang mataas na katumpakan (hal. para sa mga countdown timer), gamitin ang DateComponentsFormatter sa halip na RelativeDateTimeFormatter — pinapayagan nito ang pagpapakita ng ilang unit nang sabay-sabay.

Kawalan ng pagsusuri sa negatibong TimeInterval — kung ang petsa sa hinaharap ay ibibigay bilang nakaraan (negatibong halaga sa string(fromTimeInterval:)), maaaring magbalik ang formatter ng maling string. Palaging suriin ang tanda ng interval bago ibigay sa formatter, lalo na kapag nagtatrabaho sa data ng server, kung saan maaaring i-distort ng time zone ang pagkalkula.

Ayon sa Hacker News (2024), isa sa mga pinakapinag-uusapang problema ng RelativeDateTimeFormatter ay ang kawalan ng built-in na suporta para sa “kahapon” at “ngayon” sa wikang Ingles. Sa halip na “kahapon”, ang formatter para sa pagkakaibang 90000 segundo ay magbabalik ng “1 araw na nakalipas”. Para sa wikang Ruso, walang ganoong problema — “1 araw na nakalipas” ay natural, ngunit para sa Ingles na UI, mas kanais-nais ang “yesterday”. Ang functionality na ito ay hindi sinusuportahan at nangangailangan ng manu-manong pagsusuri sa pamamagitan ng Calendar.isDateInToday/Yesterday.

Mga madalas itanong

Ano ang RelativeDateTimeFormatter?

RelativeDateTimeFormatter — klase ng Foundation para sa pagpapakita ng mga petsa sa relative na format: “5 minutong nakalipas”, “sa loob ng 2 araw”. Available mula sa iOS 13 at macOS 10.15.

Paano pinipili ng RelativeDateTimeFormatter ang mga unit?

Ayon sa prinsipyong pinakamalaking hindi zero na unit — segundo, minuto, oras, araw, linggo, buwan o taon. Halimbawa, para sa pagkakaibang 3720 segundo (1 oras 2 minuto) pipiliin ang unit na “oras”, hindi “minuto”.

Paano baguhin ang wika ng output?

Itakda ang property na locale sa nais na instance ng Locale. Bilang default, ginagamit ang Locale.current. Halimbawa: formatter.locale = Locale(identifier: "de_DE") para sa wikang Aleman.

Ano ang pagkakaiba sa pagitan ng .numeric at .abbreviated?

.numeric — kumpletong anyo (“3 araw na nakalipas”), .abbreviated — pinaikli (“3 araw na nakalipas”). Ang pagpili ay nakasalalay sa konteksto: numeric para sa pangunahing UI, abbreviated para sa mga compact na elemento.

Paano ipakita ang “kakabigay lang” sa halip na “0 segundong nakalipas”?

Magdagdag ng manu-manong pagsusuri para sa interval na mas mababa sa 5–10 segundo. Hindi sinusuportahan ng RelativeDateTimeFormatter ang “kakabigay lang” — para sa mga maliliit na interval nagbabalik ito ng “0 segundong nakalipas”. Gumamit ng conditional na lohika na may hangganan.

Buod

  • RelativeDateTimeFormatter — maginhawang klase para sa pagpapakita ng mga relative na petsa sa iOS 13+
  • Awtomatikong lokalisasyon — tamang pagbabanghay para sa lahat ng sinusuportahang wika sa pamamagitan ng ICU
  • Tatlong estilo — .numeric (pamantayan), .abbreviated (compact), .full (nasasalita)
  • Pagpili ng unit — awtomatiko ayon sa prinsipyong pinakamalaking hindi zero na halaga
  • Configuration ng TimeZone — kinakailangan para sa consistency kapag nagtatrabaho sa mga petsa ng server
  • Hangganan ng “kakabigay lang” — hindi sinusuportahan nang built-in; nangangailangan ng manu-manong pagsusuri ng interval
  • Walang suporta sa “kahapon” — para sa wikang Ingles, hindi ginagamit ng formatter ang anyong yesterday

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din