TimeZone — ما هو، كلاس Foundation والمناطق الزمنية

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

TimeZone هو كلاس Foundation في iOS و macOS يجرد معلومات المناطق الزمنية لتحويل الوقت بشكل صحيح بين المناطق الجغرافية. وفقًا لـ Apple Developer Documentation, 2024، يوفر TimeZone طرقًا للعمل مع معرفات المناطق الزمنية (IANA Time Zone Database)، والإزاحات بالنسبة لـ UTC، وقواعد التبديل إلى التوقيت الصيفي. يدمج الكلاس مع DateFormatter و Calendar، مما يضمن التطبيق التلقائي للمنطقة الزمنية الصحيحة عند تنسيق التواريخ. على عكس الحساب اليدوي للإزاحة، يقوم TimeZone بتحديث البيانات تلقائيًا عند تغيير المنطقة الزمنية للجهاز.

النقاط الرئيسية

  • TimeZone — كلاس Foundation للعمل مع المناطق الزمنية في iOS و macOS
  • IANA Time Zone Database — المصدر الرئيسي لمعرفات المناطق الزمنية (America/New_York، Europe/Moscow)
  • تصحيح تلقائي — يتعامل TimeZone مع التوقيت الصيفي دون كتابة كود إضافي
  • التكامل مع DateFormatter — يتم تطبيق المنطقة الزمنية تلقائيًا عند تنسيق التواريخ
  • ثلاثة أنواع — محلي (حالي)، ثابت (محدد بمعرف)، و UTC

ما هو TimeZone في Foundation؟

TimeZone هو نوع قيمة في Swift يوفر معلومات حول منطقة زمنية جغرافية: الإزاحة بالنسبة لـ UTC، الاسم، الاختصار، وقواعد التوقيت الصيفي. في Objective-C، يسمى الكلاس NSTimeZone. يعتمد كلا الكلاسين على IANA Time Zone Database (المعروفة أيضًا بقاعدة بيانات Olson)، والتي تحتوي على تاريخ تغييرات المناطق الزمنية منذ عام 1970.

يخزن كل مثيل TimeZone معرف المنطقة الزمنية (مثل Europe/Moscow)، والإزاحة الحالية بالثواني من UTC، وعلم isDaylightSavingTime، وتاريخ الانتقال التالي. المعرف هو المفتاح الأساسي: عند تهيئة TimeZone(identifier:)، يقوم النظام بتحميل السجل المقابل من قاعدة بيانات المناطق الزمنية للجهاز.

وفقًا لـ IANA (2024)، تحتوي قاعدة البيانات على أكثر من 600 معرف فريد للمناطق الزمنية. توزع Apple لقطة من قاعدة البيانات هذه مع كل إصدار من iOS و macOS، مما يضمن حسابات متسقة عبر جميع الأجهزة دون الحاجة إلى طلبات شبكة.

كيف يعمل TimeZone في iOS و macOS؟

بنية TimeZone في Foundation مبنية على نظام من مستويين: معرف المنطقة الزمنية (اسم قابل للقراءة البشرية) وتمثيله الرقمي (الإزاحة من UTC). يختار النظام تلقائيًا المنطقة الزمنية الحالية من إعدادات الجهاز، لكن يمكن للمطور تجاوزها لعمليات تنسيق محددة.

يرتبط TimeZone ارتباطًا وثيقًا بـ Calendar و DateFormatter. عند تنسيق تاريخ، يستخدم DateFormatter خاصية timeZone لمثيل TimeZone لتحويل لحظة زمنية مطلقة (Date) إلى تمثيل نصي في المنطقة الزمنية المطلوبة. إذا لم يتم تعيين timeZone، يتم استخدام المنطقة الزمنية الافتراضية للنظام — TimeZone.current.

أنواع مثيلات TimeZone

النوعالتهيئةالميزات
حاليTimeZone.currentيتم التحديث تلقائيًا عند تغيير المنطقة في الإعدادات، يتتبع التوقيت الصيفي
ثابتTimeZone(identifier:)مستقل عن منطقة الجهاز. يطبق المعرف المحدد باستمرار
UTCTimeZone(secondsFromGMT: 0)منطقة زمنية بدون تصحيح. المعرف: GMT
بإزاحة عشوائيةTimeZone(secondsFromGMT: 10800)إزاحة ثابتة بالثواني. لا تراعي التوقيت الصيفي

ملاحظة مهمة: TimeZone(identifier:) يُرجع nil للمعرفات غير المعروفة. هذا سبب شائع لتعطل التطبيق — ينسى المطورون معالجة القيمة الاختيارية عند تمرير معرف غير صالح من إدخال المستخدم. بالنسبة لمعرفات IANA، حالة الأحرف مهمة: Europe/Moscow صحيح، europe/moscow يُرجع nil.

تنسيقات معرفات المناطق الزمنية

IANA Time Zone Database تستخدم تنسيق «المنطقة/المدينة» (القارة/المدينة)، حيث المنطقة هي إحدى القارات (Africa، America، Asia، Atlantic، Australia، Europe، Indian، Pacific) أو محيط، والمدينة هي أكبر منطقة سكنية ضمن نطاق تغطية المنطقة الزمنية. يضمن هذا التنسيق تفرد المعرف وسهولة قراءته.

بالإضافة إلى التنسيق الرئيسي، يدعم TimeZone ثلاث طرق إضافية للتعريف: الاختصارات (MSK، EST، PST)، رموز المناطق الزمنية المكونة من ثلاثة أحرف (GMT، UTC)، والإزاحات الرقمية (+0300، -0500). ومع ذلك، فإن الاختصارات غامضة: EST يمكن أن تعني Eastern Standard Time (GMT-5) أو Eastern Summer Time (GMT+10) في أستراليا. توصي Apple باستخدام معرفات IANA فقط.

swift
import Foundation

// الحصول على جميع معرفات المناطق الزمنية المعروفة
let allIdentifiers: [String] = TimeZone.knownTimeZoneIdentifiers
print("إجمالي المناطق الزمنية: \(allIdentifiers.count)")

// تصفية حسب المنطقة
let europeZones = allIdentifiers.filter { $0.hasPrefix("Europe/") }
print("المناطق الزمنية الأوروبية: \(europeZones)")

// الاختصارات (غير موصى بها للإنتاج)
if let moscowTimeZone = TimeZone(abbreviation: "MSK") {
    print("ثواني MSK من GMT: \(moscowTimeZone.secondsFromGMT())")
}

// البحث عن معرف بواسطة الإزاحة
let utcPlus3 = TimeZone(secondsFromGMT: 10800)
print("المعرف: \(utcPlus3.identifier)")

الاختصارات في TimeZone.abbreviationDictionary تحتوي على اختصارات لجميع المناطق الزمنية المعروفة، لكن هذا القاموس لا يضمن التفرد: مفتاح PST قد يتوافق مع America/Los_Angeles أو Pacific/Pago_Pago. للكود الإنتاجي، استخدم دائمًا معرفات IANA.

التوقيت الصيفي و TimeZone

TimeZone يراعي تلقائيًا التبديل إلى التوقيت الصيفي (DST) لجميع المناطق التي يتم فيها تطبيقه. يستخدم النظام البيانات التاريخية من IANA Time Zone Database، والتي تتضمن تواريخ دقيقة للتحولات لكل منطقة زمنية. الخاصية isDaylightSavingTime تُرجع true إذا كانت المنطقة الزمنية حاليًا في التوقيت الصيفي.

تتيح طريقة nextDaylightSavingTimeTransition معرفة تاريخ الانتقال التالي، وهو مفيد لتخطيط الأحداث المستقبلية. هذه الوظيفة مهمة بشكل خاص للمناطق ذات التغييرات المتكررة في قواعد DST، مثل البرازيل أو المغرب — حتى عام 2024، كانت البرازيل تغير تواريخ الانتقال سنويًا، وكان الحساب اليدوي يؤدي إلى أخطاء في التطبيقات.

وفقًا لـ Apple WWDC 2023، تقوم مكتبة ICU (International Components for Unicode)، التي تشكل أساس Foundation، بتحديث بيانات DST مع كل تحديث لنظام iOS. يجب ألا تخزن التطبيقات بيانات التوقيت الصيفي في الذاكرة المؤقتة لأكثر من يوم واحد بعد تحديث النظام — فقد تتغير قاعدة بيانات IANA حتى بدون تحديث إصدار نظام التشغيل من خلال تعديلات المناطق الزمنية.

swift
import Foundation

// التحقق من DST لـ Europe/Moscow
let moscow = TimeZone(identifier: "Europe/Moscow")!
let now = Date()
let isMoscowDST = moscow.isDaylightSavingTime(for: now)
print("موسكو حاليًا في DST: \(isMoscowDST)")

