RelativeDateTimeFormatter iOS और macOS में Foundation का एक क्लास है जो पूर्ण तिथियों को मानव-पठनीय सापेक्ष वाक्यांशों में बदलता है: "5 मिनट पहले", "कल", "3 दिनों में"। Apple Developer Documentation, 2024 के अनुसार, RelativeDateTimeFormatter स्वचालित रूप से उपयुक्त इकाई (सेकंड, मिनट, घंटे, दिन) चुनता है और डिवाइस की वर्तमान लोकेल की भाषा में आउटपुट को स्थानीयकृत करता है। Calendar के माध्यम से तिथियों के बीच अंतर की मैन्युअल गणना के विपरीत, यह क्लास प्रत्येक भाषा की भाषाई विशेषताओं को ध्यान में रखता है: कुछ भाषाओं में अंक विभक्त होते हैं, दूसरों में "कल" शब्द के लिए एक विशेष रूप का उपयोग किया जाता है। यह क्लास iOS 13 और macOS 10.15 से उपलब्ध है।
मुख्य बिंदु
RelativeDateTimeFormatter Foundation में Formatter का एक उपवर्ग है जो एक Date (या सेकंड में अंतर) लेता है और सापेक्ष समय के साथ एक स्थानीयकृत स्ट्रिंग लौटाता है। उदाहरण के लिए, वर्तमान से 5 मिनट पहले की तिथि के लिए, यह "5 मिनट पहले" लौटाता है। क्लास तीन लौकिक संदर्भों का समर्थन करता है: भूतकाल, भविष्यत्काल और वर्तमानकाल।
RelativeDateTimeFormatter की आंतरिक तर्क प्रक्रिया तिथियों के बीच अंतर की गणना करने और सही व्याकरणिक रूप चुनने के लिए Calendar और Locale का उपयोग करती है। हिंदी के लिए, यह "1 मिनट पहले" और "5 मिनट पहले" के बीच चुनता है (हिंदी में विभक्ति रूपों के साथ)। यह कार्यक्षमता ICU (International Components for Unicode) डेटा पर आधारित है और डेवलपर से किसी अतिरिक्त कॉन्फ़िगरेशन की आवश्यकता नहीं है।
Apple WWDC 2019 के अनुसार, RelativeDateTimeFormatter स्थानीयकरण को सरल बनाने के लिए फ्रेमवर्क का हिस्सा बना — इसके आने से पहले, डेवलपर्स को मैन्युअल रूप से तिथि अंतर की गणना करनी होती थी और String.localizedStringWithFormat के माध्यम से स्थानीयकृत स्ट्रिंग्स को प्रतिस्थापित करना होता था। इससे विभक्ति त्रुटियाँ (विशेष रूप से स्लाव और अरबी भाषाओं के लिए) और माप की इकाइयों का गलत चयन होता था।
एल्गोरिदम RelativeDateTimeFormatter तीन चरणों में काम करता है: पारित तिथि और वर्तमान क्षण के बीच अंतर की गणना, उपयुक्त इकाई का चयन (सबसे बड़ी जो शून्य नहीं देती), और लोकेल के अनुसार स्वरूपण। उदाहरण के लिए, 3720 सेकंड (1 घंटा 2 मिनट) के अंतर के लिए, इकाई "घंटा" चुनी जाती है और परिणाम "1 घंटा पहले" होता है, न कि "62 मिनट पहले"।
इकाइयाँ "सबसे बड़ी गैर-शून्य" के सिद्धांत पर चुनी जाती हैं: यदि अंतर 86400 सेकंड (1 दिन) से अधिक है, तो दिनों का उपयोग किया जाता है; यदि 604800 (1 सप्ताह) से अधिक है — सप्ताह, और इसी तरह। यह एल्गोरिदम सुनिश्चित करता है कि परिणाम हमेशा स्वाभाविक रूप से पढ़ा जाए: "518400 सेकंड पहले" के बजाय, उपयोगकर्ता "6 दिन पहले" देखता है। इकाइयों की सटीक सीमाएँ वर्तमान लोकेल के कैलेंडर द्वारा निर्धारित की जाती हैं।
| अंतर सीमा | इकाई | hi_IN के लिए उदाहरण |
|---|---|---|
| 0–59 सेकंड | Seconds | 30 सेकंड पहले |
| 1–59 मिनट | Minutes | 5 मिनट पहले |
| 1–23 घंटे | Hours | 3 घंटे पहले |
| 1–6 दिन | Days | 2 दिन पहले |
| 7–27 दिन | Weeks | 1 सप्ताह पहले |
| 28 दिन–11 महीने | Months | 3 महीने पहले |
| 12+ महीने | Years | 1 वर्ष पहले |
स्वरूपण संदर्भ वाक्यांश के अंत को निर्धारित करता है। भूतकाल के लिए: "पहले" (हिंदी)। भविष्यत्काल के लिए: "3 दिनों में" (हिंदी)। वर्तमानकाल के लिए: "अब" (हिंदी)। संदर्भ localizeString(fromTimeInterval:) विधि के माध्यम से या सीधे string(from: Date) के माध्यम से सेट किया जाता है।
RelativeDateTimeFormatter आउटपुट को नियंत्रित करने के लिए कई सेटिंग्स प्रदान करता है: unitsStyle गुण स्वरूपण शैली (numeric, abbreviated, full, spellOut) निर्धारित करता है, और maximumUnitCount प्रदर्शित इकाइयों की संख्या को सीमित करता है। उदाहरण के लिए, maximumUnitCount = 1 के साथ, 1 घंटा 30 मिनट का अंतर "1 घंटा पहले" के रूप में दिखाया जाता है न कि "1 घंटा 30 मिनट पहले"।
इकाई सीमा: डिफ़ॉल्ट रूप से, RelativeDateTimeFormatter केवल एक (सबसे बड़ी) इकाई प्रदर्शित करता है। maximumUnitCount = 2 सेट करने से अधिक सटीक विवरण के लिए अगली इकाई शामिल होती है: "1 घंटा 30 मिनट पहले"। हालांकि, यह छोटे संदेशों (पुश नोटिफिकेशन, अलर्ट) के लिए स्ट्रिंग को अत्यधिक लंबा बना सकता है। UI के लिए, maximumUnitCount = 1 रखने की अनुशंसा की जाती है।
import Foundation
let formatter = RelativeDateTimeFormatter()
// Configure styles
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1
// Examples with different dates
let fiveMinAgo = Date().addingTimeInterval(-300)
print("5 min ago: \(formatter.localizedString(for: fiveMinAgo, relativeTo: Date()))")
let twoDaysLater = Date().addingTimeInterval(172800)
print("2 days later: \(formatter.localizedString(for: twoDaysLater, relativeTo: Date()))")
// Abbreviated style
formatter.unitsStyle = .abbreviated
let oneWeekAgo = Date().addingTimeInterval(-604800)
print("Abbreviated: \(formatter.localizedString(for: oneWeekAgo, relativeTo: Date()))")
// Full style (spelled out)
formatter.unitsStyle = .full
let threeHours = Date().addingTimeInterval(10800)
print("Full: \(formatter.localizedString(for: threeHours, relativeTo: Date()))")
विभिन्न संदर्भों के लिए शैली चुनना: समाचार फ़ीड के लिए, maximumUnitCount = 1 के साथ .numeric का उपयोग करें — यह Twitter, Instagram और Facebook के लिए मानक है। अभिगम्यता (VoiceOver) के लिए, .full का उपयोग करें — वर्तनी वाली संख्याएँ अधिक स्वाभाविक रूप से पढ़ी जाती हैं। कॉम्पैक्ट तत्वों (नोटिफिकेशन बैज, स्टेटस बार) के लिए, स्थान बचाने के लिए .abbreviated का उपयोग करें।
मूल उपयोग RelativeDateTimeFormatter का एक इंस्टेंस बनाने, गुणों को कॉन्फ़िगर करने और स्वरूपण विधियों में से एक को कॉल करने तक सीमित है। मुख्य विधियाँ हैं: localizedString(for:relativeTo:) — तिथियों की एक जोड़ी के लिए, localizedString(fromTimeInterval:) — सेकंड में अंतर के लिए, और string(for:) — स्वचालित संदर्भ (भूत/भविष्य) के साथ Date के लिए।
import Foundation
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1
// Social network UI examples
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)")
}
// Future dates
let reminderFormatter = RelativeDateTimeFormatter()
reminderFormatter.unitsStyle = .abbreviated
let inOneHour = Date().addingTimeInterval(3600)
let reminderText = reminderFormatter.localizedString(
for: inOneHour,
relativeTo: Date()
)
print("Reminder: \(reminderText)")
"अभी" परिदृश्य को संभालना — RelativeDateTimeFormatter में बहुत छोटे अंतराल के लिए "अभी" वाक्यांश का कोई अंतर्निहित समर्थन नहीं है। 5 सेकंड से कम के अंतर के लिए, यह "0 सेकंड पहले" लौटाता है, जो UI में खराब दिखता है। फ़ॉर्मेटर कॉल को सशर्त तर्क में लपेटने की अनुशंसा की जाती है: यदि अंतर एक निर्धारित सीमा (जैसे, 5 सेकंड) से कम है — मैन्युअल रूप से "अभी" प्रदर्शित करें, अन्यथा तिथि को फ़ॉर्मेटर को पास करें।
import Foundation
func relativeTimeString(from date: Date) -> String {
let interval = Date().timeIntervalSince(date)
// "Just now" threshold
if interval < 5 {
return "just now"
}
// "Today" threshold
if interval < 60 {
return "just now"
}
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1
// Display without "ago" suffix
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:) विधि सेकंड में अंतर स्वीकार करती है और स्वचालित रूप से संदर्भ निर्धारित करती है (सकारात्मक मान — भविष्य, नकारात्मक — भूत)। यह तब सुविधाजनक होता है जब अंतर पहले से ज्ञात हो (जैसे, सर्वर से unix टाइमस्टैम्प के रूप में प्राप्त)। इस मामले में, Date बनाने की आवश्यकता नहीं है — अंतर सीधे पास किया जाता है।
RelativeDateTimeFormatter Locale.current के आधार पर स्वचालित रूप से आउटपुट को स्थानीयकृत करता है। स्वरूपण भाषा बदलने के लिए, locale गुण सेट करें — DateFormatter के विपरीत, RelativeDateTimeFormatter के लिए लोकेल निश्चित नहीं है और इसे प्रत्येक कॉल के लिए बदला जा सकता है। यह इंटरफ़ेस भाषा से भिन्न भाषा में सापेक्ष तिथियाँ प्रदर्शित करने की अनुमति देता है (जैसे, मूल भाषा में सामग्री)।
सापेक्ष तिथियों के स्थानीयकरण की जटिलता विभिन्न भाषाओं की व्याकरणिक विशेषताओं में निहित है। हिंदी में अंकों के विभिन्न रूपों की आवश्यकता होती है: "1 मिनट", "2 मिनट"। अरबी 3 से 10 तक की संख्याओं के लिए बहुवचन रूप और 11+ के लिए विशेष रूपों का उपयोग करती है। चीनी में कोई विभक्ति नहीं है, जो कार्य को सरल बनाता है। RelativeDateTimeFormatter अतिरिक्त कोड की आवश्यकता के बिना, ICU नियमों के माध्यम से इन सभी मामलों को कवर करता है।
import Foundation
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .numeric
formatter.maximumUnitCount = 1
let targetDate = Date().addingTimeInterval(-7200) // 2 hours ago
// Different 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)")
}
// Check Hindi pluralization
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()))")
}
एक महत्वपूर्ण बारीकियाँ: RelativeDateTimeFormatter .numeric सेटिंग्स के लिए अंतर की गणना करते समय TimeZone को अनदेखा करता है — यह सेकंड में पूर्ण अंतर का उपयोग करता है। हालांकि, .full शैली (वर्तनी वाली संख्याओं के साथ) और विशेष मामलों (कल, आज) के लिए, TimeZone को ध्यान में रखा जाता है। संगति के लिए हमेशा TimeZone को स्पष्ट रूप से सेट करें, खासकर यदि एप्लिकेशन UTC में सर्वर तिथियों के साथ काम करता है।
सापेक्ष तिथियों की गणना करते समय TimeZone को अनदेखा करना — सर्वर तिथियों के साथ काम करते समय एक सामान्य गलती। यदि सर्वर UTC में Date भेजता है, और RelativeDateTimeFormatter TimeZone.current का उपयोग करता है, तो वर्तमान क्षण के करीब की तिथियों के लिए अंतर गलत तरीके से गणना की जा सकती है। सर्वर डेटा के लिए हमेशा formatter.timeZone = TimeZone(secondsFromGMT: 0) सेट करने की अनुशंसा की जाती है।
छोटे अंतराल के लिए गलत इकाई चयन — RelativeDateTimeFormatter अंतर को सबसे बड़ी इकाई तक पूर्णांकित करता है। 25 घंटों के लिए, परिणाम "1 दिन पहले" होगा, जो उपयोगकर्ता को गुमराह कर सकता है। यदि उच्च सटीकता की आवश्यकता है (जैसे, काउंटडाउन टाइमर के लिए), तो RelativeDateTimeFormatter के बजाय DateComponentsFormatter का उपयोग करें — यह एक साथ कई इकाइयाँ प्रदर्शित करने की अनुमति देता है।
नकारात्मक TimeInterval की जाँच का अभाव — यदि भविष्य की तिथि भूतकाल के रूप में पारित की जाती है (string(fromTimeInterval:) में नकारात्मक मान), तो फ़ॉर्मेटर गलत स्ट्रिंग लौटा सकता है। फ़ॉर्मेटर को पास करने से पहले हमेशा अंतराल के चिह्न की जाँच करें, विशेष रूप से सर्वर डेटा के साथ काम करते समय जहाँ समय क्षेत्र गणना को विकृत कर सकता है।
Hacker News (2024) के अनुसार, RelativeDateTimeFormatter की सबसे चर्चित समस्याओं में से एक अंग्रेजी भाषा के लिए "कल" और "आज" के अंतर्निहित समर्थन की कमी है। "कल" के बजाय, 90000 सेकंड के अंतर के लिए फ़ॉर्मेटर "1 दिन पहले" लौटाता है। हिंदी भाषा के लिए ऐसी कोई समस्या नहीं है — "1 दिन पहले" स्वाभाविक लगता है, लेकिन अंग्रेजी UI के लिए "yesterday" बेहतर है। यह कार्यक्षमता समर्थित नहीं है और इसके लिए Calendar.isDateInToday/Yesterday के माध्यम से मैन्युअल जाँच की आवश्यकता होती है।
अक्सर पूछे जाने वाले प्रश्न
RelativeDateTimeFormatter Foundation का एक क्लास है जो तिथियों को सापेक्ष प्रारूप में प्रदर्शित करता है: "5 मिनट पहले", "2 दिनों में"। iOS 13 और macOS 10.15 से उपलब्ध।
सबसे बड़ी गैर-शून्य इकाई के सिद्धांत द्वारा — सेकंड, मिनट, घंटे, दिन, सप्ताह, महीने या वर्ष। उदाहरण के लिए, 3720 सेकंड (1 घंटा 2 मिनट) के अंतर के लिए, इकाई "घंटा" चुनी जाती है, न कि "मिनट"।
locale गुण सेट करें वांछित Locale इंस्टेंस पर। डिफ़ॉल्ट रूप से Locale.current का उपयोग किया जाता है। उदाहरण: जर्मन के लिए formatter.locale = Locale(identifier: "de_DE")।
.numeric — पूर्ण रूप ("3 दिन पहले"), .abbreviated — संक्षिप्त रूप ("3 दि. पहले")। चुनाव संदर्भ पर निर्भर करता है: मुख्य UI के लिए numeric, कॉम्पैक्ट तत्वों के लिए abbreviated।
मैन्युअल जाँच जोड़ें 5-10 सेकंड से कम के अंतराल के लिए। RelativeDateTimeFormatter "अभी" का समर्थन नहीं करता — छोटे अंतराल के लिए यह "0 सेकंड पहले" लौटाता है। सीमा के साथ सशर्त तर्क का उपयोग करें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें