ISO8601DateFormatter: المفاهيم الرئيسية وتنسيق ISO 8601

المؤلف: IT Sectr نُشر: 2026-07-13 وقت القراءة: 9 دق

ISO8601DateFormatter هي فئة Foundation في iOS وmacOS مصممة لتنسيق وتحليل التواريخ وفق المعيار الدولي ISO 8601. وفقاً لـ Apple Developer Documentation, 2024، ISO8601DateFormatter يعالج تلقائياً التنسيقات مع الميلي ثانية والمناطق الزمنية وأجزاء الثانية دون الحاجة لتعيين DateFormat يدوياً. على عكس DateFormatter، هذه الفئة لا تعتمد على Locale أو TimeZone — فهي تعمل بدقة وفقاً لمواصفات ISO 8601، مما يجعلها مثالية لتبادل التواريخ بين الخادم والعميل. الفئة متاحة بدءاً من iOS 10 وmacOS 10.12.

الخلاصة

  • ISO8601DateFormatter — فئة Foundation لتنسيق التواريخ وفق معيار ISO 8601
  • لا يتطلب DateFormat — التنسيق يُحدد تلقائياً حسب إعدادات الخيارات
  • مستقل عن الإعدادات المحلية — يعمل بشكل متماثل على جميع الأجهزة دون ضبط Locale
  • دعم الميلي ثانية — يعالج أجزاء الثانية بأي دقة (ثلاثة، ستة أو أكثر من الأرقام)
  • خيارات التنسيق — withFullDate، withTime، withMilliseconds، withTimeZone وغيرها تتحكم بمكونات الإخراج

ما هو ISO8601DateFormatter؟

ISO8601DateFormatter هو فئة فرعية متخصصة من Formatter في Foundation تنفذ التحويل ثنائي الاتجاه بين Date وسلاسل تنسيق ISO 8601. معيار ISO 8601 (International Standard for the Representation of Dates and Times) يحدد تنسيقاً دولياً لتبادل التواريخ والأوقات: 2024-07-21T14:30:00+00:00. على عكس DateFormatter، هذه الفئة لا تتطلب تحديد dateFormat وتحدد تلقائياً بنية السلسلة بناءً على الخيارات المعطاة.

المزايا الرئيسية لـ ISO8601DateFormatter مقارنة بـ DateFormatter: عدم الاعتماد على الإعدادات المحلية (التحليل يعمل بشكل متماثل على أي جهاز)، دعم مدمج لأجزاء الثانية (بأي عدد من المنازل العشرية) واكتشاف تلقائي للتنسيق حسب الخيارات الممررة. الفئة تتعامل أيضاً بشكل صحيح مع لاحقة Z (تعيين UTC)، المناطق الزمنية بتنسيق +HH:mm والدقة المخفضة (التاريخ فقط بدون وقت).

وفقاً لـ مواصفات ISO (ISO 8601-1:2019)، المعيار يدعم أربعة مستويات من الدقة: سنة (2024)، سنة-شهر (2024-07)، تاريخ كامل (2024-07-21) وتاريخ-وقت مع منطقة زمنية (2024-07-21T14:30:00+00:00). ISO8601DateFormatter يغطي جميع هذه المستويات من خلال مجموعة من خيارات التنسيق، مما يحرر المطور من بناء سلاسل dateFormat يدوياً.

كيف يعمل ISO8601DateFormatter في Foundation؟

مبدأ العمل لـ ISO8601DateFormatter يعتمد على مجموعة من خيارات البت (formatOptions)، كل منها يضم مكوناً محدداً للتاريخ أو الوقت في الإخراج. على سبيل المثال، الخيار .withFullDate يتضمن السنة والشهر واليوم؛ .withTime يتضمن الساعات والدقائق والثواني. بدمج الخيارات، يحصل المطور على مستوى الدقة المطلوب دون كتابة سلسلة dateFormat.

داخلياً، ISO8601DateFormatter يستخدم مكتبة ICU للتحليل، ولكن بقواعد ISO 8601 ثابتة. هذا يعني أنه يتجاهل إعدادات Locale وTimeZone على الجهاز — النتيجة دائماً قابلة للتنبؤ. لتعيين المنطقة الزمنية، تُستخدم الخاصية timeZone، والتي تكون قيمتها الافتراضية UTC. إذا تم تعيين timeZone إلى nil، يُستخدم الوقت المحلي للجهاز.

