مبحث تاریخ و زمان (date and time) در PHP و نحوه درج در بانک MySQL
یکی از مسائل مهم در طراحی سیستمهای مبتنی بر PHP این است که چطور تاریخ و ساعت شمسی را از کاربر بگیریم؟ چطور در دیتابیس ثبت کنیم؟ چطور مجدداً به کاربر نمایش دهیم؟
اگر با تقویم میلادی سر و کار میداشتیم، مشکلی نمیبود، اما در بحث شمسی کمی کار پیچیدهتر است.
توضیحات مهم:
فرض ما این است که شما قصد دارید تاریخ و زمان فعلی را به طور پیشفرض در قالب شش فیلد select به صورت فارسی به کاربر نمایش دهید.
به این صورت:
کاربر اگر خواست تغییراتی در تاریخ و زمان میدهد و به پردازشگر فرم ارسال میکند. حالا شما تاریخ شمسی را دارید.
- در دیتابیس، نوع فیلد را چه نوع انتخاب کنیم؟
در MySQL چند نوع فیلد مختلف برای تاریخ و زمان در نظر گرفته شده است:
- نوع DATE: اگر میخواهید فقط تاریخ را درج کنید، از این نوع فیلد استفاده کنید. همانطور که در تصویر بالا میبینید، نوع درج، به صورت زیر است:
2011-09-13
- نوع DATETIME: اگر هم تاریخ و هم زمان را نیاز دارید (مثلاً لحظه دقیق تراکنش بانکی) نوع فیلد را DATETIME در نظر بگیرید. همانطور که در تصویر بالا میبینید، نوع درج، به صورت زیر است:
2011-09-13 21:33:50
دقت کنید که بین ساعت و روز، یک فاصله (space) لازم است. این فیلد 19 کاراکتری است.
- نوع TIMESTAMP: این نوع فیلد از نظر طول و نوع درج، مثل DATETIME است. یعنی 19 کاراکتری و به صورت بالا. اما کاربرد اصلی آن، برای زیر نظر گرفتن لحظه آپدیت یک رکورد است. اگر یک فیلد را از این نوع انتخاب کنید، هر بار که آن سطر داده، آپدیت میشود، این فیلد، لحظه آپدیت را جایگزین تاریخ قبلی خود میکند. فیلد مناسبی است برای کارهای حساس که باید هر تغییر در دیتابیس ثبت و پیگیری شود. (مثلاً آخرین لحظه تغییر پسورد مدیر در موارد امنیتی بهتر است درج شود تا در صورت لزوم متوجه شوید که در چه لحظهای پسورد عوض شده است)
- نوع TIME: اگر قصد دارید فقط زمان را درج کنید، از فیلد نوع time استفاده کنید. بین ساعت، دقیقه و ثانیه، : لازم است.
- نوع YEAR: فقط برای درج سال مناسب است. به صورت 4 رقمی درج کنید.
پس، تصمیم بگیرید که کدام نوع فیلد را نیاز دارید.
در سختترین حالت، ما در این مثال، datetime را در نظر میگیریم.
پس، بعد از اینکه 6 پارامتر را از کاربر به شمسی گرفتید، در گام بعد باید آنرا تبدیل به میلادی کنید، سپس به GMT تبدیل کنید و در دیتابیس ثبت کنید.
- چرا باید به میلادی تبدیل شود؟
سؤال: نمیشود همان شش پارامتر تاریخ شمسی را مثلاً با یک خط تیره کنار هم قرار داد و در یک فیلد varchar درج کرد؟ مثلاً به این صورت:
1390-7-3-20-32-22
این هم روشیست، بله، میتوانید به این صورت ثبت کنید و بعداً با تابع explode، آنرا تکه تکه کنید و شش پارامتر را از هم جدا کنید و در یک آرایه بریزد و نمایش دهید. گاهی اوقات هم بد نیست از همین روش استفاده کنید. البته بیشتر در مورد تاریخهایی که قرار نیست بر اساس آنها پردازشی انجام شود. یعنی نمیخواهید با یک تاریخ خاص مقایسه یا sort کنید.
اما اگر قرار است با دستورات SQL یک سری پردازشها مثل مقایسه یا مثلاً به دست آوردن جمع مخارج در یک محدوده زمانی خاص انجام دهید، اگر تاریخ به صورت میلادی و در یکی از انواع بالا درج شده باشد، میتوانید با دستورات SQL، مقایسه انجام دهید.
مثلاً میتوانید بگویید: جمع مخارج، بین تاریخ x تا y
اما اگر فیلدها به صورت بالا نباشد، باید با توابع PHP کلی کدنویسی انجام دهید و خودتان حواستان باشد که ماهها چند روزه هستند و دردسرهای مشابه.
چرا باید به GMT درج شود؟
مطمئناً میدانید که منظور ما از GMT همان خط گرینویچ یعنی ساعت لندن است.
نکته: اگر شما بر روی هر سروری، تابع date را در PHP فراخوانی کنید، نرم افزار PHP ابتدا به Time Zone سیستم شما نگاه میکند. مثلاً Time Zone سیستم من روی Tehran تنظیم است. یعنی 3 ساعت و 30 دقیقه جلوتر از ساعت لندن. (البته در شش ماه اول، 4 ساعت و 30 دقیقه جلوتر خواهد بود و نرم افزار، آنرا تشخیص خواهد داد)
اینکه گفته میشود تاریخ مورد نظرتان را به GMT در دیتابیس ثبت کنید به خاطر این است که اگر خواستید سیستم را بین المللی کنید، فقط کافیست Time Zone کشور کاربر را در فایل config.php یا در دیتابیس بگیرید و ذخیره کنید تا همه تاریخها را به راحتی با افزایش یا کاهش اختلاف ساعت، به ساعت مورد نظر کاربر نمایش دهید. اما اگر بر اساس تهران درج کنید، باید همیشه یک بار به GMT تبدیل کنید و سپس به زمان مورد نظر کاربر.
خلاصه مطلب:
- به کاربر تاریخ شمسی را نمایش دهید. (بر اساس ساعت تهران)
- تاریخ شمسی را بگیرید و به میلادی تبدیل کنید.
- تاریخ میلادی را بر اساس GMT به دست آورید.
- با ساختاری که نوع فیلد دیتابیس دارد، آنرا در دیتابیس درج کنید.
1- نمایش اولیه تاریخ شمسی به کاربر:
برای نمایش تاریخ شمسی به کاربر، پیش از این مقالهای نوشتهایم که دعوت میکنم آنرا مطالعه کنید:
در آن مقاله توضیح دادهایم که برای تبدیل تاریخ میلادی به شمسی از توابع کتابخانه jdf استفاده میکنید که توسط دوستان برنامهنویس ایرانی به خوبی طراحی شده است.
خروجی قطعه کد زیر، در ادامه آمده است:
خروجی:
require_once('jdf.php');
echo '<br /><br /><div style="background-color:#b1ff9f"><strong>تاریخ عضویت</strong>:<br />
سال: <input type="text" name="year" maxlength="4" size="4" value="'.jdate("Y").'" />
ماه: ';
echo '<select name="month">';
for ($i=1;$i<=12;$i++)
if($i==jdate("m"))
echo '<option value="'.$i.'" selected="selected">'.$i.'</option>';
else
echo '<option value="'.$i.'">'.$i.'</option>';
echo '</select>';
echo 'روز: ';
echo '<select name="day">';
for ($i=1;$i<=31;$i++)
if($i==jdate("d"))
echo '<option value="'.$i.'" selected="selected">'.$i.'</option>';
else
echo '<option value="'.$i.'">'.$i.'</option>';
echo '</select><br />';
echo 'ساعت: ';
echo '<select name="hour">';
for ($i=1;$i<=24;$i++)
if($i==jdate("H"))
echo '<option value="'.$i.'" selected="selected">'.$i.'</option>';
else
echo '<option value="'.$i.'">'.$i.'</option>';
echo '</select>';
echo 'دقیقه: ';
echo '<select name="minute">';
for ($i=1;$i<=59;$i++)
if($i==jdate("i"))
echo '<option value="'.$i.'" selected="selected">'.$i.'</option>';
else
echo '<option value="'.$i.'">'.$i.'</option>';
echo '</select>';
echo 'ثانیه: ';
echo '<select name="second">';
for ($i=1;$i<=59;$i++)
if($i==jdate("s"))
echo '<option value="'.$i.'" selected="selected">'.$i.'</option>';
else
echo '<option value="'.$i.'">'.$i.'</option>';
echo '</select></div>';
2- تبدیل تاریخ شمسی به میلادی بر اساس GMT:
در PHP تابع mktime، شش پارامتر تاریخ و زمان را میگیرد و timestamp را بر میگرداند.
Time Stamp چیست؟
اولاً منظور از Time Stamp در PHP، همان Unix Time Stamp است که نوع مشهور تایم استمپ است. اما نوعی که در MySQL توضیح دادیم، MySQL Time Stamp گفته میشود که چیز متفاوتی است.
تایم استمپ، تعداد ثانیه سپری شده از تاریخ 1 / 1 / 1970 ساعت 12 نیمه شب است. برای تبدیل تاریخ میلادی به تقویمهای مختلف مثل شمسی، ما باید مقدار ثانیه گذشته از یک تاریخ واحد را بدانیم. حالا اگر بدانیم در 1 / 1 / 1970 ساعت 12 نیمه شب، در تقویم مقصد (مثلاً در تقویم شمسی) چه زمانی بوده است، ثانیه را هم که داریم پس میتوانیم با تقسیم بر طول سال به ثانیه و ادامه دادن تقسیمها، سال، ماه، روز، ساعت، دقیقه و ثانیهای که از آن تاریخ گذشته است را به آن لحظه شمسی اضافه کنیم تا لحظه شمسی فعلی به دست آید. اگر متوجه شدید که بردهاید وگرنه چندان مهم نبود:)
مهم این است که بدانید Time Stamp تعداد ثانیه سپری شده از تاریخی است که گفته شد.
در فایل jdf تابع خوبی داریم به نام jmktime که آن شش پارامتر را به شمسی میگیرد و تایم استمپ میلادی آن بر اساس GMT را برمیگرداند.
بنابراین، با استفاده از قطعه کد زیر میتوانید تاریخ شمسی که از فرم بالا گرفته شده است را به timestamp میلادی تبدیل کنید:
$timestamp = jmktime($_REQUEST['hour'],$_REQUEST['minute'],$_REQUEST['second'],$_REQUEST['month'],$_REQUEST['day'],$_REQUEST['year']);
خوب، تا اینجا تاریخ شمسی را به میلادی بر اساس GMT تبدیل کردیم.
3- درج تاریخ در دیتابیس:
ما تایم استمپ را بر اساس GMT داریم. اما موضوع این است که چطور در دیتابیس درج کنیم.
خیلی ساده است. با استفاده از تابع date، آن تایم استمپ را به فرمت دلخواه خود درآورید و در دیتابیس درج کنید.
مثلاً در این مثال، ما خروجی قطعه کد بالا را به صورت DATETIME تبدیل میکنیم و در دیتابیس درج میکنیم:
$datetime = date("Y-m-d H:i:s",$timestamp);
متغیر datetime را در دیتابیس درج کنید.
2- خواندن از دیتابیس و نمایش مجدد:
تا اینجا، ما توانستهایم تاریخ شمسی را از کاربر بگیریم و به صورت میلادی مبتنی بر GMT در دیتابیس درج کنیم.
حالا فرض کنید میخواهیم روی یک صفحه، این تاریخ را نمایش دهیم. طبیعتاً باید به شمسی و مبتنی بر تهران نمایش دهیم.
بهترین راه این است که از فیلد DATETIME، به صورت time stamp خروجی بگیرید. برای این کار، در MySQL تابع جالبی داریم. به این مثال جالب دقت کنید:
$timestamp = mysql_query("SELECT UNIX_TIMESTAMP(datetime) FROM `table_name`");
...
اگر در PHP نیاز دارید، میتوانید از این تابع استفاده کنید:
function convert_datetime($str) {
list($date, $time) = explode(' ', $str);
list($year, $month, $day) = explode('-', $date);
list($hour, $minute, $second) = explode(':', $time);
$timestamp = mktime($hour, $minute, $second, $month, $day, $year);
return $timestamp;
}
وقتی timestamp مربوط به آن تاریخ را به دست آوردید حالا با تابع jdate آنرا به شمسی تبدیل کنید. مثلاً با چنین فرمتی:
$jalali_date = jdate("Y/m/d H:i:s",$timestamp);
و یا میتوانید هر پارامتر را جدا جدا به دست آورید:
$jalali_date_year = jdate("Y");
$jalali_date_month = jdate("m");
تمام!
میدانم که بحث پیچیدهای به نظر میرسد، اما راهی جز این نیست. اگر بخواهید سیستم چند زبانه که با همه تقویمها به راحتی کار کند طراحی کنید، باید این روال را طی کنید.
سعی کنید مقاله را چندین بار بخوانید تا متوجه مطلب بشوید...
نکته پایانی:
- اگر میخواهید اعداد به صورت انگلیسی در دیتابیس درج شوند، کلاً فایل jdf.php را باز کنید و خط اول تابع jdate را به صورت زیر تغییر دهید:
function jdate($format,$timestamp='',$none='',$time_zone='Asia/Tehran',$tr_num='en'){
از این به بعد تاریخ بر اساس تهران و به صورت انگلیسی دیده خواهد شد.
موفق باشید؛
حمید رضا نیرومند
.
- مطالب مرتبط:
- چگونه گزینه های انتخاب شده یک CheckBox را با کمک inputهای hidden به صفحه سوم منتقل کنیم؟
- در آمدی بر زبان PHP
- نوشتن بر روی عکس با GD در PHP
- آموزش نمایش تاریخ هجری شمسی با استفاده از PHP در صفحات وب
- نکاتی در مورد کار با URL در پی.اچ.پی (Working with addresses in PHP)
- چگونه با PHP از اطلاعات دیتابیس خروجی csv بگیریم که کاراکترها درست نمایش داده شوند؟
- ------------
- مرورى بر تاریخچه و نحوه نصب جدید ترین نسخه ویژوال بیسیك
- در فیلمها چطور دوربین به دور یک نفر میچرخد؟
- به دست آوردن IP کاربر در PHP (مبحث آی پی در پی.اچ.پی)
- پنجاه سال شطرنج كامپیوتری به روایت موزه تاریخ كامپیوتر
- چگونه با جاوا اسکریپت، ساعت سرور را نمایش دهیم؟ (How to show server time with javascript)
ارسال سؤال یا نظر
1- سوران:
بوسیله: , در: Tuesday, 2012 January 10-کد: 3823
عالي بود
2- محمد کاظم:
بوسیله: , در: Thursday, 2012 January 19-کد: 3870
تشکر
خیلی عالی بود.
3- saeed hassani:
بوسیله: , در: Saturday, 2012 July 07-کد: 4571
very good
4- بهروز صفرزاده:
بوسیله: , در: Thursday, 2012 September 20-کد: 4940
خیلی خیلی خیلی ممنون هستم.
5- tohidhabiby:
بوسیله: , در: Friday, 2012 December 07-کد: 5553
سلام من یه تازه کارم شاید من بلد نباشم از توابع شما استفاده کنم اما طبق آمزش پیش رفتم و جواب نگرفتم عملا توابع تون کار نکردن
6- هادی:
بوسیله: , در: Saturday, 2013 April 06-کد: 6561
ممنون دوست عزیز مقاله خوبی بود و من ازش استفاده کردم...تابحال تو طراحی هام اصلا به همچین مسئله مهمی فکر نکرده بودم...
موفق باشی...
7- hadi:
بوسیله: , در: Tuesday, 2013 May 21-کد: 6837
درود
مقاله خوبی بود من تا مرحله ساعت gmt پیش میرم از اون به بعد نمیدونم کدها را در کدام فایلها باید قرار داد
میشه راهنمایی کنید
8- بهار:
بوسیله: , در: Monday, 2014 March 10-کد: 9766
دست شما درد نکنه
بهترین راه آموزش بدیگران ارائه نمونههای عینی است! متأسفانه این چیزها که فرمودید و البته بدرستی، در خیلی از جاهای دیگر هم نقل شده. کسی نمیاد ۳ تا فایل ( فرم اچتیامال، کد پیاجپی ارسال اطلاعات و کد پیاچپی نمایش اطلاعات از بانک ) رو از روی تاریخ توضیح بده. همه به گفتن روالهایی که در خیلی از کتابها و سایتها است اشاره میکنند و به همین بسنده! امیدوارم یه روزی این آموزش کار با تاریخ در پیاچپی رو همینطور به زبان ساده اما کامل و با نمونهی عملی داشته باشیم. خودم پیر شدم اینقدر که تو این سایت و اون سایت دنبالش گشتم و پیداش نکردم. :(
9- علی:
بوسیله: , در: Wednesday, 2015 May 27-کد: 13432
سلام من میخوام در یک صفحه یک دکمه ای رو قرار بدم که وقتی کاربر روش کلیک کرد ساعت همون لحضه به طور اتوماتیک در دیتابیس ذخیره بشه.باید چکا کنم.ممنون میشم اگه کمک کنید
10- پیمان:
بوسیله: , در: Saturday, 2015 August 29-کد: 13760
بالاخره تو دیتابیس datetime ذخیره کنیم یا timetamp?
timestamp هر بار که رکورد تغییر کنه بروز میشه؟ اگر اینطوری باشه که برای مثلا ثبت تاریخ ورود کالا یا هر چیز دیگه به جدول مناسب نیست
مشاهده ادامه نظرات
11- نیما:
بوسیله: , در: Friday, 2019 October 11-کد: 16129
این فایل به یک آپدیت نیاز دارد سطر 434 باید ازrn return mktime($h,$m,$s,$month,$day,$year,$is_dst);rnبه این دستور تغییر کندrn return mktime($h,$m,$s,$month,$day,$year);rnدر غیر اینصورت در php 7.0 به بالا پیام خطا میدهد چون پارامتر هفتم در این ورژن حذف شده است.