LocalDate وLocalTime وLocalDateTime
LocalDate وLocalTime وLocalDateTime
الفئات الثلاث الأكثر استخدامًا في java.time هي LocalDate وLocalTime وLocalDateTime. كلمة "Local" (محلي) تعني أنها لا تحمل أي معلومات عن المنطقة الزمنية أو الإزاحة — فهي تمثّل تاريخًا أو وقتًا كما يفهمه الإنسان من تقويم أو ساعة حائط، لا كلحظة دقيقة على الخط الزمني العالمي. إتقان متى تستخدم كل فئة، وكيف تنشئ نُسخها وتتعامل معها، هو أساس كل ما سيأتي من دروس في هذه الحزمة.
ما تمثّله كل فئة
- LocalDate — تاريخ تقويمي: سنة، شهر، يوم. مثال: 2024-03-15. بلا وقت، بلا منطقة زمنية. استخدمها لأعياد الميلاد وتواريخ الفواتير والإجازات الرسمية — أي شيء لا يهم فيه وقت اليوم.
- LocalTime — وقت من اليوم: ساعة، دقيقة، ثانية، نانوثانية. مثال: 14:30:00. بلا تاريخ، بلا منطقة. استخدمها لمواعيد العمل وإعدادات المنبّه والجداول اليومية المتكرّرة.
- LocalDateTime — تاريخ ووقت معًا. مثال: 2024-03-15T14:30:00. ما زالت بلا منطقة زمنية. استخدمها حين تحتاج البُعدين معًا لكن المعنى واحد في كل المناطق (كسطر سجل log يُكتب على خادم موحّد في موقع معروف).
LocalDateTime غامض عمدًا بشأن الخط الزمني العالمي — لا يمكن تحويله إلى Instant (لحظة دقيقة) دون إضافة منطقة زمنية. هذا تصميم مقصود، وليس قصورًا: فهو يمنع التحويلات الصامتة الخاطئة التي كانت تُعاني منها واجهة برمجة java.util.Date القديمة.
إنشاء النُّسخ: now()
المصنع الساكن now() يقرأ ساعة النظام ويُعيد التاريخ أو الوقت الحالي بحسب المنطقة الافتراضية لبيئة JVM. إنه الأسلوب المعتاد للتقاط "الآن" بصيغة بشرية:
LocalDate.now() بلا وسيطات يصعب اختباره لأنه يعتمد على الساعة الحقيقية. بدلًا من ذلك، مرّر java.time.Clock: LocalDate.now(clock). في الاختبارات، استخدم Clock.fixed(...) لتثبيت الوقت عند لحظة معروفة.
إنشاء النُّسخ: of()
of() ينشئ تاريخًا أو وقتًا محددًا من مكوّناته. يتحقق من صحة الوسيطات فورًا — تمرير تركيبة غير صالحة يُطلق DateTimeException في موضع الاستدعاء مباشرةً، لا بالطرح الصامت الذي كانت تُبديه Calendar القديمة:
إنشاء النُّسخ: parse()
حين تصل بيانات التاريخ/الوقت نصًا — من واجهة REST أو ملف CSV أو حقل VARCHAR في قاعدة البيانات — استخدم parse(). افتراضيًا يتوقع صيغة ISO-8601 التي تستخدمها الحزمة كتنسيق قياسي:
RuntimeException. عند تحليل بيانات يُدخلها المستخدم أو بيانات خارجية، احتِط دومًا بـ try-catch (أو تحقّق من الصحة أولًا) وأرسل رسالة خطأ واضحة. سلسلة نصية فارغة أو مشوّهة ستُوقف البرنامج في وقت التشغيل إن تُركت دون حماية.
الوصول إلى الحقول
تعرض الفئات الثلاث موصِّلات مكتوبة النوع. يمكنك أيضًا استخدام get(ChronoField) العام إن احتجت إلى معالجة الحقول ديناميكيًا:
اللاتغييرية ونمط with()
كل فئات java.time غير قابلة للتغيير (immutable). الدوال مثل withYear() وwithMonth() والدالة العامة with(TemporalField, long) تُعيد نسخة جديدة — الأصل يبقى دون تعديل. المبدأ نفسه ينطبق على String:
LocalDate المشتركة التي تُمرَّر لعدة دوال أو تُخزَّن في مجموعات آمنة بطبيعتها في بيئات متعددة الخيوط — دون الحاجة إلى نسخ دفاعية. هذا يُزيل فئة كاملة من أخطاء التزامن التي كانت تُعاني منها Calendar القابلة للتغيير.
دمج LocalDateTime وتفكيكه
يمكنك التنقل بحرية بين LocalDateTime ومكوّناته:
الخلاصة
استخدم LocalDate للتواريخ التقويمية، وLocalTime لأوقات اليوم، وLocalDateTime لقيم التاريخ والوقت معًا — وكلها بلا منطقة زمنية أو إزاحة. أنشئ النُّسخ بـ now() (من الساعة)، أو of() (من مكوّنات معروفة)، أو parse() (من نص). الفئات الثلاث غير قابلة للتغيير؛ تعديل حقل يُنتج كائنًا جديدًا. في الدرس التالي نتناول Instant — النظير المدرك للمنطقة الزمنية الذي يمثّل لحظة دقيقة على الخط الزمني العالمي.