التاريخ والوقت في تطوير تطبيقات الجوال: ما هو، ما هي التنسيقات وكيفية العمل

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

التاريخ والوقت في تطوير تطبيقات الجوال — أحد الموضوعات الرئيسية في هندسة تطبيقات الجوال. يستخدم iOS DateFormatter وISO8601DateFormatter، ويستخدم Android DateTimeFormatter وLocalDate من java.time. وفقًا لـ Android Developer Docs، فإن الاختيار الصحيح لواجهة برمجة التطبيقات (API) للجوال لتنسيق التاريخ والوقت يؤثر بشكل مباشر على الأداء وصحة العرض في مناطق زمنية مختلفة.

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

  • DateFormatter على iOS — قوي ولكنه بطيء عند الإنشاء المتكرر. قم بتخزين النسخ في ذاكرة التخزين المؤقت أو استخدم ISO8601DateFormatter لتنسيق ISO 8601.
  • DateTimeFormatter على Android — منسق آمن للخيوط من java.time. حل محل SimpleDateFormat القديم بدءًا من API 26.
  • ThreeTenABP — إصدار backport من java.time لإصدارات Android API الأقل من 26. يضيف LocalDate وZonedDateTime وDateTimeFormatter على الأجهزة القديمة.
  • TimeZone — ضروري للغاية لتحويل UTC إلى الوقت المحلي. قم بتخزين الوقت بصيغة UTC، واعرضه في المنطقة الزمنية للمستخدم.
  • Unix Timestamp — تنسيق قياسي لتخزين الوقت. تضمن المزامنة عبر NTP دقة تصل إلى أجزاء الثانية.

التاريخ والوقت على iOS: DateFormatter وISO8601DateFormatter

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

DateFormatter والأداء

يستغرق إنشاء DateFormatter حوالي 1 مللي ثانية بسبب تحليل نمط dateFormat وتحميل الإعدادات الإقليمية وتحديد المنطقة الزمنية. عند تنسيق قائمة من مئات التواريخ، يؤدي الإنشاء المتكرر إلى تأخير ملحوظ في واجهة المستخدم. الحل — قم بإنشاء المنسق مرة واحدة للشاشة بأكملها وأعد استخدامه. للوصول متعدد الخيوط، استخدم المزامنة عبر DispatchQueue.

swift
import Foundation

// DateFormatter مخزن مؤقتًا — يتم إنشاؤه مرة واحدة
private let dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "dd.MM.yyyy HH:mm"
    formatter.locale = Locale(identifier: "ru_RU")
    formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
    return formatter
}()

// ISO8601DateFormatter — بديل خفيف الوزن
private let isoFormatter: ISO8601DateFormatter = {
    let formatter = ISO8601DateFormatter()
    formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
    return formatter
}()

let now = Date()
let formattedDate = dateFormatter.string(from: now)
// "01.07.2026 14:30"
let isoDate = isoFormatter.string(from: now)
// "2026-07-01T14:30:00.000Z"

لتنسيق ISO 8601، استخدم ISO8601DateFormatter — لا يتطلب تحديد نمط ويعمل بشكل أسرع من DateFormatter. على iOS 10+، هذا الفصل مفضل للعمل مع تواريخ الخادم. للتنسيقات القديمة، احتفظ بـ DateFormatter ولكن قم بتخزين النسخة في ذاكرة التخزين المؤقت كخاصية ثابتة أو singleton.

التاريخ والوقت على Android: java.time وDateTimeFormatter

على Android، تتم معالجة التاريخ والوقت عبر حزمة java.time، المتاحة من API 26. الفصول الرئيسية: LocalDate (التاريخ فقط)، LocalTime (الوقت فقط)، LocalDateTime (التاريخ والوقت بدون منطقة زمنية) وZonedDateTime (مع منطقة زمنية). DateTimeFormatter — منسق آمن للخيوط لمنصة Android للجوال. يتم تنسيق التاريخ في تطبيقات الجوال عبر DateTimeFormatter وLocalDate دون فقدان الأداء.

LocalDate وZonedDateTime والتنسيق

LocalDate يخزن التاريخ بدون وقت — مثالي لأعياد الميلاد. يخزن ZonedDateTime معلومات كاملة مع المنطقة الزمنية. يدعم DateTimeFormatter الأنماط المحددة مسبقًا (ISO_LOCAL_DATE، ISO_DATE_TIME) والأنماط المخصصة عبر ofPattern. جميع فئات java.time غير قابلة للتغيير وآمنة للخيوط، مما يلغي حالات السباق عند العمل في خيوط متعددة.

kotlin
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId

// إنشاء وتنسيق التاريخ الحالي
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)

// العمل مع المناطق الزمنية
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))

DateTimeFormatter أكثر كفاءة بشكل ملحوظ من SimpleDateFormat لأنه لا يحلل النمط في كل استدعاء. يوصى بإنشاء ثوابت المنسق على مستوى الفصل أو الكائن المرافق. لتحويل Unix Timestamp، استخدم Instant.ofEpochSecond، ثم حول إلى LocalDateTime أو ZonedDateTime عبر المنطقة الزمنية.

المناطق الزمنية: التاريخ والوقت في تطبيقات الجوال وTimeZone

تعتمد التاريخ والوقت الصحيحين على شاشة المستخدم على المعالجة الصحيحة للمناطق الزمنية. يتطلب التاريخ والوقت في تطوير تطبيقات الجوال لنظام Android مراعاة المنطقة الزمنية للجهاز. القاعدة الذهبية: قم بتخزين الوقت بصيغة UTC، وقم بالتحويل إلى المنطقة الزمنية المحلية فقط للعرض. يوفر iOS TimeZone من Foundation، ويوفر Android ZoneId من java.time. تدعم كلتا واجهات برمجة التطبيقات (API) لمنصات الجوال الكشف التلقائي عن المنطقة الزمنية الحالية للجهاز. يعتمد التاريخ في تطبيق الجوال على ZoneId وTimeZone.

التوقيت الصيفي ومعرفات IANA

يخلق التوقيت الصيفي غموضًا: يمكن تمثيل لحظة زمنية واحدة بساعتين محليتين مختلفتين. تتعامل java.time وFoundation مع DST تلقائيًا. استخدم معرفات IANA (Europe/Moscow، America/New_York)، وليس الاختصارات (MSK، EST) — الاختصارات غامضة وتتجاهل الانتقال إلى التوقيت الصيفي.

swift
import Foundation

// تحويل UTC إلى الوقت المحلي على iOS
func formatToLocalTime(utcDate: Date, timeZoneId: String) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "dd.MM.yyyy HH:mm"
    formatter.timeZone = TimeZone(identifier: timeZoneId)
    return formatter.string(from: utcDate)
}

// تحديد المنطقة الزمنية للجهاز
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()

على Android، استخدم ZoneId.systemDefault() للحصول على المنطقة الزمنية للجهاز. عند تحويل UTC إلى الوقت المحلي، قم بإنشاء ZonedDateTime مع ZoneOffset.UTC وقم بتطبيق withZoneSameInstant. لواجهات برمجة التطبيقات (API) القديمة بدون java.time، استخدم TimeZone.getDefault() وCalendar — ولكن من الأفضل إضافة ThreeTenABP مباشرة.

kotlin
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId

// تحويل Unix Timestamp إلى الوقت المحلي
fun toLocalDisplay(unixSeconds: Long): String {
    val instant = Instant.ofEpochSecond(unixSeconds)
    val local = instant.atZone(ZoneId.systemDefault())
    return local.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"))
}

ThreeTenABP — التاريخ والوقت للإصدارات القديمة من Android

ThreeTenABP — مكتبة محول تنقل java.time إلى إصدارات Android API الأقل من 26. توفر نفس الفئات: LocalDate، LocalTime، ZonedDateTime، DateTimeFormatter، Instant. إذا كان التطبيق يدعم Android 5 أو 6 (API 21-25)، فإن ThreeTenABP هو الطريقة الوحيدة لاستخدام واجهة برمجة تطبيقات (API) حديثة للجوال دون الانتقال إلى Calendar القديم. يتم تنفيذ التاريخ والوقت في تطوير تطبيقات الجوال للأجهزة القديمة عبر هذه المكتبة. للأجهزة القديمة، يتم تنفيذ التاريخ والوقت عبر ThreeTenABP.

إضافة وتكوين ThreeTenABP

تتطلب المكتبة التهيئة في طريقة Application.onCreate() عن طريق استدعاء AndroidThreeTen.init(). يؤدي ذلك إلى تحميل بيانات المناطق الزمنية من assets. بعد التهيئة، تكون واجهة برمجة التطبيقات (API) مطابقة تمامًا لـ java.time — سيكون الكود لـ API 26+ وAPI 21+ هو نفسه. يبلغ حجم المكتبة حوالي 400 كيلوبايت، وهو مقبول لمعظم تطبيقات الجوال.

kotlin
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter

// التهيئة في Application
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        AndroidThreeTen.init(this)
    }
}

// واجهة برمجة التطبيقات مطابقة لـ java.time
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)

أداء ThreeTenABP مشابه لـ java.time الأصلي على الأجهزة الحديثة. على الأجهزة القديمة، قد يكون هناك تأخير في الاستدعاء الأول بسبب تحميل بيانات المناطق الزمنية. قم بترحيل الكود الحالي من Calendar إلى ThreeTenABP تدريجيًا: استبدل Date وCalendar بـ Instant وLocalDate في الوحدات الجديدة، مع ترك الكود القديم دون تغيير.

Unix Timestamp ومزامنة الوقت عبر NTP

Unix Timestamp — عدد الثواني المنقضية منذ 1 يناير 1970 00:00 UTC. هذا تنسيق عالمي لتخزين وتبادل الوقت بين الخادم والعميل. ومع ذلك، قد يختلف الوقت على الجهاز عن الوقت الفعلي بسبب إعدادات المستخدم. للمزامنة، يُستخدم NTP — بروتوكول الوقت الدقيق عبر UDP. Unix Timestamp هو التنسيق الذي يتم به تخزين التاريخ والوقت على الخادم.

الحصول على Unix Timestamp ومزامنة NTP

يقوم Date().timeIntervalSince1970 على iOS بإرجاع الثواني منذ 1970. على Android، يقوم System.currentTimeMillis() بإرجاع أجزاء الثانية. للدقة، استخدم NTP: ترسل مكتبة TrueTime لنظام iOS وAndroidNtp لنظام Android طلبًا إلى خادم NTP وتحسب إزاحة الوقت. دقة NTP هي 1-10 مللي ثانية على الشبكة المحلية و10-100 مللي ثانية عبر الإنترنت.

swift
import Foundation

// الحصول على Unix Timestamp على iOS
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)

// مزامنة NTP مع TrueTime
TrueTime.shared.start { result in
    switch result {
    case .success:
        let ntpTime = TrueTime.shared.now()
        print("الوقت الدقيق: \(ntpTime)")
    case .failure(let error):
        print("خطأ NTP: \(error)")
    }
}

بدون مزامنة في تطبيق الجوال، من الممكن حدوث أخطاء: علامات زمنية غير صحيحة للأحداث، وعدم التزامن مع الخادم. تتم مزامنة الوقت في تطوير تطبيقات الجوال عبر NTP مرة واحدة عند بدء تشغيل التطبيق، وبعد ذلك يتم استخدام الإزاحة المحسوبة. لتطبيقات الجوال الحرجة من حيث الدقة (المالية، اللوجستية)، يكون بروتوكول NTP إلزاميًا قبل إرسال البيانات إلى الخادم.

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

لماذا DateFormatter بطيء على iOS؟

يقوم DateFormatter بتحليل نمط التنسيق وتحميل الإعدادات الإقليمية وتحديد المنطقة الزمنية في كل مرة يتم فيها إنشاء نسخة. قم بتخزين المنسق في ذاكرة التخزين المؤقت كثابت ثابت أو استخدم ISO8601DateFormatter لـ ISO 8601 — فهو أخف وأسرع.

ماذا تستخدم بدلاً من SimpleDateFormat على Android؟

DateTimeFormatter من حزمة java.time — آمن للخيوط وعالي الأداء. متاح من API 26. للإصدارات القديمة، استخدم ThreeTenABP الذي يوفر واجهة برمجة تطبيقات (API) مماثلة.

كيف تتعامل مع التواريخ قبل Java 8 على Android؟

أضف ThreeTenABP — إصدار backport من java.time لنظام Android API 21+. التهيئة عبر AndroidThreeTen.init() في Application.onCreate(). واجهة برمجة التطبيقات (API) مطابقة تمامًا لـ java.time الأصلي.

هل من الضروري تخزين الوقت بصيغة UTC؟

نعم، قم بتخزين الوقت بصيغة UTC على الخادم وفي قاعدة البيانات المحلية. قم بالتحويل إلى المنطقة الزمنية المحلية للمستخدم فقط في مرحلة العرض. هذا يلغي الأخطاء عند تغيير المنطقة الزمنية أو السفر.

كيف تحصل على Unix Timestamp على iOS؟

يقوم Date().timeIntervalSince1970 بإرجاع عدد الثواني منذ 1 يناير 1970. لأجزاء الثانية، اضرب في 1000 وحول إلى Int64. للمزامنة الدقيقة، استخدم مكتبة TrueTime مع خادم NTP.

الملخص

  • DateFormatter على iOS — الأداة الرئيسية لتنسيق التاريخ والوقت، تتطلب تخزينًا إلزاميًا للنسخ في ذاكرة التخزين المؤقت. ISO8601DateFormatter هو بديل أخف لـ ISO 8601.
  • DateTimeFormatter على Android — منسق آمن للخيوط من java.time لـ API 26+. LocalDate وZonedDateTime هما الفئتان الرئيسيتان للعمل مع التواريخ.
  • ThreeTenABP — واجهة برمجة تطبيقات (API) موحدة لجميع إصدارات Android. أضفه للتوافق مع الإصدارات السابقة API 21-25. الكود لا يختلف عن java.time.
  • TimeZone وUTC — قم بتخزين الوقت بصيغة UTC، وحول إلى المنطقة الزمنية المحلية فقط للعرض. استخدم معرفات IANA.
  • Unix Timestamp — تنسيق عالمي لتبادل الوقت بين الخادم والعميل. احصل عليه عبر Date().timeIntervalSince1970 على iOS.
  • مزامنة NTP — تضمن دقة الوقت حتى أجزاء الثانية. TrueTime (iOS) وAndroidNtp (Android) هما المكتبتان القياسيتان.

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

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

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