در این مقاله به معرفی روش های مختلف جهت ذخیره سازی زمان و تاریخ در پایگاه داده و نمایش اطلاعات و مشکلات مربوطه می پردازم.
یکی از مشکلات متداولی که برنامه نویسان برنامه های تحت وب و به طور کلی برنامه های توزیع شده (Distributed Applications) با آن روبرو هستند، ذخیره سازی تاریخ و زمان در پایگاه داده می باشد.
ادامه مقاله را با ذکر دو مثال دنبال می کنیم. با بایت لرن همراه باشید.
اگر شما برای یک منطقه خاص جغرافیایی (Time Zone) برنامه نویسی انجام می دهید، شاید نحوه ذخیره سازی تاریخ و زمان چندان مسئله ساز نباشد و شما براحتی با استفاده از دستور DateTime.Now در فریم ورک DotNet و یا با استفاده از متد GETDATE در پایگاه داده SQL Server مشکل خود را حل نمایید. دلیل این موضوع این است که در یک منطقه جغرافیایی خاص، تاریخ و زمان در تمام نقاط یکسان می باشد. به طور مثال هنگامی که در تهران ساعت 4:30 باشد، در مشهد، اصفهان و تبریز نیز ساعت 4:30 است و در نتیجه تاریخ و زمان ذخیره سازی برای ساعت 4:30 کاملا معتبر می باشد.
ولی در مورد کشور هایی که در مناطق مختلف جغرافیایی قرار دارند، این موضوع متفاوت می باشد زیرا مناطق مختلف جغرافیایی با یکدیگر اختلاف زمانی دارند. مثلا هنگامی که در کشور ایران ساعت 4:30 می باشد، در کشور های کانادا و ایالت های مختلف امریکا، ساعت چندین ساعت جلوتر و یا عقب تر می باشد.
فرض کنید قرار است کنفرانسی در تاریخ 1 دسامبر و ساعت 18:30 قرار است در یک از ایالت های امریکا برگزار گردد و شما قصد دارید از تمام افراد واجد شرایط در کشورهای مختلف دنیا برای این کنفرانس دعوت به عمل آورید. ایالت های مختلف امریکا در منطقه های جغرافیایی مختلفی قرار دارند. یعنی مثلا اگر کنفرانس قرار باشد در ساعت 18:30 به وقت تگزاس برگزار گردد، این ساعت ممکن است برابر ساعت 14:30 به وقت ایالت دالاس باشد! پس چگونه باید تاریخ و زمان را اعلام نمود؟
به مثالی دیگر توجه فرمایید.
فرض کنید شما در حال طراحی یک برنامه تالار گفتمان هستید. شخصی در یک منطقه زمانی خاص سوالی را در این تالار مطرح می کند و شما تاریخ مطرح شدن سوال را براحتی ذخیره می کنید. این تاریخ می تواند 14 دسامبر 2018 ساعت 16:30 باشد. اکنون شخص دیگری وارد تالار گفتمان می شود که در منطقه جغرافیایی متفاوتی قرار دارد. این شخص ملاحظه می کند که تاریخ ثبت شده برای این سوال، مربوط به چند ساعت بعد می باشد که هنوز فرا نرسیده است! چگونه باید این مشکل را رفع نمود؟
قبل از اینکه به جواب دادن به سوالات فوق بپردازم لازم می باشد که مقدمه ای را بیان کنم.
برای ذخیره نمودن تاریخ در پایگاه داده SQL Server معمولا از دو روش استفاده می شود. یا تاریخ توسط برنامه برای پایگاه داده ارسال می شود (به طور مثال با استفاده از دستور DateTime.Now) و یا اینکه با استفاده از تابع GETDATE مربوط به SQL Server و از طریق پایگاه داده این عمل انجام می شود. (در اینجا فرض بر این است که نوع فیلد پایگاه داده از جنس DateTime می باشد و بنده قصد معرفی انواع مختلف فیلد های پایگاه داده SQL Server را که جهت نگهداری انواع تاریخ و زمان استفاده می شود را ندارم)
اگر وب سایت و پایگاه داده بر روی یک سرور و یا در یک منطقه جغرافیایی باشند، تفاوت چندانی بین دو روش ذکر شده در بالا وجود ندارد ولی اگر سرور وب سایت در یک منطقه جغرافیایی و سرور پایگاه داده در یک منطقه دیگر جغرافیایی قرار داشته باشد، بدیهی است که زمان ذخیره شده در پایگاه داده با زمانی که کاربر در وب سایت اطلاعات را وارد نموده است، متفاوت می شود.
بهترین روش:
اما بهترین روش برای حل مشکلاتی که در بالا ذکر شد، استفاده از زمان استاندارد بین المللی یعنی Coordinated Universal Time یا به عبارت دیگری UTC می باشد. این زمان در تمام مناطق جغرافیایی یکسان می باشد. یعنی اگر زمان UTC در حال حاضر14 دسامبر 2018 و ساعت 16:30 باشد، این ساعت در تمام دنیا یکسان می باشد. در فریم ورک DotNet با استفاده از دستور DateTime.UtcNow و در پایگاه داده SQL Server با استفاده از تابع GETutcDATE می توانید به این تاریخ و زمان دسترسی پیدا نمایید.
در شکل زیر حاصل دو دستور مختلف ذکر شده برای پاگاه داده SQL Server را ملاحظه می نمایید.
دقت کنید که حاصل اجرای دستور GETDATE ساعت 22:58 می باشد در حالیکه حاصل اجرای دستور GETutcDATE ساعت 18:28 می باشد. مبنای تشخیص ساعت تمام مناطق جغرافیایی بر اساس تاریخ و زمان UTC می باشد و ما همواره با اضافه و یا کم نموده میزان مشخصی از زمان UTC می توانیم تاریخ و زمان هر منطقه جغرافیایی را بدست آوریم.(در ادامه مقاله این موضوع را ملاحظه می نمایید)
توجه:
میزان زمانی که با توجه به تاریک و روشن بودن هوا در کشور های مختلف از ساعت رسمی کم و زیاد می شوند (Daylight Saving) در تاریخ و زمان UTC مورد محاسبه قرار نمی گیرد. به طور مثال در کشور ما در ابتدای سال یک ساعت زمان رسمی به جلو کشیده شده و در ابتدای شش ماهه دوم، این زمان مجددا به عقب کشیده می شود.
تاکنون مشکل ذخیره سازی تاریخ و زمان را حل نموده ایم ولی مسئله ای که هم اکنون وجود دارد این است که چگونه این زمان را نمایش دهیم. به عبارت دیگر، کاربران و مخاطبین وب سایت معمولا آگاهی چندانی در مورد تبدیل زمان بین المللی UTC به زمان منطقه جغرافیایی خود ندارند و شما صرفا با نمایش تاریخ UTC کمک چندانی به مخاطبین خود ننموده اید.
در اینجا نحوه های مختلف نمایش زمان را ملاحظه می نمایید.
-
نمایش تاریخ و زمان دقیقا همانطور که در پایگاه داده ذخیره شده است
-
نمایش تاریخ و زمان به صورت نسبی و تقریبی
-
نمایش تاریخ و زمان متناسب با هر منطقه جغرافیایی
اکنون به معرفی هر کدام از این روش ها می پردازیم.
نمایش تاریخ و زمان دقیقا همانطور که در پایگاه داده ذخیره شده است:
در این روش، تاریخ را همانگونه که در پایگاه داده ذخیره شده است، در برنامه نمایش می دهیم. بدیهی است که این روش جهت وب سایت هایی که فعالیت در چند منطقه جغرافیایی مختلف دارند، چندان مناسب نمی باشد.
نمایش تاریخ و زمان به صورت نسبی و تقریبی:
در این روش نمایش تاریخ و زمان بسیار جالب می باشد. اگر به سایت های مربوط به شبکه های اجتماعی و یا تالارهای گفتمان مراجعه نموده باشید، بارها با این موضوع روبرو شده اید که زمان گذاشتن مطلب به شکل های زیر نمایش داده می شود:
-
یک دقیقه پیش
-
سه ساعت پیش
-
دو روز پیش
-
30 ثانیه پیش
این سبک نمایش تاریخ بسیار متداول می باشد و در سایت هایی کاربرد دارد که زمان دقیق، چندان مورد اهمیت نمی باشد. در این روش شما با استفاده از تاریخ ثبت شدن سوال و زمان حال، می توانید مدت زمان سپری شده را محاسبه نمایید و دیگر توفیری ندارد که شخص بازدیدکننده در وب سایت در کدام منطقه جغرافیایی قرار دارد.
در قسمت زیر یک پیاده سازی به زبان #C و به صورت متدهای توسعه گر(Extension Method) برای کلاس DateTime ملاحظه می نمایید.
public static class DateTimeExtensions public static string ToRelativeDateString(this DateTime date)
|
اگر زمان را به شکل معمولی ذخیره نموده باشیم، با استفاده از متد ToRelativeDateString می توانیم زمانی نسبی مورد نظر را بدست آوریم و در صورتی که زمان را به شکل UTC ذخیره نموده باشیم، با فراخوانی تابع ToRelativeDateStringUtc می توانیم زمان نسبی سپری شده را بدست آوریم.
در قسمت زیر نحوه استفاده از متدهای بالا را ملاحظه می نمایید:
DateTime dateTime = GetDatabaseTime(); string relativeTimeString= DateTime.ToRelativeDateString(dateTime); DateTime dateTime = GetDatabaseUtcTime(); string relativeTimeString = DateTime.ToRelativeDateStringUtc(dateTime); |
نمایش تاریخ و زمان متناسب با هر منطقه جغرافیایی:
در این روش ما زمان را به صورت UTC در دیتابیس ذخیره می کنیم و سپس منطقه جغرافیایی کاربر را بدست می آوریم. اکنون زمان ذخیره شده به شکل UTC را تبدیل به زمان مورد استفاده کاربر در یک محدوده جغرافیایی خاص می کنیم.
فرض کنید که یک کاربر از کشور ایران وارد وب سایت می شود و قصد داریم زمانی که در دیتابیس به شکل UTC ذخیره شده است را به زمان منطقه جغرافیایی ایران تبدیل کنیم. برای انجام این کار باید مشابه زیر عمل نماییم.
TimeZoneInfo timeZoneInfo; DateTime dateTime; //Set the time zone information to Iran Standard Time timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time"); //Get date and time in Iran Standard Time dateTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, timeZoneInfo); //Print out the date and time Label1.Text = dateTime.ToString(); |
در قطعه کد بالا ما شناسه منطقه جغرافیایی (Time Zone ID) ایران("Iran Standard Time") را به تابع FindSystemTimeZoneById ارسال نموده ایم و این تابع، مشخصات منطقه جغرافیایی ایران را برگردانده است. سپس با استفاده از دستور TimeZoneInfo.ConvertTime زمان دخیره شده به شکل UTC تبدیل به زمان مورد استفاده در منطقه جغرافیایی ما می شود.
لیست چند شناسه مناطق مختلف جغرافیایی جهان را در قسمت زیر ملاحظه می نمایید.
|
در صورتی که شما قصد دارید از این روش جهت نمایش تاریخ استفاده نمایید، بهتر است از کاربران هنگام ثبت نام در سایت، نام منطقه جغرافیایی مورد نظر آن ها را سوال نموده و ذخیره نمایید (حتما تاکنون هنگام ثبت نام در تالار های گفتمان با گزینه انتخاب Time Zone مواجه شده اید)
در غیر اینصورت باید با توجه به IP کاربر منطقه جغرافیایی را محاصبه نموده و سایر موارد را اعمال نمایید.
نمایش تاریخ با فرمت مناسب:
یکی دیگر از مشکلاتی که هنگام نمایش تاریخ با آن روبرو هستیم، فرمت نمایش تاریخ می باشد.
به نحوه نمایش تاریخ در چند فرهنگ زیر توجه نمایید:
// Iran --> YYYY/MM/DD -- روز/ماه/سال // USA --> MM/DD/YYYY -- سال/روز/ماه // United Kingdom --> DD/MM/YYYY -- سال/ماه/روز |
همانطور که ملاحظه می نمایید، تاریخ 5/7/2018 در کشور انگلستان و امریکا کاملا معنی متفاوتی می دهد. در انگلستان این تاریخ برابر پنجم ماه جولای سال 2018 می باشد در حالیکه در امریکا این تاریخ هفتم ماه MAY سال 2018 معنا می دهد!
برای نمایش تاریخ های میلادی پیشنهاد می شود از فرمت های زیر بنابر نیاز خود استفاده نمایید.
string result = DateTime.Now.ToString("d MMM yyyy h:mm tt"); // result is --> 10 Apr 2018 12:26 AM
|