DateIntervalFormatter یک کلاس Foundation در iOS و macOS است که برای قالببندی محدودههای تاریخ به رشتههای بومیسازی شده طراحی شده است: «۲۱–۲۵ ژوئیه ۲۰۲۴»، «از ۲۱ تا ۲۵ ژوئیه ۲۰۲۴» یا «Jul 21–25, 2024». بر اساس Apple Developer Documentation, 2024، DateIntervalFormatter به طور خودکار تعیین میکند که کدام اجزای تاریخ تکرار شوند (اگر بازه در یک ماه باشد — ماه یک بار نمایش داده میشود) و جداکنندهها و ترتیب کلمات را بومیسازی میکند. برخلاف چسباندن دستی دو تاریخ قالببندی شده، این کلاس قواعد گرامری زبان را در نظر میگیرد: برای فارسی — حرف اضافه «تا»، برای انگلیسی — خط تیره بدون حرف اضافه. این کلاس از iOS 8 و macOS 10.10 در دسترس است.
نکات اصلی
DateIntervalFormatter زیرکلاسی از Formatter در Foundation است که یک شی DateInterval (محدوده بین دو تاریخ) را دریافت میکند و یک رشته بومیسازی شده با توضیح این محدوده برمیگرداند. به عنوان مثال، برای محدوده ۲۱ تا ۲۵ ژوئیه ۲۰۲۴، نتیجه برای fa_IR «۲۱–۲۵ ژوئیه ۲۰۲۴» و برای en_US «Jul 21–25, 2024» خواهد بود. این کلاس عناصر تکراری را هوشمندانه گروهبندی میکند: اگر هر دو تاریخ در یک ماه باشند، نام ماه یک بار نمایش داده میشود.
ارزش اصلی DateIntervalFormatter پردازش خودکار گرامر بازهها است. در قالببندی دستی، برنامهنویس باید ماه/سال شروع و پایان را مقایسه کند، جداکننده (خط تیره، «تا»، «to»، «bis») را انتخاب کرده و بر انحنا نظارت داشته باشد. DateIntervalFormatter این کار را بر اساس دادههای CLDR (مخزن دادههای محلی مشترک) به طور خودکار انجام میدهد، که تعداد باگها را در برنامههای بینالمللی، به ویژه برای زبانهایی با گرامر پیچیده، کاهش میدهد.
بر اساس Unicode CLDR v44 (2024)، قواعد قالببندی بازههای تاریخ بین زبانها بسیار متفاوت است. آلمانی از حرف اضافه «bis» (21.–25. Juli 2024)، فرانسوی از «au» (du 21 au 25 juillet 2024)، ژاپنی از خط فاصله (2024 Jul 21–25) استفاده میکند. DateIntervalFormatter همه این تغییرات را بدون کد اضافی از طرف برنامهنویس پوشش میدهد.
اصل کار DateIntervalFormatter بر اساس تجزیه و تحلیل دو تاریخ تشکیلدهنده بازه و انتخاب نمایش متنی بهینه با در نظر گرفتن locale است. کلاس اجزای تاریخ (سال، ماه، روز) را مقایسه کرده و درباره گروهبندی تصمیم میگیرد: اگر سال یکسان است — یک بار نمایش داده میشود؛ اگر ماه یکسان است — یک بار نمایش داده میشود؛ اگر روزها متفاوت هستند — محدوده روزها نمایش داده میشود.
| بازه | fa_IR | en_US |
|---|---|---|
| یک روز | ۲۱ ژوئیه ۲۰۲۴ | Jul 21, 2024 |
| داخل یک ماه | ۲۱–۲۵ ژوئیه ۲۰۲۴ | Jul 21–25, 2024 |
| ماههای مختلف | ۲۱ ژوئیه – ۵ اوت ۲۰۲۴ | Jul 21 – Aug 5, 2024 |
| سالهای مختلف | ۲۵ دسامبر ۲۰۲۴ – ۵ ژانویه ۲۰۲۵ | Dec 25, 2024 – Jan 5, 2025 |
| با زمان | ۲۱ ژوئیه ۲۰۲۴، ۱۴:۳۰–۱۶:۴۵ | Jul 21, 2024, 2:30–4:45 PM |
منطق گروهبندی بر اساس الگوهای CLDR پیادهسازی شده است. قالببند برابری هر جزء تاریخ (Calendar.Component: year, month, day) را به ترتیب از بزرگ به کوچک بررسی میکند. به محض اینکه جزئی متفاوت شد، تمام اجزای کوچکتر برای هر دو تاریخ نمایش داده میشوند. به عنوان مثال، برای ۲۱–۲۵ ژوئیه: سال مطابقت دارد، ماه مطابقت دارد، روز متفاوت است → ماه یک بار، روزها برای هر تاریخ جداگانه نمایش داده میشوند.
نکته مهم: DateIntervalFormatter از تنظیم جداکننده از طریق API پشتیبانی نمیکند. جداکننده توسط locale تعیین میشود و قابل بازنویسی نیست. اگر جداکننده سفارشی مورد نیاز است (مثلاً «الی» به جای «تا»)، باید تاریخها را به صورت دستی از طریق DateFormatter قالببندی کرده و رشتهها را با جداکننده سفارشی بچسبانید.
DateIntervalFormatter دو مجموعه سبک ارائه میدهد: dateStyle و timeStyle — برای هر انتهای بازه. این سبکها مشابه DateFormatter کار میکنند: .none جزء را پنهان میکند، .short فرمت کوتاه میدهد (۲۱.۰۷.۲۰۲۴)، .medium — متوسط (۲۱ ژوئیه ۲۰۲۴)، .long — کامل (۲۱ ژوئیه ۲۰۲۴)، .full — حداکثر جزئیات (یکشنبه، ۲۱ ژوئیه ۲۰۲۴). با ترکیب dateStyle و timeStyle میتوان سطوح مختلف جزئیات را به دست آورد.
مهم: dateStyle و timeStyle به طور یکسان برای هر دو انتهای بازه اعمال میشوند. نمیتوان سبک متفاوتی برای شروع و پایان تنظیم کرد (مثلاً .medium برای شروع و .short برای پایان). اگر سبک متفاوت مورد نیاز است، باید هر تاریخ را با DateFormatter جداگانه قالببندی کرده و نتایج را بچسبانید.
import Foundation
let formatter = DateIntervalFormatter()
// ترکیبهای مختلف سبکها
let startDate = Date()
let endDate = Date().addingTimeInterval(345600) // +۴ روز
let interval = DateInterval(start: startDate, end: endDate)
// فقط تاریخ، فرمت متوسط
formatter.dateStyle = .medium
formatter.timeStyle = .none
print("فقط تاریخ: \(formatter.string(from: interval))")
// فرمت کوتاه با زمان
formatter.dateStyle = .short
formatter.timeStyle = .short
print("کوتاه با زمان: \(formatter.string(from: interval))")
// فرمت کامل
formatter.dateStyle = .full
formatter.timeStyle = .none
print("تاریخ کامل: \(formatter.string(from: interval))")
استفاده پایه DateIntervalFormatter شامل ایجاد نمونه، پیکربندی سبکها و فراخوانی string(from:) است. این متد DateInterval — ساختاری با ویژگیهای start و end را میپذیرد. DateInterval را میتوان هم از دو Date و هم با Duration (iOS 16+) ایجاد کرد. پس از قالببندی، نتیجه بدون پردازش اضافی برای نمایش در UI آماده است.
import Foundation
let calendar = Calendar.current
let now = Date()
// مثالهای بازههای خاص
let examples: [(title: String, start: Date, end: Date)] = [
(
"2-hour event",
now,
now.addingTimeInterval(7200)
),
(
"Week-long vacation",
now,
now.addingTimeInterval(604800)
),
(
"Cross-year period",
calendar.date(from: DateComponents(
year: 2024, month: 12, day: 25
))!,
calendar.date(from: DateComponents(
year: 2025, month: 1, day: 5
))!
)
]
let intervalFormatter = DateIntervalFormatter()
intervalFormatter.dateStyle = .medium
intervalFormatter.timeStyle = .short
for (title, start, end) in examples {
let interval = DateInterval(start: start, end: end)
let result = intervalFormatter.string(from: interval)
print("\(title): \(result)")
}
// قالببندی از طریق Calendar (iOS 16+)
if let nextWeek = calendar.date(
byAdding: .day, value: 7, to: now
) {
let weekInterval = DateInterval(start: now, end: nextWeek)
print("۷ روز بعد: \(intervalFormatter.string(from: weekInterval))")
}
DateIntervalFormatter و Calendar Booking: در برنامههای رزرو (هتلها، بلیطها) بازههای تاریخ یک عنصر کلیدی UI هستند. DateIntervalFormatter بازههای بینسالی را به درستی پردازش میکند (مثلاً از ۲۸ دسامبر تا ۳ ژانویه)، ماه و سال را برای هر تاریخ جداگانه گروهبندی میکند. برای چنین سناریوهایی توصیه میشود از dateStyle = .medium و timeStyle = .none استفاده کنید — خواناترین فرمت برای تاریخ بدون زمان.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
// مثالهای رزرو
struct Booking {
let checkIn: Date
let checkOut: Date
var formattedInterval: String {
let interval = DateInterval(start: checkIn, end: checkOut)
return formatter.string(from: interval)
}
}
let booking = Booking(
checkIn: calendar.date(from: DateComponents(
year: 2024, month: 7, day: 21
))!,
checkOut: calendar.date(from: DateComponents(
year: 2024, month: 7, day: 25
))!
)
print("رزرو: \(booking.formattedInterval)")
// استفاده با localeهای مختلف
let enFormatter = DateIntervalFormatter()
enFormatter.dateStyle = .medium
enFormatter.timeStyle = .none
enFormatter.locale = Locale(identifier: "en_US")
print("انگلیسی: \(enFormatter.string(from: interval))")
DateInterval در مقابل DateIntervalFormatter: DateInterval — ساختاری که یک بازه تاریخ را نشان میدهد (شروع و پایان). DateIntervalFormatter — قالببندی که این ساختار را به رشته تبدیل میکند. DateInterval همچنین از بررسی contains(Date) و intersection(with:) پشتیبانی میکند که برای منطق رزرو (بررسی تداخل تاریخها) مفید است.
DateIntervalFormatter خروجی را از طریق ویژگی locale بومیسازی میکند. به طور پیشفرض از Locale.current — locale دستگاه استفاده میشود. برای نمایش بازهها به زبان دیگر (مثلاً محتوای انگلیسی در رابط فارسی)، locale را به صراحت تنظیم کنید. برخلاف DateFormatter، DateIntervalFormatter برای دادههای سرور نیاز به تنظیم Locale ندارد — همیشه از منطق گروهبندی داخلی خود مبتنی بر CLDR استفاده میکند.
تفاوتهای زبانی در قالببندی بازههای تاریخ بسیار پیچیدهتر از تاریخهای تکی است. انگلیسی از خط تیره ساده استفاده میکند: Jul 21–25. فارسی — از حرف اضافه «تا»: از ۲۱ تا ۲۵ ژوئیه. فرانسوی — از «au»: du 21 au 25 juillet. آلمانی — از نقطه بعد از عدد و خط تیره: 21.–25. Juli. ژاپنی — از خط فاصله بدون حرف اضافه: Jul 21–25. DateIntervalFormatter همه این گزینهها را پوشش میدهد.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
let start = Date()
let end = Date().addingTimeInterval(259200) // +۳ روز
let interval = DateInterval(start: start, end: end)
// نمایش localeهای مختلف
let localeIds = ["ru_RU", "en_US", "de_DE", "fr_FR", "ja_JP", "zh_CN"]
for localeId in localeIds {
formatter.locale = Locale(identifier: localeId)
print("\(localeId): \(formatter.string(from: interval))")
}
// بومیسازی برای بازههای زمانی
formatter.dateStyle = .none
formatter.timeStyle = .short
let todayStart = Date()
let todayEnd = Date().addingTimeInterval(3600)
let timeInterval = DateInterval(start: todayStart, end: todayEnd)
for localeId in ["ru_RU", "en_US", "de_DE"] {
formatter.locale = Locale(identifier: localeId)
print("\(localeId) زمان: \(formatter.string(from: timeInterval))")
}
ویژگیهای بومیسازی: برای زبان فارسی DateIntervalFormatter از حروف اضافه «از» و «تا» برای فرمتهای طولانی تاریخ استفاده میکند. برای فرمت کوتاه (short) — فقط خط تیره: ۲۱.۰۷–۲۵.۰۷.۲۰۲۴. برای فرمت کامل (full) — با ذکر روز هفته. انتخاب فرمت به زمینه بستگی دارد: برای لیست رزروها از .medium، برای نمای جزئیات از .long یا .full استفاده کنید.
DateIntervalFormatter جایگاه قالببندی بازههای تاریخ را پر میکند که کلاسهای دیگر Foundation پوشش نمیدهند. DateFormatter تاریخهای تکی، RelativeDateTimeFormatter — تاریخهای نسبی (پیش/بعد)، DateComponentsFormatter — مدت زمان (۲ ساعت ۳۰ دقیقه) را قالببندی میکند. هر یک از این کلاسها مسئله خود را حل میکنند و نمیتوان آنها را جایگزین یکدیگر کرد.
| کلاس | هدف | نمونه خروجی |
|---|---|---|
| DateIntervalFormatter | محدوده تاریخ | ۲۱–۲۵ ژوئیه ۲۰۲۴ |
| DateFormatter | تاریخ تکی | ۲۱ ژوئیه ۲۰۲۴ |
| RelativeDateTimeFormatter | زمان نسبی | ۳ روز پیش |
| DateComponentsFormatter | مدت زمان | ۲ ساعت ۳۰ دقیقه |
| ISO8601DateFormatter | فرمت ISO 8601 | ۲۰۲۴-۰۷-۲۱T۱۴:۳۰:۰۰Z |
چه زمانی از DateIntervalFormatter استفاده کنیم: برای نمایش بازههای تاریخ در UI — رزرو هتل، رویدادها، فیلتر بر اساس تاریخ، تاریخچه عملیات. برای محاسبه مدت زمان بین تاریخها از DateComponentsFormatter استفاده کنید، نه DateIntervalFormatter — دومی برای نمایش مدت زمان طراحی نشده است. DateFormatter را فقط برای تاریخهای تکی استفاده کنید، نه برای چسباندن دو تاریخ قالببندی شده از طریق الحاق رشته — این منجر به از دست رفتن بومیسازی جداکننده میشود.
لبه: DateIntervalFormatter از نمایش بازههای باز (بدون تاریخ پایان) پشتیبانی نمیکند. اگر پایان بازه نامشخص است (مثلاً «از ۲۱ ژوئیه»)، برای فارسی از DateFormatter با حرف اضافه «از» استفاده کنید. DateIntervalFormatter همچنین از بازههای با ذکر زمان برای روزهای مختلف پشتیبانی نمیکند — زمان برای هر تاریخ جداگانه اعمال میشود که ممکن است برای بازههای کوتاه اضافی به نظر برسد.
سوالات متداول
DateIntervalFormatter — کلاس Foundation برای قالببندی محدودههای تاریخ به رشتههای بومیسازی شده. از iOS 8 در دسترس است، به طور خودکار اجزای تکراری (ماه، سال) را گروهبندی میکند و جداکننده مناسب زبان را انتخاب میکند.
اجزا را مقایسه میکند از سال تا روز. اگر سال مطابقت دارد — یک بار نمایش داده میشود. اگر ماه مطابقت دارد — یک بار نمایش داده میشود. روزهای متفاوت به عنوان بازه نمایش داده میشوند. این باعث میشود «۲۱–۲۵ ژوئیه ۲۰۲۴» به جای «۲۱ ژوئیه ۲۰۲۴ – ۲۵ ژوئیه ۲۰۲۴».
خیر، جداکننده توسط locale تعیین میشود و از طریق API قابل تنظیم نیست. برای جداکننده سفارشی (مثلاً «الی» به جای «تا»)، هر تاریخ را با DateFormatter جداگانه قالببندی کرده و رشتهها را به صورت دستی بچسبانید.
DateIntervalFormatter یک بازه تاریخ (دو تاریخ) را به عنوان یک کل واحد با گروهبندی اجزا قالببندی میکند. DateFormatter یک تاریخ تکی را قالببندی میکند. برای بازهها همیشه از DateIntervalFormatter استفاده کنید — این بومیسازی صحیح جداکننده را تضمین میکند.
به طور خودکار — DateIntervalFormatter تشخیص میدهد که سالها متفاوت هستند و تاریخهای کامل را برای هر دو انتها نمایش میدهد: «۲۵ دسامبر ۲۰۲۴ – ۵ ژانویه ۲۰۲۵». هیچ تنظیم اضافی لازم نیست، فقط کافی است dateStyle تنظیم شود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید