مقدمة: لماذا تعاني من الصداع بسبب التواريخ؟
إذا سبق لك كتابة كود بلغة C# وواجهت مهمة نقل تاريخ ووقت بين خادم في موسكو وعميل في نيويورك، فبالتأكيد لاحظت أخطاء غريبة: "لماذا أصبح غداً؟"، "من أين أتت 3 ساعات؟". هل هذا الموقف مألوف؟
في .NET هناك أداتان رئيسيتان للعمل مع التواريخ: DateTime و DateTimeOffset. للوهلة الأولى تبدوان متشابهتين - كلاهما يخزنان التاريخ والوقت. لكن الفرق بينهما جوهري، والاختيار الخاطئ قد يؤدي إلى أخطاء كارثية في منطق الأعمال.
في هذا البرنامج التعليمي سنشرح DateTime مقابل DateTimeOffset بأمثلة واقعية، ونفهم متى نستخدم أيهما، وننسى إلى الأبد الارتباك مع المناطق الزمنية. هيا بنا!
ما هو DateTime؟ (ولماذا هو فخ)
DateTime هو بنية تخزن التاريخ والوقت. وهي موجودة في .NET منذ الإصدار الأول. لكن لديها ميزة واحدة: لا تخزن معلومات عن المنطقة الزمنية. بالأحرى، تخزنها ولكن فقط كعلامة Kind:
DateTimeKind.Unspecified- المنطقة غير محددة (الافتراضي).DateTimeKind.Utc- توقيت UTC.DateTimeKind.Local- الوقت المحلي للنظام.
المشكلة أن هذه العلامة هي مجرد معلومات. لا تقوم بتحويل الوقت تلقائياً. تخيل أنك تحفظ في قاعدة البيانات DateTime مع Kind = Local على خادم في موسكو. ثم تقرأ هذا التاريخ على خادم في فلاديفوستوك. ماذا سيحدث؟ صحيح - سيرى البرنامج أن Kind = Local وسيظن أن هذا هو الوقت المحلي لفلاديفوستوك. لكنه في الحقيقة وقت موسكو. كارثة مطلقة.
// مثال على مشكلة مع DateTimeDateTime moscowTime = new DateTime(2025, 3, 15, 14, 0, 0, DateTimeKind.Local);Console.WriteLine(moscowTime); // 15.03.2025 14:00:00 (يفترض أنه MSK)
// إذا تم تشغيل هذا الكود على خادم بمنطقة زمنية UTC+10 (فلاديفوستوك)// سيتم تفسير DateTime كوقت محلي لفلاديفوستوك!// مما يؤدي إلى خطأ بمقدار 7 ساعات.ما هو DateTimeOffset؟ (منقذ المطورين)
DateTimeOffset هو بنية أكثر ذكاءً ظهرت في .NET Framework 3.5. تخزن التاريخ والوقت والفرق بالنسبة لـ UTC (Offset). الفرق هو عدد الساعات والدقائق التي يختلف بها وقتك المحلي عن UTC.
مثال: 2025-03-15 14:00:00 +03:00 - هذا هو الوقت في موسكو (UTC+3). إذا قمت بنقل هذه القيمة إلى خادم في فلاديفوستوك (UTC+10)، سيفهم .NET: "أها، هذا +03، إذن UTC = 11:00. الآن يمكنني بسهولة إعادة الحساب إلى الوقت المحلي: 21:00". لا سحر - مجرد رياضيات بحتة.
// مثال مع DateTimeOffsetDateTimeOffset moscowOffset = new DateTimeOffset(2025, 3, 15, 14, 0, 0, TimeSpan.FromHours(3));Console.WriteLine(moscowOffset); // 15.03.2025 14:00:00 +03:00
// الآن، حتى على خادم في فلاديفوستوك، نعرف الفرق الدقيق// ويمكننا عرض الوقت بشكل صحيح للمستخدمالاختلافات الرئيسية: DateTime مقابل DateTimeOffset
دعنا نلخص كل شيء في جدول توضيحي. سيساعدك هذا على فهم ما تختاره بسرعة في موقف معين.
1. تخزين معلومات المنطقة الزمنية
- DateTime: يخزن فقط علامة Kind (Unspecified, Utc, Local). لا يخزن الفرق نفسه.
- DateTimeOffset: يخزن الفرق الدقيق من UTC (مثل +03:00, -05:00).
2. مقارنة القيم
- DateTime: يقارن حسب القيمة "المجردة". إذا كان لديك 10:00 UTC و 10:00 MSK (UTC+3)، فإن
DateTime.Equals()سيقول إنهما متساويان. رغم أنهما في الحقيقة لحظتان زمنيتان مختلفتان. - DateTimeOffset: يقارن حسب لحظة الوقت (UTC). 10:00 UTC و 13:00 MSK ستكونان متساويتين.