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 — بدون تنظیم 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: عدم وابستگی به locale (تجزیه روی هر دستگاهی یکسان کار می‌کند)، پشتیبانی داخلی از کسری ثانیه (با هر تعداد رقم اعشار) و تعیین خودکار فرمت بر اساس گزینه‌های ارسال شده. این کلاس همچنین پسوند Z (نشان‌دهنده UTC)، مناطق زمانی در قالب +HH:mm و دقت کاهش‌یافته (فقط تاریخ بدون زمان) را به درستی پردازش می‌کند.

طبق ISO Specification (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کسری از ثانیه (تا ۳ رقم).123
.withFractionalSecondsکسری از ثانیه (هر دقتی).123456
.withTimeZoneمنطقه زمانی+03:00
.withColonSeparatorInTimeZoneجداساز : در منطقه زمانی+03:00 (به جای +0300)
.withInternetDateTimeفرمت کامل (date + time + tz)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

// پیکربندی ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// ترکیب‌های مختلف گزینه‌های فرمت
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("تاریخ: \(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)")

// تجزیه رشته با میلی‌ثانیه
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
    print("تجزیه شد: \(parsed)")
}

ISO8601DateFormatter در Swift: نمونه کد

استفاده پایه ISO8601DateFormatter به ایجاد نمونه، تنظیم timeZone (توصیه می‌شود UTC برای داده‌های سرور) و formatOptions خلاصه می‌شود، پس از آن می‌توان string(from:) برای قالب‌بندی و date(from:) برای تجزیه فراخوانی کرد. برخلاف DateFormatter، نیازی به نگرانی درباره Locale نیست — کلاس تنظیمات منطقه‌ای را نادیده می‌گیرد.

swift
import Foundation

let formatter = ISO8601DateFormatter()

// تجزیه فرمت‌های مختلف ISO 8601
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("تجزیه شد '\(str)': \(autoParsed)")
    } else {
        // برای رشته‌های فقط تاریخ از withFullDate استفاده کنید
        formatter.formatOptions = [.withFullDate]
        if let fallback = formatter.date(from: str) {
            print("بازگشت تجزیه شد '\(str)': \(fallback)")
        }
        formatter.formatOptions = [.withInternetDateTime]
    }
}

// سریال‌سازی به RFC 3339 (API GitHub)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")

تجزیه تاریخ‌های دارای کسری ثانیه با طول متغیر — ویژگی بسیاری از APIهای مدرن. سرور می‌تواند هم 2024-07-21T14:30:00.123Z (۳ رقم) و هم 2024-07-21T14:30:00.123456Z (۶ رقم) ارسال کند. ISO8601DateFormatter با گزینه .withFractionalSeconds هر دو گزینه را به درستی پردازش می‌کند، در حالی که DateFormatter با dateFormat = “yyyy-MM-dd’T’HH:mm:ss.SSSZ” فقط میلی‌ثانیه‌های سه رقمی را پردازش می‌کند.

swift
import Foundation

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

// دقت مختلف کسری ثانیه
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)")
    }
}

// از withMilliseconds استفاده کنید (فقط ۳ رقم)
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("با میلی‌ثانیه: \(milliParsed)")

تست تجزیه همه گزینه‌ها: کد بالا نشان می‌دهد که ISO8601DateFormatter با .withFractionalSeconds کسری ثانیه با هر طولی از ۱ تا ۹ رقم را با موفقیت پردازش می‌کند. این برای سازگاری با پلتفرم‌های مختلف سرور مهم است: .NET اغلب ۷ رقم (تیک‌های ۱۰۰ نانوثانیه)، Python — ۶، Java — ۳ یا ۹ بسته به نسخه تولید می‌کند.

مقایسه با DateFormatter برای ISO 8601

DateFormatter نیز می‌تواند ISO 8601 را تجزیه کند، اما نیاز به تنظیم دستی dateFormat، locale و timeZone دارد. مشکل اصلی این است که DateFormatter به Locale وابسته است و اگر en_US_POSIX تنظیم نشود، تجزیه ممکن است برای کاربران مناطق با فرمت‌های تاریخ غیراستاندارد خراب شود. ISO8601DateFormatter این مشکل را در سطح معماری حل می‌کند: از Locale استفاده نمی‌کند.

