مقارنة التواريخ في JavaScript: كيف تتجنب الأخطاء وتسريع الكود
\n\nتخيل: أنت تكتب متجرًا إلكترونيًا، وتحتاج إلى التحقق مما إذا كان الخصم على المنتج قد انتهى. أو تقوم بعمل تقويم للمهام حيث تحتاج إلى تصفية الأحداث الخاصة باليوم. أو تجمع تحليلات - "أظهر جميع الطلبات خلال الأسبوع الماضي". في كل هذه الحالات، تحتاج إلى مقارنة تاريخين. قد يبدو الأمر بسيطًا، لكن JavaScript، كالعادة، مستعدة لتقديم المفاجآت.
\n\nسؤال "Compare two dates with JavaScript" على Stack Overflow حصد آلاف المشاهدات - وهذا ليس من قبيل الصدفة. المطورون، حتى ذوو الخبرة، غالبًا ما يتعثرون في الميزات غير الواضحة للعمل مع التواريخ. في هذه المقالة، لن نعرض فقط كيفية مقارنة تاريخين، بل سنحلل أيضًا أي طريقة أسرع وأيها أكثر أمانًا. هيا بنا!
\n\nلماذا لا تعمل المقارنة البسيطة للتواريخ؟
\n\nلنبدأ بالخطأ الكلاسيكي للمبتدئين. لنفترض أن لدينا تاريخين:
\n\nlet date1 = new Date('2024-03-15');\nlet date2 = new Date('2024-03-20');\n\nconsole.log(date1 < date2); // true\nconsole.log(date1 > date2); // false\nconsole.log(date1 == date2); // false\n\n\nمع العوامل < و > كل شيء يعمل بشكل ممتاز. يقوم JavaScript بتحويل كائنات Date إلى أرقام (ملي ثانية) ومقارنتها. لكن العامل == (والصارم ===) يتصرف بشكل مختلف. فهو يقارن المراجع إلى الكائنات، وليس قيمها. تاريخان مختلفان هما كائنان مختلفان، لذلك سيعيد == دائمًا false، حتى لو تطابقت التواريخ حتى الملي ثانية.
هذا هو الفخ الأول. ومن هنا الخلاصة: لا تستخدم أبدًا == أو === لمقارنة التواريخ. استخدم فقط <، >، <=، >= أو الطرق الخاصة.
طريقة getTime(): المعيار الذهبي لمقارنة التواريخ
\n\nالطريقة الأكثر موثوقية وكفاءة هي استخدام طريقة getTime(). فهي تعيد عدد الملي ثانية المنقضية منذ 1 يناير 1970 (عصر Unix). والأرقام، يعرف JavaScript كيفية مقارنتها بشكل ممتاز:
let date1 = new Date('2024-03-15T10:00:00');\nlet date2 = new Date('2024-03-15T10:00:00');\nlet date3 = new Date('2024-03-20T10:00:00');\n\nconsole.log(date1.getTime() === date2.getTime()); // true\nconsole.log(date1.getTime() < date3.getTime()); // true\nconsole.log(date1.getTime() > date3.getTime()); // false\n\n\nلماذا هذا فعال؟ لأن getTime() هي عملية خفيفة جدًا. إنها ببساطة تعيد القيمة الرقمية المخزنة بالفعل داخل كائن Date. لا تحليل، ولا حسابات إضافية. مجرد رقم.
دعنا نقيس الأداء. إليك اختبار صغير في وحدة تحكم المتصفح:
\n\nlet date1 = new Date('2024-01-01');\nlet date2 = new Date('2024-12-31');\n\nconsole.time('getTime');\nfor (let i = 0; i < 1000000; i++) {\n date1.getTime() < date2.getTime();\n}\nconsole.timeEnd('getTime');\n// النتيجة: ~5-10 ملي ثانية في المتصفحات الحديثة\n\n\nمليون مقارنة في 10 ملي ثانية - هذه نتيجة ممتازة. للمقارنة، قد تكون الطرق البديلة أبطأ بمقدار 2-3 مرات.
\n\nمقارنة التواريخ باستخدام valueOf()
\n\nطريقة valueOf() تفعل نفس الشيء الذي تفعله getTime() - تعيد التمثيل الرقمي للتاريخ. لكن هناك فارق بسيط: عند استخدام عوامل المقارنة (<، >، إلخ)، يقوم JavaScript باستدعاء valueOf() ضمنيًا لكائنات Date. أي أن هذا الكود:
let date1 = new Date('2024-03-15');\nlet date2 = new Date('2024-03-20');\nconsole.log(date1 < date2);\n\n\nفي الواقع يعمل كالتالي:
\n\nconsole.log(date1.valueOf() < date2.valueOf());\n\n\nلذلك، للمقارنات البسيطة باستخدام < و >، يمكن استخدام كائنات Date مباشرة. لكن للمساواة الدقيقة (===)، لن يعمل هذا، وهنا لا غنى عن getTime() أو va