// الحصول على تاريخ انتقال DST التالي
if let nextTransition = moscow.nextDaylightSavingTimeTransition(
    after: now
) {
    let dstOffset = moscow.daylightSavingTimeOffset(
        for: nextTransition
    )
    print("الانتقال التالي: \(nextTransition)، إزاحة DST: \(dstOffset)s")
}

// تحويل آمن مع مراعاة DST
let newYork = TimeZone(identifier: "America/New_York")!
let offsetNY = newYork.secondsFromGMT(for: now)
print("الإزاحة الحالية لنيويورك: \(offsetNY / 3600)h")

فارق دقيق حاسم: secondsFromGMT(for:) يراعي DST للتاريخ المحدد، بينما secondsFromGMT() ينطبق فقط على الوقت الحالي. عند تنسيق التواريخ التاريخية، استخدم دائمًا الإصدار مع معامل Date: secondsFromGMT(for: someHistoricalDate). يمكن أن يصل الفرق إلى 1–2 ساعة، وهو أمر حاسم للسجلات أو البيانات التاريخية.

TimeZone في Swift: أمثلة كود

تنسيق تاريخ بمنطقة زمنية محددة هو المهمة الأكثر شيوعًا عند العمل مع TimeZone. يستخدم DateFormatter خاصية timeZone لتحويل Date إلى سلسلة نصية. إذا لم يتم تعيين timeZone صراحةً، يستخدم المنسق TimeZone.current — المنطقة الزمنية المحددة على جهاز المستخدم، مما قد يؤدي إلى نتائج غير متوقعة لبيانات الخادم.

swift
import Foundation

// تنسيق التاريخ في منطقة زمنية محددة
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let tokyo = TimeZone(identifier: "Asia/Tokyo")!
formatter.timeZone = tokyo
let tokyoTime = formatter.string(from: Date())
print("وقت طوكيو: \(tokyoTime)")

// المعرفات المتاحة لاختيار المستخدم
let displayNames: [(String, String)] = TimeZone.knownTimeZoneIdentifiers
    .prefix(20)
    .map { ($0, TimeZone(identifier: $0)!.localizedName(
        for: .generic, locale: .current
    )) }

// مقارنة منطقتين زمنيتين
let london = TimeZone(identifier: "Europe/London")!
let difference = tokyo.secondsFromGMT(for: Date())
    - london.secondsFromGMT(for: Date())
print("الفرق طوكيو-لندن: \(difference / 3600)h")

// العمل مع قاموس الاختصارات
let knownAbbrevs = TimeZone.abbreviationDictionary
for (abbr, ident) in knownAbbrevs.sorted(by: { $0.key < $1.key }).prefix(5) {
    print("\(abbr) -> \(ident)")
}

اسم مترجم للمنطقة الزمنية عبر localizedName(for:locale:) يُرجع اسمًا قابلًا للقراءة البشرية باللغة المحددة. على سبيل المثال، بالنسبة لـ Europe/Moscow مع الإعدادات الإقليمية الروسية، يُرجع الأسلوب الاسم الروسي «Moskva»، ومع الإعدادات الإقليمية الإنجليزية — «Moscow Time». الأنماط المتاحة: .standard (الاسم القياسي)، .daylightSaving (التوقيت الصيفي)، و .shortGeneric (قصير).

swift
import Foundation

let paris = TimeZone(identifier: "Europe/Paris")!
let nameRU = paris.localizedName(
    for: .standard,
    locale: Locale(identifier: "ru_RU")
)
print("الاسم بالروسية: \(nameRU)")

// التحقق مما إذا كانت المنطقة في نفس اليوم
let isSameDay = Calendar.current.isDate(
    Date(),
    equalTo: Date(),
    toGranularity: .day
)
print("نفس اليوم عبر المناطق الزمنية: \(isSameDay)")

تسلسل معرف المنطقة الزمنية هو أفضل ممارسة لتخزين TimeZone في قواعد البيانات أو UserDefaults. احفظ المعرف (سلسلة نصية مثل Europe/Moscow)، وليس الإزاحة بالثواني أو الاختصار. يمكن أن تتغير الإزاحة مع تغييرات DST، والاختصارات غامضة. الاستعادة: TimeZone(identifier: savedString).

الأخطاء الشائعة عند العمل مع TimeZone

استخدام إزاحة ثابتة بدلاً من معرف المنطقة الزمنية هو الخطأ الأكثر شيوعًا. TimeZone(secondsFromGMT: 10800) لا يراعي DST، لذلك بالنسبة لـ Europe/Moscow في الصيف، يعطي هذا التركيب إزاحة غير صحيحة بمقدار ساعة واحدة. استخدم دائمًا معرف IANA للمناطق ذات التوقيت الصيفي.