خيارالوصفمثال الإخراج
.withFullDateالسنة، الشهر، اليوم2024-07-21
.withTimeالساعات، الدقائق، الثواني14:30:00
.withMillisecondsأجزاء الثانية (حتى 3 أرقام).123
.withFractionalSecondsأجزاء الثانية (أي دقة).123456
.withTimeZoneالمنطقة الزمنية+03:00
.withColonSeparatorInTimeZoneفاصل النقطتين في المنطقة الزمنية+03:00 (مقابل +0300)
.withInternetDateTimeالتنسيق الكامل (تاريخ + وقت + منطقة)2024-07-21T14:30:00+00:00

دمج الخيارات: .withInternetDateTime مكافئ لدمج .withFullDate و .withTime و .withTimeZone. لتحليل السلاسل مع الميلي ثانية، أضف .withFractionalSeconds. من المهم تذكر أن .withMilliseconds يحد أجزاء الثانية إلى ثلاثة أرقام، بينما .withFractionalSeconds يدعم أي دقة — من رقم إلى تسعة أرقام بعد الفاصلة العشرية.

خيارات تنسيق ISO 8601

خيارات التنسيق لـ ISO8601DateFormatter تنقسم إلى ثلاث مجموعات: مكونات التاريخ (withFullDate، withYear، withMonth، withDay، withWeekOfYear)، مكونات الوقت (withTime، withHours، withMinutes، withSeconds) وإعدادات إضافية (withMilliseconds، withFractionalSeconds، withTimeZone، withColonSeparatorInTimeZone، withDashSeparatorInDate، withFullTime). بدمجها، يمكن الحصول على أي تنسيق فرعي تقريباً من ISO 8601.

المجموعات الرئيسية للخيارات

  • .withFullDate — تاريخ فقط: 2024-07-21. لتحليل سلاسل YYYY-MM-DD
  • .withFullDate + .withTime — تاريخ ووقت بدون منطقة زمنية: 2024-07-21T14:30:00
  • .withInternetDateTime — تنسيق كامل: 2024-07-21T14:30:00Z أو 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — مع أجزاء الثانية: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — تنسيق كامل بدون نقطتين في tz: 2024-07-21T14:30:00+0300

فارق مهم: .withFractionalSeconds و .withMilliseconds متنافيان — إذا تم تعيين كليهما، يتم تطبيق .withFractionalSeconds. لتحليل الميلي ثانية من بيانات الخادم، يُوصى باستخدام .withFractionalSeconds، لأن العديد من الخوادم ترسل أجزاء الثانية بثلاثة أو ستة أو تسعة أرقام، و .withFractionalSeconds يعالج أي طول.

swift
import Foundation

// Configure ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// Different format option combinations
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Date: \(dateOnly)")

formatter.formatOptions = [.withFullDate, .withTime]
let dateTime = formatter.string(from: Date())
print("DateTime: \(dateTime)")

formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let full = formatter.string(from: Date())
print("Full: \(full)")

// Parse string with milliseconds
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
    print("Parsed: \(parsed)")
}

ISO8601DateFormatter في Swift: أمثلة برمجية

الاستخدام الأساسي لـ ISO8601DateFormatter يتلخص في إنشاء مثيل، ضبط timeZone (يُوصى بـ UTC لبيانات الخادم) و formatOptions، بعد ذلك يمكن استدعاء string(from:) للتنسيق و date(from:) للتحليل. على عكس DateFormatter، لا داعي للقلق بشأن Locale — الفئة تتجاهل الإعدادات الإقليمية.

swift
import Foundation

let formatter = ISO8601DateFormatter()

// Parse different ISO 8601 formats
let strings: [String] = [
    "2024-07-21T14:30:00Z",
    "2024-07-21T14:30:00+03:00",
    "2024-07-21T14:30:00.123Z",
    "2024-07-21"
]

for str in strings {
    if let autoParsed = formatter.date(from: str) {
        print("Parsed '\(str)': \(autoParsed)")
    } else {
        // Use withFullDate for date-only strings
        formatter.formatOptions = [.withFullDate]
        if let fallback = formatter.date(from: str) {
            print("Fallback parsed '\(str)': \(fallback)")
        }
        formatter.formatOptions = [.withInternetDateTime]
    }
}

// Serialize to RFC 3339 (GitHub API)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")

