لماذا يكسر فرق التواريخ في عام 1927 الكود؟ أهم أخطاء Java

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

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

ابدأ الدورة

عام 1927: تلك اللحظة التي عاد فيها الزمن إلى الوراء

\n\n

تخيل: أنت تكتب سكريبت بسيط بلغة Java لحساب الفرق بين تاريخين بالمللي ثانية. تأخذ عام 1927، وتطرح قيمة من أخرى - وتحصل على رقم غريب بدلاً من 3600 ثانية (ساعة واحدة). تتحقق من الكود، تبحث في Google، وتجد السؤال الأسطوري على StackOverflow بآلاف المشاهدات. وتدرك: أنت لست وحدك.

\n\n

هذا الخطأ هو قطعة أثرية حقيقية من التاريخ، لا تزال تخيف المبتدئين حتى اليوم. في هذه المقالة، سنشرح لماذا يعطي طرح epoch-milli times في عام 1927 نتيجة غريبة، ونعرض أمثلة حقيقية من كود Java، والأهم من ذلك، سنقدم طرقاً عملية لتجنب هذا الفخ. إذا كنت تعمل مع بيانات تاريخية أو تريد ببساطة كتابة كود موثوق - فهذه المعلومات لك.

\n\n

جوهر المشكلة: سحر 31 ديسمبر 1927

\n\n

دعنا نذهب مباشرة إلى الكود. إليك مثالاً كلاسيكياً يحير العقل:

\n\n
import java.util.TimeZone;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class StrangeDateDifference {\n    public static void main(String[] args) throws Exception {\n        TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");\n        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\n        sdf.setTimeZone(tz);\n\n        Date date1 = sdf.parse("1927-12-31 23:54:07");\n        Date date2 = sdf.parse("1927-12-31 23:54:08");\n\n        long diff = date2.getTime() - date1.getTime();\n        System.out.println("الفرق بالمللي ثانية: " + diff);\n        // نتوقع 1000، لكننا نحصل على...\n    }\n}
\n\n

تشغّل الكود - وبدلاً من 1000 مللي ثانية (ثانية واحدة) ترى 353؟ أو حتى رقماً سالباً؟ تهانينا، لقد واجهت خطأ طرح التواريخ لعام 1927.

\n\n

السبب ليس خطأً في Java (على الرغم من وجود خطأ أيضاً، ولكن سنتحدث عن ذلك لاحقاً). السبب هو تغيير تاريخي في المنطقة الزمنية. في 31 ديسمبر 1927 في شنغهاي (Asia/Shanghai)، حدث أمر غريب: في الساعة 23:54:08، تم إرجاع التوقيت المحلي بمقدار 5 دقائق و52 ثانية. في الواقع، لم تدم الثانية 1000 مللي ثانية، بل 353 مللي ثانية فقط. Java تتعامل بأمانة مع هذه الحقيقة التاريخية، لكن بالنسبة للمطور، يبدو هذا كالسحر.

\n\n

أهم الأخطاء التي يرتكبها المطورون

\n\n

1. الثقة العمياء في واجهات API القديمة (java.util.Date و SimpleDateFormat)

\n\n

الخطأ الأول والأكثر شيوعاً هو استخدام الفئات القديمة java.util.Date و SimpleDateFormat. فهي ليست غير مريحة فحسب، بل تحتوي أيضاً على مفاجآت مخفية، خاصة عند العمل مع التواريخ التاريخية.

\n\n

كيف تتجنب ذلك: استخدم java.time (Java 8+). على سبيل المثال:

\n\n
import java.time.LocalDateTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\n\npublic class SafeDateDifference {\n    public static void main(String[] args) {\n        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");\n        ZoneId zone = ZoneId.of("Asia/Shanghai");\n\n        LocalDateTime ldt1 = LocalDateTime.parse("1927-12-31 23:54:07", formatter);\n        LocalDateTime ldt2 = LocalDateTime.parse("1927-12-31 23:54:08", formatter);\n\n        ZonedDateTime zdt1 = ldt1.atZone(zone);\n        ZonedDateTime zdt2 = ldt2.atZone(zone);\n\n        long diff = zdt2.toInstant().toEpochMilli() - zdt1.toInstant().toEpochMilli();\n        System.out.println("الفرق بالمللي ثانية: " + diff);\n        // ستظل تحصل على رقم غريب، لكن على الأقل ستعرف لماذا!\n    }\n}
\n\n

2. تجاهل التغييرات التاريخية للمناطق الزمنية

\n\n

يعتقد الكثيرون أن المناطق الزمنية هي مجرد إزاحة ثابتة بالنسبة لـ UTC. لكن في الواقع، لقد تغيرت عشرات المرات خلال المائة عام الماضية.

المدونات

توصيات الكتب