المناطق الزمنية في Kotlin: دليلك الشامل لإتقان الوقت

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا الوقت مشكلة كبيرة (وكيف يحلها Kotlin)

\n\n

إذا سبق لك كتابة تطبيق يخدم مستخدمين من مناطق زمنية مختلفة، فأنت تعرف هذه المعاناة. يصل الطلب مع طابع زمني، في قاعدة البيانات مخزّن بصيغة UTC، والمستخدم في نيويورك يشكو من أن الإشعار وصل في الثالثة صباحًا، بينما في قاعدة البيانات الساعة الثامنة صباحًا. هل هذا مألوف؟

\n\n

التعامل مع المناطق الزمنية هو مجال في البرمجة تبدو بساطته خادعة، لكنها تسبب عشرات الأخطاء. لكن Kotlin، الذي ورث أفضل ممارسات Java، يمنحنا ترسانة قوية لمكافحة الفوضى. في هذا المقال، سنشرح كيفية التعامل الصحيح مع المناطق الزمنية في Kotlin، وتجنب الأخطاء الشائعة، وكتابة كود لا ينهار عند التحول إلى التوقيت الصيفي.

\n\n

نبذة سريعة: ما هي المنطقة الزمنية؟

\n\n

قبل الغوص في الكود، دعونا نتفق على المصطلحات. المنطقة الزمنية (time zone) ليست مجرد فرق توقيت عن UTC. بل هي أيضًا مجموعة قواعد للتحول إلى التوقيت الصيفي/الشتوي (DST). على سبيل المثال، Europe/Moscow ليس مجرد +3 ساعات، بل يشمل أيضًا تغييرات تاريخية (في 2014 توقفت روسيا عن تغيير الساعة).

\n\n

في عالم Java/Kotlin، هناك مفهومان رئيسيان مسؤولان عن ذلك:

\n\n
    \n
  • ZoneId — معرف المنطقة الزمنية (مثل "America/New_York"). يحتوي على كل تاريخ DST.
  • \n
  • ZoneOffset — مجرد فرق توقيت (مثل +05:00). بدون قواعد تحول.
  • \n
\n\n

الفرق جوهري: إذا استخدمت ZoneOffset بدلاً من ZoneId، سينهار كودك في يوم تغيير الساعة. تذكر هذا جيدًا.

\n\n

الفئات الأساسية لـ java.time في Kotlin

\n\n

يدعم Kotlin بالكامل حزمة java.time (Java 8+). إذا كنت تكتب لتطبيق Android — لا تنسَ إضافة desugaring أو استخدم ThreeTenABP. بالنسبة لـ Kotlin على الخادم، لا توجد مشاكل.

\n\n

Instant — لحظة زمنية

\n\n

Instant هي لحظة مطلقة على الخط الزمني. غير مرتبطة بمنطقة زمنية. هذا هو ما يجب تخزينه في قاعدة البيانات.

\n\n
import java.time.Instant\n\nfun main() {\n    val now = Instant.now()\n    println(now) // 2025-03-15T10:30:00.123Z\n}
\n\n

لاحظ الحرف Z في النهاية — وهو توقيت زولو، أي UTC. خزّن كل شيء بصيغة UTC — هذه هي القاعدة الذهبية.

\n\n

ZonedDateTime — الوقت مع مراعاة المنطقة

\n\n

عندما تريد عرض الوقت للمستخدم، استخدم ZonedDateTime. يخزن التاريخ والوقت وفرق التوقيت ومعرف المنطقة.

\n\n
import java.time.ZonedDateTime\nimport java.time.ZoneId\n\nfun main() {\n    val moscowTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))\n    println(moscowTime) // 2025-03-15T13:30:00.123+03:00[Europe/Moscow]\n}
\n\n

هل ترى الأقواس المربعة؟ هذا هو ZoneId الذي يسمح للنظام بمعالجة DST بشكل صحيح.

\n\n

OffsetDateTime — الوقت مع فرق التوقيت

\n\n

إذا كنت لا تحتاج معلومات عن المنطقة، بل فقط فرق التوقيت — استخدم OffsetDateTime. إنه أخف وأسرع.

\n\n
import java.time.OffsetDateTime\nimport java.time.ZoneOffset\n\nfun main() {\n    val offsetTime = OffsetDateTime.now(ZoneOffset.ofHours(5))\n    println(offsetTime) // 2025-03-15T15:30:00.123+05:00\n}
\n\n

لكن تذكر: إذا حفظت OffsetDateTime لنيويورك، ثم تحولت الولايات المتحدة إلى التوقيت الصيفي — سيصبح فرق التوقيت قديمًا.

\n\n

التحويل بين المناطق الزمنية في Kotlin

\n\n

المهمة الأكثر شيوعًا هي أخذ الوقت من قاعدة البيانات (UTC) وعرضه في المنطقة الزمنية للمستخدم. دعنا نشرح كيفية القيام بذلك بشكل صحيح.

\n\n

من UTC إلى المنطقة المحلية

\n\n
import java.time.Instant\nimport java.time.ZoneId\nimport java.time.ZonedDateTime\n\nfun convertUtcToLocal(utcInstant: Instant, targetZone: String): ZonedDateTime {\n    return utcInstant.atZone(ZoneId.of(targetZone))\n}\n\nfun main() {\n    val utcNow =                

المدونات

توصيات الكتب