پارامترISO8601DateFormatterDateFormatter
تنظیم Localeنیاز ندارد (نادیده می‌گیرد)en_US_POSIX اجباری
DateFormatخودکار (از طریق گزینه‌ها)رشته format دستی
ثانیه‌های کسریهر دقتی (.withFractionalSeconds)SSS ثابت
پسوند Zبه درستی پردازش می‌کنداز طریق dateFormat
کاراییبالاتر (تخصصی)پایین‌تر (عمومی)
استانداردفقط ISO 8601هر فرمتی
نسخه iOSiOS 10+iOS 2+

چه زمانی از DateFormatter استفاده کنیم: اگر نیاز به قالب‌بندی تاریخ در قالبی غیر از ISO 8601 دارید (مثلاً «۲۱ ژوئیه ۲۰۲۴» برای UI) یا اگر پشتیبانی از iOS 9 و قدیمی‌تر مورد نیاز است. برای همه وظایف تبادل تاریخ با سرور از ISO8601DateFormatter استفاده کنید — ایمن‌تر، کارآمدتر و با کد کمتر است. DateFormatter برای ISO 8601 منبع اشکالات بالقوه مربوط به locale و تنظیمات منطقه‌ای است.

مهاجرت از DateFormatter به ISO8601DateFormatter: ایجاد DateFormatter + تنظیم dateFormat + locale + timeZone را با ایجاد ISO8601DateFormatter + تنظیم formatOptions + timeZone جایگزین کنید. تجزیه رشته از طریق date(from:) بدون تغییر باقی می‌ماند. برای سازگاری عقب‌گرد، می‌توان از #available(iOS 10, *) با fallback روی DateFormatter استفاده کرد.

خطاهای رایج هنگام تجزیه ISO 8601

فراموش کردن تنظیم formatOptions باعث می‌شود formatter از مقدار پیش‌فرض — .withInternetDateTime استفاده کند. اگر سرور فقط تاریخ بدون زمان ارسال کند (2024-07-21)، تجزیه nil برمی‌گرداند. همیشه بررسی کنید که formatOptions همه فرمت‌های ممکنی که از سرور می‌آیند را پوشش می‌دهد. برای API با فرمت‌های متغیر، از تلاش‌های fallback با ترکیب‌های مختلف گزینه‌ها استفاده کنید.

اشتباه گرفتن withMilliseconds و withFractionalSeconds — خطای رایج هنگام تجزیه تاریخ‌های دارای کسری ثانیه. withMilliseconds دقیقاً ۳ رقم اعشار انتظار دارد. اگر سرور ۶ رقم (میکروثانیه) ارسال کند، تجزیه با withMilliseconds با خطا مواجه می‌شود. برای سازگاری با هر تعداد رقم از .withFractionalSeconds استفاده کنید. .withFractionalSeconds در iOS 13 ظاهر شد؛ برای نسخه‌های قدیمی‌تر از DateFormatter با dateFormat استفاده کنید.

نادیده گرفتن منطقه زمانی — مشکل رایج دیگر. اگر سرور تاریخ را با منطقه زمانی ارسال کند (+03:00) و formatter روی UTC تنظیم شده باشد، تجزیه خراب نمی‌شود اما نتیجه به UTC خواهد بود. توسعه‌دهندگان اغلب انتظار دارند که Date منطقه زمانی را حفظ کند، اما Date یک لحظه مطلق در زمان است و اطلاعات منطقه زمانی را ذخیره نمی‌کند. برای نمایش صحیح، منطقه زمانی را جداگانه ذخیره کنید یا از ISO8601DateFormatter با timeZone درست استفاده کنید.

طبق Apple Forum (2024)، حدود ۲۰٪ سوالات مربوط به 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 استفاده کنید — از ۱ تا ۹ رقم اعشار را پشتیبانی می‌کند. اگر دقت می‌تواند متغیر باشد از .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 کسری ثانیه را با هر دقتی پردازش می‌کند (۱ – ۹ رقم)
  • DateFormatter بازنده است در کارایی، امنیت و سادگی برای وظایف ISO 8601
  • اشتباه گرفتن گزینه‌ها — withMilliseconds و withFractionalSeconds قابل جایگزینی نیستند
  • فرمت بدون ثانیه (2024-07-21T14:30+03:00) پشتیبانی نمی‌شود — DateFormatter نیاز است

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید