RelativeDateTimeFormatter: de essentie, relatieve datums en Swift

Auteur: IT Sectr Gepubliceerd: 2026-07-13 Leestijd: 10 min

RelativeDateTimeFormatter is een Foundation-klasse in iOS en macOS die absolute datums omzet in leesbare relatieve formuleringen: „5 minuten geleden“, „gisteren“, „over 3 dagen“. Volgens Apple Developer Documentation, 2024 selecteert RelativeDateTimeFormatter automatisch de geschikte eenheid (seconden, minuten, uren, dagen) en lokaliseert de uitvoer in de taal van de huidige locale van het apparaat. In tegenstelling tot het handmatig berekenen van het verschil tussen datums via Calendar, houdt deze klasse rekening met de taalkundige kenmerken van elke taal: voor sommige talen worden telwoorden verbogen, voor andere wordt een speciale vorm gebruikt voor het woord „gisteren“. De klasse is beschikbaar vanaf iOS 13 en macOS 10.15.

Het belangrijkste

  • RelativeDateTimeFormatter — klasse voor het weergeven van relatieve datums in iOS en macOS (iOS 13+)
  • Gelokaliseerde uitvoer — selecteert automatisch formuleringen in de taal van de huidige locale
  • Drie soorten context — past (geleden), future (over), present (nu) met verschillende formuleringen
  • Automatische eenheidsselectie — seconden, minuten, uren, dagen, weken, maanden, jaren
  • Stijlconfiguratie — numeric (over 3 dagen) of abbreviated (over 3 dagen)

Wat is RelativeDateTimeFormatter?

RelativeDateTimeFormatter is een subklasse van Formatter in Foundation die Date (of het verschil in seconden) accepteert en een gelokaliseerde tekenreeks met relatieve tijd retourneert. Voor een datum 5 minuten eerder dan de huidige retourneert het bijvoorbeeld „5 minuten geleden“ voor ru_RU of „5 minutes ago“ voor en_US. De klasse ondersteunt drie tijdscontexten: verleden (past), toekomst (future) en heden (present).

De interne logica van RelativeDateTimeFormatter gebruikt Calendar en Locale om het verschil tussen datums te berekenen en de juiste grammaticale vorm te kiezen. Voor het Nederlands verbuigt de klasse telwoorden correct: „1 minuut geleden“, „2 minuten geleden“, „5 minuten geleden“. Voor het Engels kiest het tussen „minute ago“ en „minutes ago“. Deze functionaliteit is gebaseerd op ICU-gegevens (International Components for Unicode) en vereist geen extra configuratie van de ontwikkelaar.

Volgens Apple WWDC 2019 werd RelativeDateTimeFormatter onderdeel van het framework om lokalisatie te vereenvoudigen — vóór de komst ervan moesten ontwikkelaars het datumsverschil handmatig berekenen en gelokaliseerde tekenreeksen invoegen via String.localizedStringWithFormat. Dit leidde tot verbuigingsfouten (vooral voor Slavische en Arabische talen) en een onjuiste keuze van meeteenheden.

Hoe toont RelativeDateTimeFormatter „5 minuten geleden“?

Het werkingsalgoritme van RelativeDateTimeFormatter bestaat uit drie stappen: het berekenen van het verschil tussen de doorgegeven datum en het huidige moment, het kiezen van de geschikte eenheid (de grootste die geen nul oplevert) en het formatteren met inachtneming van de locale. Voor een verschil van 3720 seconden (1 uur 2 minuten) wordt bijvoorbeeld de eenheid „uur“ gekozen en het resultaat is „1 uur geleden“, niet „62 minuten geleden“.

Eenheden worden gekozen volgens het principe van de „grootste niet-nul“: als het verschil groter is dan 86400 seconden (1 dag), worden dagen gebruikt; als het groter is dan 604800 (1 week) — weken, enzovoort. Dit algoritme garandeert dat het resultaat altijd natuurlijk leest: in plaats van „518400 seconden geleden“ ziet de gebruiker „6 dagen geleden“. De exacte grenzen van de eenheden worden bepaald door de kalender van de huidige locale.

VerschilbereikEenheidVoorbeeld voor ru_RU
0–59 secondenSeconds30 seconden geleden
1–59 minutenMinutes5 minuten geleden
1–23 uurHours3 uur geleden
1–6 dagenDays2 dagen geleden
7–27 dagenWeeks1 week geleden
28 dagen–11 maandenMonths3 maanden geleden
12+ maandenYears1 jaar geleden

De formatteringscontext bepaalt het einde van de zin. Voor het verleden: „geleden“ (Nederlands), „ago“ (Engels). Voor de toekomst: „over 3 dagen“ (Nederlands), „in 3 days“ (Engels). Voor het heden: „nu“ (Nederlands), „now“ (Engels). De context wordt ingesteld via de methode localizeString(fromTimeInterval:) of rechtstreeks via string(from: Date).

Instellingen van eenheden en stijlen

RelativeDateTimeFormatter biedt verschillende instellingen om de uitvoer te beheren: de eigenschap unitsStyle bepaalt de opmaakstijl (numeric, abbreviated, full, spellOut), en maximumUnitCount beperkt het aantal weergegeven eenheden. Met maximumUnitCount = 1 wordt een verschil van 1 uur 30 minuten bijvoorbeeld weergegeven als „1 uur geleden“ in plaats van „1 uur 30 minuten geleden“.

Formatteringsstijlen

  • .numeric — de volledige numerieke waarde: „3 dagen geleden“, „over 2 weken“. Standaard aanbevolen voor UI
  • .abbreviated — de verkorte vorm: „3 dagen geleden“, „over 2 wk.“. Voor compacte weergave in tabellen en lijsten
  • .full — de woordvorm zonder cijfers: „drie dagen geleden“. Voor Accessibility en spraakinterfaces
  • .spellOut — de lettervorm met alternatieve spelling: „three days ago“. Wordt zelden gebruikt, voornamelijk voor speciale doeleinden

Eenheidsbeperking: standaard toont RelativeDateTimeFormatter slechts één (de grootste) eenheid. Door maximumUnitCount = 2 in te stellen, wordt de volgende eenheid geactiveerd voor een nauwkeurigere beschrijving: „1 uur 30 minuten geleden“. Dit kan de tekenreeks echter overmatig lang maken voor korte berichten (push, meldingen). Voor UI wordt aanbevolen maximumUnitCount = 1 te behouden.

swift
import Foundation

let formatter = RelativeDateTimeFormatter()

// Configureer stijlen
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1

// Voorbeelden met verschillende datums
let fiveMinAgo = Date().addingTimeInterval(-300)
print("5 min geleden: \(formatter.localizedString(for: fiveMinAgo, relativeTo: Date()))")

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

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

// Volledige stijl (uitgeschreven)
formatter.unitsStyle = .full
let threeHours = Date().addingTimeInterval(10800)
print("Volledig: \(formatter.localizedString(for: threeHours, relativeTo: Date()))")

Stijlkeuze voor verschillende contexten: gebruik voor de nieuwsfeed .numeric met maximumUnitCount = 1 — dit is de standaard voor Twitter, Instagram en Facebook. Gebruik voor Accessibility (VoiceOver) .full — uitgeschreven getallen lezen natuurlijker. Gebruik voor compacte elementen (meldingshoek, statusbalk) .abbreviated om ruimte te besparen.

RelativeDateTimeFormatter in Swift: voorbeelden

Basisgebruik van RelativeDateTimeFormatter komt neer op het maken van een instantie, het configureren van eigenschappen en het aanroepen van een van de formatteringsmethoden. De belangrijkste methoden: localizedString(for:relativeTo:) — voor een paar datums, localizedString(fromTimeInterval:) — voor het verschil in seconden, en string(for:) — voor Date met automatische context (verleden/toekomst).

swift
import Foundation

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

// UI-voorbeelden voor sociale netwerken
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)")
}

// Toekomstige datums
let reminderFormatter = RelativeDateTimeFormatter()
reminderFormatter.unitsStyle = .abbreviated
let inOneHour = Date().addingTimeInterval(3600)
let reminderText = reminderFormatter.localizedString(
    for: inOneHour,
    relativeTo: Date()
)
print("Herinnering: \(reminderText)")

Het scenario „zojuist“ verwerken — RelativeDateTimeFormatter heeft geen ingebouwde ondersteuning voor de uitdrukking „zojuist“ voor zeer kleine intervallen. Voor een verschil kleiner dan 5 seconden retourneert het „0 seconden geleden“, wat er niet mooi uitziet in de UI. Het wordt aanbevolen de formatter-aanroep in voorwaardelijke logica te wikkelen: als het verschil kleiner is dan de ingestelde drempel (bijvoorbeeld 5 seconden) — geef „zojuist“ handmatig weer, anders geef de datum door aan de formatter.

swift
import Foundation

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

    // Drempel „zojuist“
    if interval < 5 {
        return "just now"
    }

    // Drempel „vandaag“
    if interval < 60 {
        return "just now"
    }

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

    // Weergave zonder achtervoegsel „geleden“
    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)))

De methode string(fromTimeInterval:) accepteert het verschil in seconden en bepaalt automatisch de context (positieve waarde — toekomst, negatieve — verleden). Dit is handig wanneer het verschil al bekend is (bijvoorbeeld ontvangen van de server als unix timestamp). In dit geval hoeft u geen Date te maken — het verschil wordt rechtstreeks doorgegeven.

Lokalisatie van relatieve datums

RelativeDateTimeFormatter lokaliseert de uitvoer automatisch op basis van Locale.current. Om de formatteringstaal te wijzigen, stelt u de eigenschap locale in — in tegenstelling tot DateFormatter is locale voor RelativeDateTimeFormatter niet vast en kan deze per aanroep worden gewijzigd. Dit maakt het mogelijk relatieve datums in een andere taal dan de interfacetaal weer te geven (bijvoorbeeld inhoud in de oorspronkelijke taal).

De complexiteit van het lokaliseren van relatieve datums ligt in de grammaticale kenmerken van verschillende talen. Het Russisch vereist verschillende telwoordvormen: „1 minuut“, „2 minuten“, „5 minuten“. Het Arabisch gebruikt de meervoudsvorm voor getallen van 3 tot 10 en speciale vormen voor 11+. Het Chinees heeft helemaal geen verbuiging, wat de taak vereenvoudigt. RelativeDateTimeFormatter dekt al deze gevallen af via ICU-regels, zonder dat extra code nodig is.

swift
import Foundation

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

let targetDate = Date().addingTimeInterval(-7200) // 2 uur geleden

// Verschillende locales
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)")
}

// Controleer Russische verbuiging
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()))")
}

Belangrijk detail: RelativeDateTimeFormatter negeert TimeZone bij het berekenen van het verschil voor .numeric-instellingen — het gebruikt het absolute verschil in seconden. Voor de .full-stijl (met uitgeschreven getallen) en speciale gevallen (gisteren, vandaag) wordt TimeZone echter wel meegenomen. Stel TimeZone altijd expliciet in voor consistentie, vooral als de app met serverdatums in UTC werkt.

Veelvoorkomende fouten bij het formatteren

TimeZone negeren bij het berekenen van relatieve datums — een veelvoorkomende fout bij het werken met serverdatums. Als de server Date in UTC verzendt en RelativeDateTimeFormatter TimeZone.current gebruikt, kan het verschil onjuist worden berekend voor datums dicht bij het huidige moment. Het wordt aanbevolen altijd formatter.timeZone = TimeZone(secondsFromGMT: 0) in te stellen voor servergegevens.

