Farsi | English

[خانه] [درباره] [کتابها] [مقالات] [برنامه‌ها] [گالری عکس] [تماس] [ورود]

تبديل تاريخ تقويم هاي ميلادي/شمسي/قمري/رومي/عبري به يکديگر به زبان T-SQL

تاریخ: 1389/05/23
دفعات مشاهده: 31744
بازگشت
توضيح
اين صفحه به الگوريتم تبديل تاريخ به زبان T-SQL اختصاص دارد. اگر به دنبال الگوريتم دقيقي مي گرديد که تاريخ را از قالب ميلادي/هجري شمسي/هجري قمري/عبري/رومي به يکديگر تبديل کند، اين صفحه به شما تعلق دارد. الگوريتم اين کار در قالب يک اسکريپت T-SQL براي پايگاه داده SQL Server از حدود 50 تابع و روال تشکيل مي شود. اين اسکريپت بر اساس برنامه ديگري به زبان VB 6.0 که توسط آقاي مهدي وجودي نوشته شده به زبان T-SQL بازنويسي شده است.
تقويم هاي قابل استفاده
تکنولوژي پياده سازي
مجوز استفاده
استفاده از اين اسکريپت براي عموم افراد آزاد مي باشد.
ضمائم
توضيح
الگوريتم مزبور مجموعه‌اي است متشكل از 50 تابع و روال كه هر كدام عمليات به خصوصي را انجام مي‌دهد. براي سهولت استفاده و شسته رُفته شدن نحوه كار با آنها من 20 روال و 20 تابع جديد نيز اضافه كردم كه براي تبديل تاريخ‌ها كافي است فقط از اينها استفاده كنيد و نيازي نيست كاري با ساير توابع و روال‌هاي ديگري كه اسكريپت اين برنامه ايجاد مي‌كند داشته باشيد (اگرچه برخي از آنها مثل تابع Fix و Xor كه به ترتيب براي حذف قسمت اعشار يك عدد اعشاري و عمل ياي انحصاري يا Exclusive OR به كار مي‌رود جنبه عمومي دارد و مي‌توانيد آنها را در ساير جاها به دلخواه استفاده كنيد). نحوه نامگذاري روالها و توابعي كه ايجاد كرده‌ام بسيار شبيه هم است با اين تفاوت كه روال‌ها با حرف P و توابع با حرف U شروع مي‌شوند. ساختار نامگذاري بدين صورت است:
{P | U}DateConvert_{Source Calendar}2{Target Calendar}
P: SPROC Version
U: UDF Version
Source Calendar, Target Calendar ---> Christian | Hebrew | Islamic | Julian | Persian
ليست اسامي روال‌ها و توابع مزبور در زير آورده شده است:
SPROCS:
PDateConvert_Christian2Hebrew
PDateConvert_Christian2Islamic
PDateConvert_Christian2Julian
PDateConvert_Christian2Persian
PDateConvert_Hebrew2Christian
PDateConvert_Hebrew2Islamic
PDateConvert_Hebrew2Julian
PDateConvert_Hebrew2Persian
PDateConvert_Islamic2Christian
PDateConvert_Islamic2Hebrew
PDateConvert_Islamic2Julian
PDateConvert_Islamic2Persian
PDateConvert_Julian2Christian
PDateConvert_Julian2Hebrew
PDateConvert_Julian2Islamic
PDateConvert_Julian2Persian
PDateConvert_Persian2Christian
PDateConvert_Persian2Hebrew
PDateConvert_Persian2Islamic
PDateConvert_Persian2Julian
ساختار پارامترهاي تمام روال‌هاي مزبور شبيه هم بوده و بدين صورت است:
@Date VARCHAR(10),@Result CHAR(10) OUT,@SEPARATOR CHAR(1) = '/'
مثال:
DECLARE @Result CHAR(10)
EXEC dbo.PDateConvert_Christian2Persian '2010/08/15',@Result OUT
SELECT @Result

