RelativeDateTimeFormatter হল iOS এবং macOS-এ Foundation-এর একটি ক্লাস যা পরম তারিখকে মানব-পাঠযোগ্য আপেক্ষিক বাক্যাংশে রূপান্তরিত করে: "৫ মিনিট আগে", "গতকাল", "৩ দিনের মধ্যে"। Apple Developer Documentation, 2024 অনুসারে, RelativeDateTimeFormatter স্বয়ংক্রিয়ভাবে উপযুক্ত ইউনিট (সেকেন্ড, মিনিট, ঘন্টা, দিন) নির্বাচন করে এবং ডিভাইসের বর্তমান লোকেলের ভাষায় আউটপুট স্থানীয়করণ করে। Calendar-এর মাধ্যমে তারিখের মধ্যে পার্থক্যের ম্যানুয়াল গণনার বিপরীতে, এই ক্লাসটি প্রতিটি ভাষার ভাষাতাত্ত্বিক বৈশিষ্ট্যগুলি বিবেচনা করে: কিছু ভাষার জন্য অঙ্ক বিবর্তিত হয়, অন্যগুলির জন্য "গতকাল" শব্দের একটি বিশেষ রূপ ব্যবহৃত হয়। ক্লাসটি iOS 13 এবং macOS 10.15 থেকে উপলব্ধ।
মূল পয়েন্ট
RelativeDateTimeFormatter হল Foundation-এ Formatter-এর একটি উপশ্রেণী যা একটি Date (বা সেকেন্ডে পার্থক্য) নেয় এবং আপেক্ষিক সময় সহ একটি স্থানীয়কৃত স্ট্রিং ফেরত দেয়। উদাহরণস্বরূপ, বর্তমান থেকে ৫ মিনিট আগের একটি তারিখের জন্য, এটি "৫ মিনিট আগে" ফেরত দেয়। ক্লাসটি তিনটি সাময়িক প্রসঙ্গ সমর্থন করে: অতীত, ভবিষ্যৎ এবং বর্তমান।
RelativeDateTimeFormatter-এর অভ্যন্তরীণ যুক্তি তারিখের মধ্যে পার্থক্য গণনা করতে এবং সঠিক ব্যাকরণগত রূপ নির্বাচন করতে Calendar এবং Locale ব্যবহার করে। বাংলার জন্য, এটি "১ মিনিট আগে" এবং "৫ মিনিট আগে"-এর মধ্যে নির্বাচন করে (বাংলায় বিবর্তিত রূপ সহ)। এই কার্যকারিতা ICU (International Components for Unicode) ডেটার উপর ভিত্তি করে এবং ডেভেলপারের কাছ থেকে কোনো অতিরিক্ত কনফিগারেশনের প্রয়োজন হয় না।
Apple WWDC 2019 অনুসারে, RelativeDateTimeFormatter স্থানীয়করণ সহজ করার জন্য ফ্রেমওয়ার্কের অংশ হয়ে উঠেছে — এর আগমনের আগে, ডেভেলপারদের ম্যানুয়ালি তারিখের পার্থক্য গণনা করতে হত এবং String.localizedStringWithFormat-এর মাধ্যমে স্থানীয়কৃত স্ট্রিং প্রতিস্থাপন করতে হত। এর ফলে বিবর্তন ত্রুটি (বিশেষ করে স্লাভিক এবং আরবি ভাষার জন্য) এবং পরিমাপের এককের ভুল নির্বাচন ঘটত।
অ্যালগরিদম RelativeDateTimeFormatter তিনটি ধাপ নিয়ে গঠিত: পাস করা তারিখ এবং বর্তমান মুহূর্তের মধ্যে পার্থক্য গণনা, উপযুক্ত ইউনিট নির্বাচন (সবচেয়ে বড় যা শূন্য দেয় না), এবং লোকেল অনুযায়ী ফর্ম্যাটিং। উদাহরণস্বরূপ, ৩৭২০ সেকেন্ড (১ ঘন্টা ২ মিনিট) পার্থক্যের জন্য, ইউনিট "ঘন্টা" নির্বাচিত হয় এবং ফলাফল "১ ঘন্টা আগে" হয়, "৬২ মিনিট আগে" নয়।
ইউনিটগুলি "সবচেয়ে বড় অ-শূন্য" নীতিতে নির্বাচিত হয়: যদি পার্থক্য ৮৬৪০০ সেকেন্ড (১ দিন) এর বেশি হয়, দিন ব্যবহার করা হয়; যদি ৬০৪৮০০ (১ সপ্তাহ) এর বেশি হয় — সপ্তাহ, এবং আরও অনেক কিছু। এই অ্যালগরিদম নিশ্চিত করে যে ফলাফল সর্বদা স্বাভাবিকভাবে পড়া যায়: "৫১৮৪০০ সেকেন্ড আগে"-এর পরিবর্তে, ব্যবহারকারী "৬ দিন আগে" দেখেন। ইউনিটের সঠিক সীমানা বর্তমান লোকেলের ক্যালেন্ডার দ্বারা নির্ধারিত হয়।
| পার্থক্যের সীমা | ইউনিট | bn_BD-এর জন্য উদাহরণ |
|---|---|---|
| ০–৫৯ সেকেন্ড | Seconds | ৩০ সেকেন্ড আগে |
| ১–৫৯ মিনিট | Minutes | ৫ মিনিট আগে |
| ১–২৩ ঘন্টা | Hours | ৩ ঘন্টা আগে |
| ১–৬ দিন | Days | ২ দিন আগে |
| ৭–২৭ দিন | Weeks | ১ সপ্তাহ আগে |
| ২৮ দিন–১১ মাস | Months | ৩ মাস আগে |
| ১২+ মাস | Years | ১ বছর আগে |
ফর্ম্যাটিং প্রসঙ্গ বাক্যাংশের সমাপ্তি নির্ধারণ করে। অতীতের জন্য: "আগে" (বাংলা)। ভবিষ্যতের জন্য: "৩ দিনের মধ্যে" (বাংলা)। বর্তমানের জন্য: "এখন" (বাংলা)। প্রসঙ্গটি localizeString(fromTimeInterval:) পদ্ধতির মাধ্যমে বা সরাসরি string(from: Date)-এর মাধ্যমে সেট করা হয়।
RelativeDateTimeFormatter আউটপুট নিয়ন্ত্রণের জন্য বেশ কয়েকটি সেটিংস প্রদান করে: unitsStyle বৈশিষ্ট্য ফর্ম্যাটিং শৈলী (numeric, abbreviated, full, spellOut) নির্ধারণ করে, এবং maximumUnitCount প্রদর্শিত ইউনিটের সংখ্যা সীমিত করে। উদাহরণস্বরূপ, maximumUnitCount = 1-এর সাথে, ১ ঘন্টা ৩০ মিনিটের পার্থক্য "১ ঘন্টা আগে" হিসাবে দেখানো হয় "১ ঘন্টা ৩০ মিনিট আগে"-এর পরিবর্তে।
ইউনিট সীমা: ডিফল্টরূপে, RelativeDateTimeFormatter শুধুমাত্র একটি (সবচেয়ে বড়) ইউনিট প্রদর্শন করে। maximumUnitCount = 2 সেট করলে আরও সঠিক বর্ণনার জন্য পরবর্তী ইউনিট অন্তর্ভুক্ত হয়: "১ ঘন্টা ৩০ মিনিট আগে"। তবে, এটি ছোট বার্তার (পুশ নোটিফিকেশন, সতর্কতা) জন্য স্ট্রিংটি অত্যধিক দীর্ঘ করতে পারে। 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-এ খুব ছোট ব্যবধানের জন্য "এইমাত্র" বাক্যাংশের কোনো অন্তর্নির্মিত সমর্থন নেই। ৫ সেকেন্ডের কম পার্থক্যের জন্য, এটি "০ সেকেন্ড আগে" ফেরত দেয়, যা UI-তে খারাপ দেখায়। ফর্ম্যাটার কলকে শর্তসাপেক্ষ যুক্তিতে মোড়ানোর সুপারিশ করা হয়: যদি পার্থক্য নির্ধারিত সীমার চেয়ে কম হয় (যেমন, ৫ সেকেন্ড) — ম্যানুয়ালি "এইমাত্র" প্রদর্শন করুন, অন্যথায় তারিখটি ফর্ম্যাটারে পাঠান।
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-এর জন্য লোকেল স্থির নয় এবং এটি প্রতিটি কলের জন্য পরিবর্তন করা যেতে পারে। এটি ইন্টারফেস ভাষা থেকে ভিন্ন ভাষায় আপেক্ষিক তারিখ প্রদর্শনের অনুমতি দেয় (যেমন, মূল ভাষায় বিষয়বস্তু)।
আপেক্ষিক তারিখের স্থানীয়করণের জটিলতা বিভিন্ন ভাষার ব্যাকরণগত বৈশিষ্ট্যের মধ্যে নিহিত। বাংলায় অঙ্কের বিভিন্ন রূপের প্রয়োজন হয়: "১ মিনিট", "২ মিনিট"। আরবি ৩ থেকে ১০ পর্যন্ত সংখ্যার জন্য বহুবচন রূপ এবং ১১+-এর জন্য বিশেষ রূপ ব্যবহার করে। চীনা ভাষায় কোনো বিবর্তন নেই, যা কাজটিকে সহজ করে। 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 Bengali 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 পার্থক্যকে বৃহত্তম ইউনিটে রাউন্ড করে। ২৫ ঘন্টার জন্য, ফলাফল "১ দিন আগে" হবে, যা ব্যবহারকারীকে বিভ্রান্ত করতে পারে। যদি উচ্চ নির্ভুলতার প্রয়োজন হয় (যেমন, কাউন্টডাউন টাইমারের জন্য), RelativeDateTimeFormatter-এর পরিবর্তে DateComponentsFormatter ব্যবহার করুন — এটি একসাথে একাধিক ইউনিট প্রদর্শনের অনুমতি দেয়।
নেতিবাচক TimeInterval-এর চেকের অভাব — যদি ভবিষ্যতের তারিখ অতীত হিসাবে পাঠানো হয় (string(fromTimeInterval:)-এ নেতিবাচক মান), ফর্ম্যাটারটি ভুল স্ট্রিং ফেরত দিতে পারে। ফর্ম্যাটারে পাঠানোর আগে সর্বদা ব্যবধানের চিহ্ন পরীক্ষা করুন, বিশেষ করে সার্ভার ডেটার সাথে কাজ করার সময় যেখানে সময় অঞ্চল গণনাকে বিকৃত করতে পারে।
Hacker News (2024) অনুসারে, RelativeDateTimeFormatter-এর সবচেয়ে আলোচিত সমস্যাগুলির মধ্যে একটি হল ইংরেজি ভাষার জন্য "গতকাল" এবং "আজ"-এর অন্তর্নির্মিত সমর্থনের অভাব। "গতকাল"-এর পরিবর্তে, ৯০০০০ সেকেন্ডের পার্থক্যের জন্য ফর্ম্যাটার "১ দিন আগে" ফেরত দেয়। বাংলা ভাষার জন্য এমন কোনো সমস্যা নেই — "১ দিন আগে" স্বাভাবিক শোনায়, কিন্তু ইংরেজি UI-এর জন্য "yesterday" পছন্দনীয়। এই কার্যকারিতা সমর্থিত নয় এবং Calendar.isDateInToday/Yesterday-এর মাধ্যমে ম্যানুয়াল চেক প্রয়োজন।
সচরাচর জিজ্ঞাসা
RelativeDateTimeFormatter হল Foundation-এর একটি ক্লাস যা তারিখকে আপেক্ষিক বিন্যাসে প্রদর্শন করে: "৫ মিনিট আগে", "২ দিনের মধ্যে"। iOS 13 এবং macOS 10.15 থেকে উপলব্ধ।
সবচেয়ে বড় অ-শূন্য ইউনিটের নীতি দ্বারা — সেকেন্ড, মিনিট, ঘন্টা, দিন, সপ্তাহ, মাস বা বছর। উদাহরণস্বরূপ, ৩৭২০ সেকেন্ড (১ ঘন্টা ২ মিনিট) পার্থক্যের জন্য, ইউনিট "ঘন্টা" নির্বাচিত হয়, "মিনিট" নয়।
locale বৈশিষ্ট্য সেট করুন পছন্দসই Locale ইনস্ট্যান্সে। ডিফল্টরূপে Locale.current ব্যবহার করা হয়। উদাহরণ: জার্মানের জন্য formatter.locale = Locale(identifier: "de_DE")।
.numeric — পূর্ণ রূপ ("৩ দিন আগে"), .abbreviated — সংক্ষিপ্ত রূপ ("৩ দি. আগে")। পছন্দ প্রসঙ্গের উপর নির্ভর করে: প্রধান UI-এর জন্য numeric, কমপ্যাক্ট উপাদানের জন্য abbreviated।
একটি ম্যানুয়াল চেক যোগ করুন ৫-১০ সেকেন্ডের কম ব্যবধানের জন্য। RelativeDateTimeFormatter "এইমাত্র" সমর্থন করে না — ছোট ব্যবধানের জন্য এটি "০ সেকেন্ড আগে" ফেরত দেয়। একটি সীমা সহ শর্তসাপেক্ষ যুক্তি ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন