الفرق بين Datetime و Timestamp بقواعد البيانات MySQL

Database MySQL

خلال عملي الفترة الماضية واجهت تصرفاً غير متوقع عند إضافة حقل من نوع timestamp، لنقل مثلا أنه اسمه issued_at، وقمت بإضافة في ملف migration بالشكل التالي:

$table->timestamp('issued_at');

عند إضافة سجل جديد بدون تحديد قيمة لهذا الحقل يأخذ قيمة التاريخ والوقت الحالي وكان هذا الفعل متوقعاً ومقبولاً بالنسبة إلي في حالات الإضافة، ولكنه كان يقوم بهذا أيضاً عند التعديل فعندما أقوم بتعديل حقول آخرى بهذا الجدول دون تحديد قيمة لهذا الحقل تتغير قيمته إلى التاريخ والوقت الحالي، لم أكن أتوقع هذا الفعل، و اضطرني الأمر إلى البحث عن سبب هذا الفعل وإصلاحه، قمت ببحث سريع ووجدت بعض الإجابات تقول أنه كهذا هو عمل timestamp لدى MySQL ويمكن حل هذا بتحول الحقل إلى نوع datetime قمت بهذا الإصلاح سريعا، ولكنني بعدها درست ماسبب هذا الفعل وقررت أن أشاركه بهذه التدوينة.

أولا، ما الفرق بين النوعين Datetime و Timestamp؟

بناءً على توثيق MySQL، نوع Datetime:

The DATETIME type is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD hh:mm:ss' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.

يستخدم نوع DATETIME للقيم التي تحتوي على جزئين التاريخ والوقت معاً، يقوم، MySQL بعرضها بالشكل  YYYY-MM-DD hh:mm:ss والنطاق المسموح به من  1000-01-01 00:00:00 إلى 9999-12-31 23:59:59.

نوع Timestamp

The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC. MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval.

يستخدم نوع TIMESTAMP للقيم التي تحتوي على جزئين التاريخ والوقت معاً، والنطاق المسموح به من 1970-01-01 00:00:01 UTC إلى  2038-01-19 03:14:07 UTC.

يقوم MySQL بتحويل قيم TIMESTAMP من تاريخ ووقت المنطقة الزمنية الحالية (حسب ماتم تحديده على السيرفر) إلى UTC  (التوقيت العالمي الموحد  - Coordinated Universal Time)عند الحفظ، ومن UTC إلى  تاريخ ووقت المنطقة الزمنية الحالية.


ثانياً، كيف يقوم لارافل بترحيل هذه اﻷنواع من الحقول إلى قاعدة البيانات؟

عند إضافة حقل من نوع Datetime في ملف migration

$table->datetime('issued_at');

نجد أنه تمت إضافته كنوع datetime ولا يقبل قيم NULL كالتالي:



أما عند إضافة الحقل من نوع Timestamp

$table->timestamp('issued_at');



نلاحظ أنه بالاضافة على تحديد نوعه وأنه لا يقبل قيم NULL، تم تحديد أن القيمة الافتراضية هي CURRENT_TIMESTAMP وهي التاريخ والوقت الحالي، فعند إضافة سجل جديد مع عدم تحديد قيمة للحقل issued_at سيتم حفظ التاريخ والوقت الحالي. ونلاحظ أيضاً أنه تم إضافة on update CURRENT_TIMESTAMP والتي تعني أنه في حال تم التعديل على هذا السجل ولم يتم تحديد قيمة لهذا الحقل سيتم حفظ التاريخ والوقت الحالي، وهذا الفعل هو لتجنب أن يكون قيم الحقل NULL لأننا لم نحدد عليه nullable.


ثالثاً، كيف أثر السلوك الإفتراضي للنوع Timestamp على الحقل الذي قمت بإضافته؟

سببت هذه المعدلات اﻹضافية على النوع Timestamp سوء الفهم الذي شرحت عنه عند بداية المقالة، ولكن هذا هو تصرف MySQL مع هذا النوع فوجب علي إيجاد بديل.

كان الحل الأول هو تحويل نوع الحقل إلى Datetime وهذا الحل مناسب في حال أنني لا أحتاج إلى حفظ التاريخ والوقت بصيغة UTC وتحويله حسب المنطقة الزمنية.

أما الحل التاني هو أن أبقى على النوع Timestamp مع تحديد أنه يقبل قيم NULL.

$table->timestamp('issued_at')->nullable();

وبهذه الطريقة في حال إضافة سجل جديد أو التعديل عليه لن يقوم بتغيير القيمة إلى التاريخ والوقت الحالي.