DateIntervalFormatter هي فئة من Foundation في iOS وmacOS مصممة لتنسيق نطاقات التاريخ إلى سلاسل مترجمة: «21–25 يوليو 2024»، «من 21 إلى 25 يوليو 2024» أو «Jul 21–25, 2024». وفقًا لـ Apple Developer Documentation, 2024، يقوم DateIntervalFormatter تلقائيًا بتحديد مكونات التاريخ التي يجب تكرارها (إذا كان النطاق ضمن شهر واحد، يظهر الشهر مرة واحدة)، ويقوم بتوطين الفواصل وترتيب الكلمات. على عكس الدمج اليدوي لتاريخين منسقين، تراعي هذه الفئة القواعد النحوية للغة. الفئة متاحة منذ iOS 8 وmacOS 10.10.
النقاط الرئيسية
DateIntervalFormatter هي فئة فرعية من Formatter في Foundation تأخذ كائن DateInterval (نطاق بين تاريخين) وتعيد سلسلة مترجمة تصف ذلك النطاق. على سبيل المثال، للنطاق من 21 إلى 25 يوليو 2024، ستكون النتيجة «21–25 يوليو 2024» لـ ar_SA. تقوم الفئة بتجميع العناصر المتكررة بذكاء: إذا كان كلا التاريخين في نفس الشهر، يظهر اسم الشهر مرة واحدة.
القيمة الرئيسية لـ DateIntervalFormatter هي المعالجة التلقائية لقواعد النطاقات. عند التنسيق اليدوي، سيتعين على المطور مقارنة شهر/سنة البداية والنهاية، واختيار فاصل (شرطة، «إلى»، «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 يعتمد على تحليل تاريخين يشكلان نطاقًا واختيار التمثيل النصي الأمثل مع مراعاة الإعدادات المحلية. تقوم الفئة بمقارنة مكونات التاريخ (السنة، الشهر، اليوم) واتخاذ قرارات التجميع: إذا كانت السنة نفسها، تظهر مرة واحدة؛ إذا كان الشهر نفسه، يظهر مرة واحدة؛ إذا اختلفت الأيام، يظهر نطاق الأيام.
| النطاق | ar_SA |
|---|---|
| يوم واحد | 21 يوليو 2024 |
| ضمن الشهر | 21–25 يوليو 2024 |
| أشهر مختلفة | 21 يوليو – 5 أغسطس 2024 |
| سنوات مختلفة | 25 ديسمبر 2024 – 5 يناير 2025 |
| مع الوقت | 21 يوليو 2024، 14:30–16:45 |
منطق التجميع منفذ بناءً على قوالب CLDR. يتحقق المنسق من مساواة كل مكون تاريخ (Calendar.Component: year, month, day) بالترتيب من الأكبر إلى الأصغر. بمجرد اختلاف مكون، تظهر جميع المكونات الأصغر لكلا التاريخين. على سبيل المثال، لـ 21–25 يوليو: السنة متطابقة، الشهر متطابق، اليوم مختلف ← يظهر الشهر مرة واحدة، وتظهر الأيام لكل تاريخ.
ملاحظة مهمة: DateIntervalFormatter لا يدعم تخصيص الفاصل عبر API. يتم تحديد الفاصل بواسطة الإعدادات المحلية ولا يمكن تجاوزه. إذا كان هناك حاجة إلى فاصل غير قياسي (على سبيل المثال، «حتى» بدلاً من «إلى»)، فسيلزم تنسيق التواريخ يدويًا باستخدام DateFormatter ودمج السلاسل بفاصل مخصص.
DateIntervalFormatter يوفر مجموعتين من الأنماط: dateStyle وtimeStyle لكل طرف من النطاق. تعمل هذه الأنماط بشكل مشابه لـ DateFormatter: .none يخفي المكون، .short يعطي تنسيقًا قصيرًا (21/07/2024)، .medium (21 يول 2024)، .long (21 يوليو 2024)، .full (الأحد، 21 يوليو 2024). من خلال الجمع بين dateStyle وtimeStyle، يمكن تحقيق مستويات مختلفة من التفاصيل.
مهم: dateStyle وtimeStyle يتم تطبيقهما على طرفي النطاق بالتساوي. لا يمكن تعيين أنماط مختلفة للبداية والنهاية (مثل .medium للبداية و.short للنهاية). إذا كانت هناك حاجة لأنماط مختلفة، فيجب تنسيق كل تاريخ باستخدام DateFormatter منفصل ودمج النتائج.
import Foundation
let formatter = DateIntervalFormatter()
// تركيبات أنماط مختلفة
let startDate = Date()
let endDate = Date().addingTimeInterval(345600) // +4 أيام
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+). بعد التنسيق، تكون النتيجة جاهزة للعرض في واجهة المستخدم دون معالجة إضافية.
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 وحجوزات التقويم: في تطبيقات الحجز (الفنادق، التذاكر)، تعتبر فترات التاريخ عنصرًا رئيسيًا في واجهة المستخدم. يعالج DateIntervalFormatter بشكل صحيح الفترات عبر السنوات (مثل 28 ديسمبر إلى 3 يناير)، مع تجميع الشهر والسنة لكل تاريخ على حدة. لمثل هذه السيناريوهات، يُوصى باستخدام 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)")
// الاستخدام مع إعدادات محلية مختلفة
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 بشكل صريح. على عكس DateFormatter، لا يتطلب DateIntervalFormatter تعيين locale لبيانات الخادم. فهو دائمًا يستخدم منطق التجميع الداخلي المستند إلى CLDR.
الاختلافات اللغوية في تنسيق فترات التاريخ أكثر تعقيدًا بشكل ملحوظ من التواريخ الفردية. تستخدم العربية حرف الجر «إلى»: من 21 إلى 25 يوليو. تستخدم الإنجليزية شرطة بسيطة: Jul 21–25. تستخدم الفرنسية حرف الجر «au»: du 21 au 25 juillet. تستخدم الألمانية نقطة بعد الرقم وشرطة: 21.–25. Juli. يغطي DateIntervalFormatter كل هذه الاختلافات.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
let start = Date()
let end = Date().addingTimeInterval(259200) // +3 أيام
let interval = DateInterval(start: start, end: end)
// عرض إعدادات محلية مختلفة
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 حرف الجر «إلى» للصيغ الطويلة. للصيغ القصيرة، يستخدم الشرطة. يعتمد اختيار التنسيق على السياق: لقائمة الحجوزات استخدم .medium، للعرض التفصيلي استخدم .long أو .full.
DateIntervalFormatter يملأ مجال تنسيق نطاقات التاريخ، الذي لا تغطيه فئات Foundation الأخرى. DateFormatter ينسق التواريخ الفردية، RelativeDateTimeFormatter ينسق التواريخ النسبية (منذ/بعد)، DateComponentsFormatter ينسق المدة (ساعتان 30 دقيقة). كل من هذه الفئات تحل مهمة محددة ولا يمكن استخدامها بالتبادل.
| الفئة | الغرض | مثال الإخراج |
|---|---|---|
| DateIntervalFormatter | نطاق تاريخ | 21–25 يوليو 2024 |
| DateFormatter | تاريخ فردي | 21 يوليو 2024 |
| RelativeDateTimeFormatter | وقت نسبي | منذ 3 أيام |
| DateComponentsFormatter | مدة | ساعتان 30 دقيقة |
| ISO8601DateFormatter | تنسيق ISO 8601 | 2024-07-21T14:30:00Z |
متى تستخدم DateIntervalFormatter: لعرض نطاقات التاريخ في واجهة المستخدم — حجوزات الفنادق، الأحداث، التصفية حسب التواريخ، سجل العمليات. لحساب المدة بين التواريخ، استخدم DateComponentsFormatter وليس DateIntervalFormatter، لأن الأخير غير مصمم لعرض المدة. يجب استخدام DateFormatter فقط للتواريخ الفردية، وليس لدمج تاريخين منسقين عبر تسلسل السلاسل، لأن هذا يؤدي إلى فقدان توطين الفاصل.
حالة طرفية: DateIntervalFormatter لا يدعم عرض الفترات المفتوحة (بدون تاريخ انتهاء). إذا كانت نهاية النطاق غير معروفة (مثل «من 21 يوليو»)، استخدم DateFormatter مع حرف الجر «من». أيضًا، DateIntervalFormatter لا يدعم الفترات مع وقت محدد لأيام مختلفة. يتم تطبيق الوقت على كل تاريخ على حدة، مما قد يبدو زائدًا عن الحاجة للفترات القصيرة.
الأسئلة الشائعة
DateIntervalFormatter هي فئة Foundation لتنسيق نطاقات التاريخ في سلاسل مترجمة. متاحة منذ iOS 8، تقوم تلقائيًا بتجميع المكونات المتكررة (الشهر، السنة) واختيار الفاصل الصحيح للغة.
يقوم بمقارنة المكونات من السنة إلى اليوم. إذا تطابقت السنة، تظهر مرة واحدة. إذا تطابق الشهر، يظهر مرة واحدة. الأيام المختلفة تظهر كنطاق. هذا يعطي «21–25 يوليو 2024» بدلاً من «21 يوليو 2024 – 25 يوليو 2024».
لا، يتم تحديد الفاصل بواسطة الإعدادات المحلية ولا يمكن تخصيصه عبر API. لفاصل مخصص (مثل «حتى» بدلاً من «إلى»)، قم بتنسيق كل تاريخ باستخدام DateFormatter منفصل ودمج السلاسل يدويًا.
DateIntervalFormatter ينسق نطاق تاريخ (تاريخين) كوحدة واحدة مع تجميع المكونات. DateFormatter ينسق تاريخًا فرديًا. للنطاقات، استخدم دائمًا DateIntervalFormatter لأنه يوفر توطينًا صحيحًا للفاصل.
تلقائيًا — يكتشف DateIntervalFormatter أن السنوات مختلفة ويعرض التواريخ الكاملة لكلا الطرفين: «25 ديسمبر 2024 – 5 يناير 2025». لا يلزم أي تكوين إضافي، فقط قم بتعيين dateStyle.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.