UDFs:
UDateConvert_Christian2Hebrew
UDateConvert_Christian2Islamic
UDateConvert_Christian2Julian
UDateConvert_Christian2Persian
UDateConvert_Hebrew2Christian
UDateConvert_Hebrew2Islamic
UDateConvert_Hebrew2Julian
UDateConvert_Hebrew2Persian
UDateConvert_Islamic2Christian
UDateConvert_Islamic2Hebrew
UDateConvert_Islamic2Julian
UDateConvert_Islamic2Persian
UDateConvert_Julian2Christian
UDateConvert_Julian2Hebrew
UDateConvert_Julian2Islamic
UDateConvert_Julian2Persian
UDateConvert_Persian2Christian
UDateConvert_Persian2Hebrew
UDateConvert_Persian2Islamic
UDateConvert_Persian2Julian
ساختار پارامترهاي تمام اين توابع نيز شبيه هم بوده و به صورت زير است. همگي آنها نيز يك رشته CHAR(10) بر مي‌گردانند.
@Date VARCHAR(10),@SEPARATOR CHAR(1) = '/'
مثال:
DECLARE @Result CHAR(10)
SET @Result = dbo.UDateConvert_Christian2Persian('2010/08/15','/')
نكات:
  • در رشته ورودي قالب تاريخ دريافتي به شكل YYYY/MM/DD فرض مي‌شود. لذا حتماً از سمت چپ ابتدا سال، سپس ماه و بعد روز را ذكر كنيد.
  • در صورتي كه شماره ماه يا روز يك رقمي باشد، نيازي به اضافه كردن صفر در كنار آن نيست (مثلاً 2 را به صورت 02 بنويسيد). لذا 2010/8/1 نيز معتبر است.
  • اما در رشته‌اي كه به عنوان نتيجه برگردانده مي‌شود، حتماً روز و ماه در حالت تك رقمي بودن با صفر همراه مي‌گردد. لذا رشته خروجي قطعاً 10 كاراكتر طول دارد.
  • به طور پيش فرض كاراكتر جداكننده روز، ماه و سال در تاريخ ورودي برابر '/' فرض مي‌شود. در صورتي كه روز، ماه، سال در تاريخ شما با كاراكتر ديگري نظير '-' جدا شده باشد (مانند 2010-03-04 يا 2010.4.2 يا 2010\5\12) مي‌توانيد از پارامتر @SEPARATOR استفاده كنيد و اين كاراكتر جداكننده را براي آن مشخص كنيد.
  • در حالت استفاده از SPROC در صورتي كه بخواهيد از مقدار پيش فرض كاراكتر جداكننده استفاده كنيد نيازي به ذكر پارامتر @SEPARATOR نيست اما در حالت استفاده از UDF بايد اين پارامتر را ذكر كنيد.