تحليل التواريخ بأجزاء ثانية متغيرة الطول — ميزة للعديد من API الحديثة. قد يرسل الخادم إما 2024-07-21T14:30:00.123Z (3 أرقام) أو 2024-07-21T14:30:00.123456Z (6 أرقام). ISO8601DateFormatter مع خيار .withFractionalSeconds سيعالج كلا الحالتين بشكل صحيح، بينما DateFormatter مع dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" سيعالج فقط الميلي ثانية ثلاثية الأرقام.

swift
import Foundation

let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withFractionalSeconds
]

// Different fractional second precision
let variants: [String] = [
    "2024-07-21T14:30:00.1Z",
    "2024-07-21T14:30:00.12Z",
    "2024-07-21T14:30:00.123Z",
    "2024-07-21T14:30:00.123456Z",
    "2024-07-21T14:30:00.123456789Z"
]

for variant in variants {
    if let parsed = variantFormatter.date(from: variant) {
        print("OK: \(variant) -> \(parsed)")
    } else {
        print("FAIL: \(variant)")
    }
}

// Use withMilliseconds (3 digits only)
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("With milliseconds: \(milliParsed)")

اختبار تحليل جميع المتغيرات: الكود المعروض يوضح أن ISO8601DateFormatter مع .withFractionalSeconds يعالج بنجاح أجزاء الثانية بأي طول من 1 إلى 9 أرقام. هذا مهم للتوافق مع منصات الخادم المختلفة: .NET غالباً ما يولد 7 أرقام (تكات 100 نانوثانية)، Python — 6، Java — 3 أو 9 حسب الإصدار.

مقارنة مع DateFormatter لـ ISO 8601

DateFormatter يمكنه أيضاً تحليل ISO 8601، لكنه يتطلب ضبطاً يدوياً لـ dateFormat و locale و timeZone. المشكلة الرئيسية هي أن DateFormatter يعتمد على Locale، وإذا لم يتم تعيين en_US_POSIX، قد يفشل التحليل للمستخدمين من المناطق ذات تنسيقات التاريخ غير القياسية. ISO8601DateFormatter يحل هذه المشكلة على مستوى البنية: فهو لا يستخدم Locale.

المعلمةISO8601DateFormatterDateFormatter
ضبط Localeغير مطلوب (يتجاهله)en_US_POSIX إلزامي
DateFormatتلقائي (عبر خيارات)سلسلة تنسيق يدوية
أجزاء الثانيةأي دقة (.withFractionalSeconds)SSS ثابت
لاحقة Zيعالج بشكل صحيحعبر dateFormat
الأداءأعلى (متخصص)أقل (عام)
المعيارISO 8601 فقطأي تنسيق
إصدار iOSiOS 10+iOS 2+

متى تستخدم DateFormatter: إذا كنت بحاجة لتنسيق تاريخ بتنسيق غير ISO 8601 (مثل "21 يوليو 2024" لواجهة المستخدم) أو إذا كنت بحاجة لدعم iOS 9 والإصدارات الأقدم. لجميع مهام تبادل التواريخ بين الخادم والعميل، استخدم ISO8601DateFormatter — إنه أكثر أماناً وأداءً ويتطلب كوداً أقل. DateFormatter لـ ISO 8601 هو مصدر أخطاء محتملة تتعلق بالإعدادات المحلية والإقليمية.

الترحيل من DateFormatter إلى ISO8601DateFormatter: استبدل إنشاء DateFormatter + ضبط dateFormat + locale + timeZone بإنشاء ISO8601DateFormatter + ضبط formatOptions + timeZone. تحليل السلسلة يبقى دون تغيير عبر date(from:). للتوافق مع الإصدارات السابقة، يمكن استخدام #available(iOS 10, *) مع fallback إلى DateFormatter.

الأخطاء الشائعة عند تحليل ISO 8601

ضبط formatOptions المنسي يؤدي إلى استخدام القيمة الافتراضية — .withInternetDateTime. إذا أرسل الخادم تاريخاً بدون وقت (2024-07-21)، سيعيد التحليل nil. تحقق دائماً من أن formatOptions تغطي جميع التنسيقات الممكنة التي قد تصل من الخادم. لـ API ذات التنسيقات المتغيرة، استخدم محاولات fallback بمجموعات مختلفة من الخيارات.

الخلط بين withMilliseconds و withFractionalSeconds — خطأ شائع عند تحليل التواريخ بأجزاء الثانية. withMilliseconds يتوقع بالضبط 3 أرقام بعد الفاصلة العشرية. إذا أرسل الخادم 6 أرقام (ميكروثانية)، سيفشل التحليل مع withMilliseconds. استخدم .withFractionalSeconds للتوافق مع أي عدد من الأرقام. .withFractionalSeconds ظهر في iOS 13؛ للإصدارات الأقدم، استخدم DateFormatter مع dateFormat.

تجاهل المنطقة الزمنية — مشكلة شائعة أخرى. إذا أرسل الخادم تاريخاً بمنطقة زمنية (+03:00) وكان formatter مضبوطاً على UTC، التحليل لن يفشل، لكن النتيجة ستكون في UTC. غالباً ما يتوقع المطورون أن Date يحتفظ بالمنطقة الزمنية، لكن Date هي لحظة زمنية مطلقة — لا تخزن معلومات المنطقة الزمنية. للعرض الصحيح، احفظ المنطقة الزمنية بشكل منفصل أو استخدم ISO8601DateFormatter مع timeZone الصحيح.

وفقاً لمنتدى Apple (2024)، حوالي 20% من الأسئلة حول ISO8601DateFormatter تتعلق بالتنسيق حيث الثواني اختيارية. معيار ISO 8601 يسمح بتنسيق بدون ثوانٍ: 2024-07-21T14:30+03:00. ISO8601DateFormatter مع .withInternetDateTime لا يدعم هذا التنسيق — لتحليله ستحتاج DateFormatter مع dateFormat = "yyyy-MM-dd'T'HH:mmZ". هذا القيد مهم للنظر فيه عند العمل مع API التي تستخدم تنسيق الوقت المختصر.

الأسئلة الشائعة

ما هو ISO8601DateFormatter؟

ISO8601DateFormatter — فئة Foundation متخصصة لتنسيق وتحليل التواريخ بتنسيق ISO 8601، متاحة منذ iOS 10. تعالج تلقائياً التنسيقات القياسية دون ضبط dateFormat يدوياً.

ما الفرق بين ISO8601DateFormatter و DateFormatter؟

ISO8601DateFormatter لا يعتمد على Locale، يستخدم خيارات بدلاً من dateFormat ويعالج بشكل صحيح أجزاء الثانية بأي طول. DateFormatter شامل لكنه يتطلب ضبطاً يدوياً وعرضة للأخطاء المتعلقة بالإعدادات الإقليمية.

كيف نتعامل مع أجزاء الثانية متغيرة الطول؟

استخدم خيار .withFractionalSeconds — يدعم من 1 إلى 9 أرقام بعد الفاصلة العشرية. لا تستخدم .withMilliseconds إذا كانت الدقة قد تختلف. .withFractionalSeconds متاح منذ iOS 13.

ما المنطقة الزمنية التي يستخدمها ISO8601DateFormatter؟

UTC افتراضياً. لتغييرها، اضبط الخاصية timeZone. إذا كان timeZone = nil، يُستخدم الوقت المحلي للجهاز. عند تحليل سلسلة بمنطقة زمنية صريحة بتنسيق +HH:MM، يراعيها formatter تلقائياً.

لماذا تحليل تاريخ بدون وقت يعيد nil؟

لأن formatOptions الافتراضي هو .withInternetDateTime، الذي يتوقع تاريخ + وقت + منطقة زمنية. لتحليل تاريخ فقط، اضبط formatOptions = [.withFullDate]. لدعم كلا الخيارين، استخدم fallback بخيارات مختلفة.

الملخص

  • ISO8601DateFormatter — فئة متخصصة لـ ISO 8601، أكثر أماناً وبساطة من DateFormatter
  • خيارات التنسيق تحل محل dateFormat اليدوي — ادمج .withFullDate، .withTime، .withTimeZone
  • مستقل عن Locale — التحليل يعمل بشكل متماثل على جميع الأجهزة دون ضبط locale
  • .withFractionalSeconds يعالج أجزاء الثانية بأي دقة (1–9 أرقام)
  • DateFormatter أقل كفاءة في الأداء والأمان والبساطة لمهام ISO 8601
  • الخلط بين الخيارات — withMilliseconds و withFractionalSeconds غير قابلين للتبديل
  • التنسيق بدون ثوانٍ (2024-07-21T14:30+03:00) غير مدعوم — يحتاج DateFormatter

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا