یکی از مسائل مهم در طراحی سیستمهای مبتنی بر 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 همان خط گرینویچ یعنی ساعت لندن است.
نکته: اگر شما بر روی هر سروری، تابع date را در PHP فراخوانی کنید، نرم افزار PHP ابتدا به Time Zone سیستم شما نگاه میکند. مثلاً Time Zone سیستم من روی Tehran تنظیم است. یعنی 3 ساعت و 30 دقیقه جلوتر از ساعت لندن. (البته در شش ماه اول، 4 ساعت و 30 دقیقه جلوتر خواهد بود و نرم افزار، آنرا تشخیص خواهد داد)
اینکه گفته میشود تاریخ مورد نظرتان را به GMT در دیتابیس ثبت کنید به خاطر این است که اگر خواستید سیستم را بین المللی کنید، فقط کافیست Time Zone کشور کاربر را در فایل config.php یا در دیتابیس بگیرید و ذخیره کنید تا همه تاریخها را به راحتی با افزایش یا کاهش اختلاف ساعت، به ساعت مورد نظر کاربر نمایش دهید. اما اگر بر اساس تهران درج کنید، باید همیشه یک بار به GMT تبدیل کنید و سپس به زمان مورد نظر کاربر.
- به کاربر تاریخ شمسی را نمایش دهید. (بر اساس ساعت تهران)
- تاریخ شمسی را بگیرید و به میلادی تبدیل کنید.
- تاریخ میلادی را بر اساس GMT به دست آورید.
- با ساختاری که نوع فیلد دیتابیس دارد، آنرا در دیتابیس درج کنید.
برای نمایش تاریخ شمسی به کاربر، پیش از این مقالهای نوشتهایم که دعوت میکنم آنرا مطالعه کنید:
در آن مقاله توضیح دادهایم که برای تبدیل تاریخ میلادی به شمسی از توابع کتابخانه 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>';
در PHP تابع mktime، شش پارامتر تاریخ و زمان را میگیرد و timestamp را بر میگرداند.
اولاً منظور از 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 تبدیل کردیم.
ما تایم استمپ را بر اساس GMT داریم. اما موضوع این است که چطور در دیتابیس درج کنیم.
خیلی ساده است. با استفاده از تابع date، آن تایم استمپ را به فرمت دلخواه خود درآورید و در دیتابیس درج کنید.
مثلاً در این مثال، ما خروجی قطعه کد بالا را به صورت DATETIME تبدیل میکنیم و در دیتابیس درج میکنیم:
$datetime = date("Y-m-d H:i:s",$timestamp);
متغیر datetime را در دیتابیس درج کنید.
تا اینجا، ما توانستهایم تاریخ شمسی را از کاربر بگیریم و به صورت میلادی مبتنی بر 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'){
از این به بعد تاریخ بر اساس تهران و به صورت انگلیسی دیده خواهد شد.
موفق باشید؛
حمید رضا نیرومند
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 به بالا پیام خطا میدهد چون پارامتر هفتم در این ورژن حذف شده است.