ماجرا
اگر شما هم جزو آن افرادي هستيد که کارشان به نوعي به بحث تقويم و تبديل تاريخ تقويم هاي مختلف به يکديگر مربوط شده و به دنبال الگوريتم مناسب و دقيقي براي اين کار مي گرديد، جاي درستي آمده ايد. براي من ماجراي الگوريتم تبديل تقويم به زبان T-SQL به يك پروژه وب بر مي گردد. تا قبل از آن کار تبديل تقويم را در سطح برنامه (Application) انجام مي دادم، اما در آن پروژه به انجام اين کار در خود پايگاه داده نياز پيدا کردم. در آن پروژه با استفاده از يک الگوريتم آماده، کارم راه افتاد. همه چيز ظاهراً به خوبي و خوشي مي گذشت تا اين که بعد از يک سال متوجه شدم الگوريتمي که استفاده کرده ام باگ دارد و در برخي مواقع تاريخ را با اختلاف 1 روز اشتباه حساب مي کند.
با توجه به اين که آن الگوريتم را به صورت تابع در آورده بوده و در جاهاي بسيار زيادي در پروژه استفاده کرده بودم، اين واقعه براي من چيز بسيار تلخي بود. چون يا بايد الگوريتم را ديباگ مي کردم كه اين بهترين حالت بود، و يا در غير اين صورت مي بايست الگوريتم ديگري پيدا مي کردم که بتوانم آن را جايگزين قبلي کنم. كه در اين حالت اين احتمال وجود داشت كه الگوريتم جديد قابل جايگزيني با قبلي نباشد كه اين خود دردسري بزرگ بود زيرا مي بايست تمامي جاهايي از برنامه از SPROC ها گرفته تا UDF ها و VIEW ها هر جايي كه تابع تبديل تاريخ مربوط به الگوريتم قبلي استفاده شده بود را دستكاري مي‌كردم (يعني چيزي حدود 70، 80 مورد!).
و متاسفانه ور رفتن با الگوريتم قبلي بيفايده بود. آن اوايل وقتي الگوريتم را ديدم پيش خودم گفتم عجب چيز مسخره اي، چون ظاهر بسيار بدقواره اي داشت و از لحاظ خوانايي برنامه نويسي بسيار بد نوشته شده بود (افرادي که برنامه نويس هستند مي دانند چه مي گويم). اما توجهي نكرده بودم. چون برايم مهم نبود اين جعبه چه آشغالي تويش است، همين که کارم را راه بيندازد و درست کار کند کافي است.
خوب. دست سرنوشت مرا مجبور کرد که بيايم سراغ اين جعبه آشغال و در آن را باز کنم. صرف نظر از اين که در حالت کلي ديباگ کردن يک الگوريتم کار سختي است و وقت زيادي از تو تلف مي كند تا از کارش سر در بياوري، آنهم الگوريتمي که خودت ننوشته باشي و آنهم الگوريتمي که خوانا نباشد، پس از آن كه به طور دقيق جزئيات آن را بررسي کردم تازه ديدم اين الگوريتم عجب فاجعه‌اي از نظر برنامه‌نويسي است!
محض اين که کمي مطلع شويد در دنياي برنامه نويسي چه خلاقيت هايي که نمي توان از خود بروز داد (!) من قسمت تبديل تاريخ ميلادي به شمسي الگوريتم مورد نظر را برايتان توضيح مي دهم.
الگوريتم مزبور در يک حلقه از سال 1900 ميلادي يا 1279 شمسي شروع کرده و سال به سال تمام روزها را جمع مي زد. در همين حين هم موقع حلقه زدن اگر سالي کبيسه بود، يک روز هم اضافي مي گرفت (و از من نپرسيد که سال کبيسه را چطور حساب مي کرد چون واقعاً فاجعه بود!). سپس اينقدر اين کار را ادامه مي داد تا به روز جاري مي رسيد و بعد جمع کل روزهاي به دست آمده را به اولين روز (1900/3/21) اضافه مي کرد تا روز فعلي محاسبه شود! خوب فکر کنم نيازي نباشد ديگر درباره اين الگوريتم وحشتناك بيشتر صحبت کنم و مطمئن هستم به من حق مي دهيد چرا براي رفع باگ اين الگوريتم وقت نگذاشتم!).
خوب. اولين راه با شکست مواجه شد. راه بعدي پيدا کردن الگوريتم مشابهي بود که بتوانم با كمترين تلفات و تبعات آن را جايگزين قبلي كنم.
همان طور که گفتم چيزي که من دقيقاً لازم داشتم، نسخه T-SQL اين الگوريتم بود و نه چيز ديگر. اما متاسفانه هرچه گشتم چيزي پيدا نکردم. در واقع الگوريتم اين تبديل به هر زباني بود به جز T-SQL! لذا آمدم سراغ سايت برنامه‌نويس که در ايران يکي از سايت هاي برنامه نويسي خوب است، ضمن اين که دوست عزيزم آقاي امين ثباتي هم يکي از مديران تالار گفتگوي SQL Server در آن بود. اما در آنجا هم پس از جستجو چيزي به دست نياوردم. لذا با کمال نا اميدي بحثي را ايجاد کردم با اين عنوان که آيا کسي الگوريتم تبديل تاريخ به T-SQL سراغ دارد يا خير.
از آنجايي که شک نداشتم برنامه نويسان .NET شروع مي کنند به معرفي برنامه هاي مختلفي که به .NET نوشته شده و با استفاده از کلاس PersianCalendar يک رويه ذخيره شده CLR در SQL Server ايجاد مي کند (چيزي که من نمي خواستم)، در ابتداي بحثي که ايجاد کردم دقيقاً نوشتم که دوستان عزيز، CLR نه ، فقط T-SQL!
دو سه روزي گذشته و خبري نشد. به خودم گفتم شايد واقعاً هنوز چنين چيزي خلق نشده و كسي واقعاً نسخه T-SQL الگوريتم تبديل تقويم را سراغ ندارد! تا اين كه پس از چند روز يک فردي الگوريتمي را معرفي کرد. با خوشحالي کُد معرفي شده را برداشتم. اما اين بار براي اين که همان بلايي که قبلاً سرم آمده بود دوباره سرم نيايد، اولين کاري که کردم آزمايش اين الگوريتم بود و متاسفانه مشاهده کردم که الگوريتم مزبور هم باگ دارد و در محاسبه سال هاي کبيسه اشتباه مي کند.
با توجه به اين كه فرصتم محدود بود و بايد هرچه سريع‌تر راهي براي تصحيح برنامه‌ام پيدا مي‌كردم ديدم فايده ندارد. ديگر نمي‌شود وقت را تلف كرد و بايد خودم دست به کار بشوم. خوشبختانه يك بار قبلاً در يک پروژة VB 6.0 با مساله تبديل تاريخ ميلادي به شمسي و بالعكس برخورد كرده بودم و آن موقع پس از جستجو در اينترنت نمونه برنامه اي به زبان VB 6.0 پيدا کرده بودم که فردي به نام مهدي وجودي در سايت خودش گذاشته بود. نکته بسيار مثبت برنامه صحت الگوريتم بود، ضمن اين که علاوه بر تاريخ هجري شمسي و ميلادي، سه تقويم ديگر هجري قمري، عبري و رومي را هم پشتيباني مي کرد. لذا بدون هيچ ترديدي يک راست رفتم سراغ اين برنامه تا خودم آن را به T-SQL تبديل کنم.
و در نهايت چيزي شد که الان در اين صفحه گذاشته ام. يعني الگوريتم دقيق تبديل تاريخ و تقويم به زبان T-SQL. خوب ارزشش را داشت. البته وقتي با زهم به بحثي كه در تالار گفتگوي سايت برنامه‌نويس ايجاد كرده بودم سر زدم مشاهده كردم فرد ديگري يك الگوريتم ديگر را معرفي كرده، اما وقتي آن را هم آزمايش كردم ديدم آن الگوريتم هم باگ دارد، لذا ديدم چيزي را از دست نداده‌ام. اميدوارم اين توابع تبديل تاريخ اين اسكريپت براي شما هم مفيد باشد.
بسیار عالی است بنحوی که بنده گیج شدم خواهشی داشتم اگر امکان داشت شما برایم یک محاسبه انجام دهید : 25/12/1339 شمسی را به قمری از همان روز محاسبه و اعلام فرمائید. اجرکم عندالله

yavaliollah@yahoo.com 1389/06/30 4:58:
سلام. ضمن پوزش بابت تاخير در بررسي نظر شما به علت گرفتاري بسيار زياد. براي تبديل تاريخ مي توانيد از سايت مرکز تقويم موسسه ژئوفيزيک به آدرس calendar.ut.ac.ir استفاده کنيد (http://calendar.ut.ac.ir/Fa/Software/RunCalConv.asp). الگوريتم T-SQL پياده سازي شده در اين صفحه نيز همان تاريخ را بر مي گرداند.

me@m-omrani.ir 1389/08/16 11:19
ba salamo khaste nabashid man ino download kardam ,lotfan tarigh nasbesho to website bedin mamnoon misham اسكريپت كامل تبديل تقويم ميلادي/رومي/شمسي/قمري/عبري به يكديگر به صورت فشرده در قالب ZIP (17.79 KB) hatef

hatef777@gmail.com 1389/10/19 7:40:
سلام اگر امکانش براتون هست می خواستم تاریخ 7 حزیران سال جاری( سال 90) رو به شمسی برام ارسال کنید. قبلا از شما متشکرم

arash1150@yahoo.com 1390/03/16 12:34
سلام : خیلی از برنامه های خوبتان می خواستم برای گواهینامه بین المللی شرکت کنم که گفتند با تاریخ مثلاً 01/09/1360 را 27/03/1981 تبدیل کنی می توانید این کار را برایم انجام دهید. با تشکر

z.shahabi60@gemil.com 1390/06/28 7:57:
هر چیزی نکاتی دارد و زکات علم هم آموزش ان به دیگران

rezaie.abbas_s@yahoo.com 1390/08/30 12:16
برای تبدیل تاریخ می‌توانید از آدرس http://calendar.ut.ac.ir/Fa/Software/CalConv.asp (مرکز تقويم موسسه ژئو فیزیک دانشگاه تهران) استفاده کنید. جناب شهابی. این آدرس و همچنین الگوریتمی که در این مقاله قرار داده‌ام هر دو برای 1 آذر 1360 (01/09/130) تاریخ 22 اکتبر 1981 (22/11/1981) را بر می‌گردانند. با سپاس از همه‌ی دوستان.

me@m-omrani.ir 1390/09/05 1:05:
ok

ali1390.ir12@yahoo.com 1390/10/06 2:58:
سلام.من هم مشابه داستانی که شما تجربه کردید را با برنامه های خودم داشتم. و این شد که آمدم سراغ TSQL. توابع شما را در یک برنامه نمونه استفاده کردم و تا الان که خوب جواب داده. بسیار بسیار ممنون از زحمتی که کشیدید و توابعی که در اختیار سایر برنامه نویسان هم قرار دادید.

kamal@yahoo.com 1391/10/27 9:36:

= 1 + 10