معالجة nil المفقودة عند تهيئة TimeZone(identifier:) هو ثاني أكثر الأخطاء شيوعًا. إذا أدخل المستخدم معرفًا غير صحيح (مثل «moscow» بدلاً من «Europe/Moscow»)، يُرجع المُنشئ nil. بدون معالجة القيمة الاختيارية، يتعطل التطبيق مع خطأ وقت التشغيل. استخدم guard let أو TimeZone(identifier:) مع fallback معروف.

تجاهل DST عند العمل مع التواريخ المستقبلية. TimeZone.secondsFromGMT(for:) هي الطريقة الصحيحة الوحيدة للحصول على الإزاحة لتاريخ محدد. استخدام secondsFromGMT() بدون معامل للتواريخ التاريخية أو المستقبلية يعطي الإزاحة للحظة الحالية، والتي قد لا تتطابق مع الإزاحة الفعلية في التاريخ المحدد، خاصة للمناطق التي ألغت أو أدخلت DST.

وفقًا لـ Stack Overflow (2024)، حوالي 15% من الأسئلة حول DateFormatter مرتبطة بتكوين غير صحيح لـ timeZone. سيناريو نموذجي: يرسل الخادم تاريخًا بصيغة UTC، ويقوم المطور بتنسيقه دون تعيين timeZone للمنسق، ويتم عرض التاريخ في المنطقة الزمنية للجهاز، مما يخلق ارتباكًا لدى المستخدمين من مناطق مختلفة. القاعدة: قم دائمًا بتعيين timeZone للمنسق صراحةً لبيانات الخادم.

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

ما هو TimeZone في Foundation؟

TimeZone هو كلاس Foundation للعمل مع المناطق الزمنية في iOS و macOS. يوفر معلومات حول الإزاحة بالنسبة لـ UTC، وقواعد التوقيت الصيفي، ومعرفات المناطق الزمنية المستندة إلى IANA Time Zone Database.

ما تنسيقات المعرفات التي يدعمها TimeZone؟

ثلاثة تنسيقات: معرفات IANA (Europe/Moscow)، الاختصارات (MSK، EST)، والإزاحات الرقمية (+0300). توصي Apple باستخدام معرفات IANA كالتنسيق الوحيد غير المبهم للكود الإنتاجي.

كيف يتعامل TimeZone مع التوقيت الصيفي؟

تلقائيًا من خلال طريقتي secondsFromGMT(for:) و isDaylightSavingTime(for:). يستخدم TimeZone بيانات IANA التاريخية، المحدثة مع كل إصدار من iOS، مما يضمن انتقالات DST صحيحة لأي تاريخ.

ما الفرق بين TimeZone.current و TimeZone.system؟

TimeZone.current يُرجع المنطقة الزمنية المحددة من قبل المستخدم في الإعدادات (قد تختلف عن الجغرافية). TimeZone.system يُرجع المنطقة الزمنية للجهاز، والتي تُحدد تلقائيًا عن طريق الموقع الجغرافي ولا يمكن تجاوزها من قبل المستخدم.

كيف تحصل على المنطقة الزمنية الحالية في Swift؟

TimeZone.current يُرجع المنطقة الزمنية الحالية للجهاز. للحصول على المعرف، استخدم الخاصية identifier: TimeZone.current.identifier. للحصول على اسم مترجم، استدع localizedName(for:locale:).

الخلاصة

  • TimeZone — كلاس Foundation أساسي للعمل مع المناطق الزمنية في iOS و macOS
  • معرفات IANA — الطريقة الموثوقة الوحيدة لتحديد منطقة زمنية (Europe/Moscow، America/New_York)
  • معالجة تلقائية لـ DST — يتعامل TimeZone بشكل صحيح مع التوقيت الصيفي عبر secondsFromGMT(for:)
  • التكامل مع DateFormatter — الإعداد الإلزامي لـ timeZone يمنع عرض التواريخ بشكل غير صحيح
  • الأسماء المترجمة — طريقة localizedName(for:locale:) تُرجع اسم المنطقة الزمنية باللغة المطلوبة
  • معالجة الأخطاء — تهيئة TimeZone(identifier:) تُرجع nil للمعرفات غير الصالحة
  • تخزين المعرفات — احفظ سلسلة IANA للتسلسل، وليس الإزاحة أو الاختصار

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

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

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

اقرأ أيضًا