Onjuiste eenheidskeuze voor korte intervallen — RelativeDateTimeFormatter rondt het verschil af op de grootste eenheid. Voor 25 uur is het resultaat „1 dag geleden“, wat de gebruiker kan misleiden. Als hoge nauwkeurigheid vereist is (bijvoorbeeld voor afteltimers), gebruik dan DateComponentsFormatter in plaats van RelativeDateTimeFormatter — deze kan meerdere eenheden tegelijk weergeven.

Geen controle op negatieve TimeInterval — als een datum in de toekomst als verleden wordt doorgegeven (negatieve waarde in string(fromTimeInterval:)), kan de formatter een onjuiste tekenreeks retourneren. Controleer altijd het teken van het interval vóór doorgeven aan de formatter, vooral bij het werken met servergegevens waar de tijdzone de berekening kan verstoren.

Volgens Hacker News (2024) is een van de meest besproken problemen van RelativeDateTimeFormatter het ontbreken van ingebouwde ondersteuning voor „gisteren“ en „vandaag“ in het Engels. In plaats van „gisteren“ retourneert de formatter voor een verschil van 90000 seconden „1 dag geleden“. Voor het Russisch bestaat dit probleem niet — „1 dag geleden“ klinkt natuurlijk, maar voor een Engelstalige UI is „yesterday“ te prefereren. Deze functionaliteit wordt niet ondersteund en vereist handmatige controle via Calendar.isDateInToday/Yesterday.

Veelgestelde vragen

Wat is RelativeDateTimeFormatter?

RelativeDateTimeFormatter — Foundation-klasse voor het weergeven van datums in relatief formaat: „5 minuten geleden“, „over 2 dagen“. Beschikbaar vanaf iOS 13 en macOS 10.15.

Hoe selecteert RelativeDateTimeFormatter eenheden?

Volgens het principe van de grootste niet-nul eenheid — seconden, minuten, uren, dagen, weken, maanden of jaren. Voor een verschil van 3720 seconden (1 uur 2 minuten) wordt bijvoorbeeld de eenheid „uur“ gekozen, niet „minuten“.

Hoe wijzig ik de taal van de uitvoer?

Stel de eigenschap locale in op de gewenste Locale-instantie. Standaard wordt Locale.current gebruikt. Voorbeeld: formatter.locale = Locale(identifier: "de_DE") voor het Duits.

Wat is het verschil tussen .numeric en .abbreviated?

.numeric — de volledige vorm („3 dagen geleden“), .abbreviated — verkort („3 dagen geleden“). De keuze hangt af van de context: numeric voor de hoofd-UI, abbreviated voor compacte elementen.

Hoe geef ik „zojuist“ weer in plaats van „0 seconden geleden“?

Voeg een handmatige controle toe voor een interval kleiner dan 5–10 seconden. RelativeDateTimeFormatter ondersteunt „zojuist“ niet — voor kleine intervallen retourneert het „0 seconden geleden“. Gebruik voorwaardelijke logica met een drempel.

Samenvatting

  • RelativeDateTimeFormatter — handige klasse voor het weergeven van relatieve datums in iOS 13+
  • Automatische lokalisatie — correcte verbuiging voor alle ondersteunde talen via ICU
  • Drie stijlen — .numeric (standaard), .abbreviated (compact), .full (uitgeschreven)
  • Eenheidskeuze — automatisch volgens het principe van de grootste niet-nul waarde
  • TimeZone-configuratie — vereist voor consistentie bij het werken met serverdatums
  • Drempel „zojuist“ — niet ingebouwd ondersteund; handmatige controle van het interval vereist
  • Geen ondersteuning voor „gisteren“ — voor het Engels gebruikt de formatter de vorm yesterday niet

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook