آموزش تبدیل تاریخ میلادی به شمسی | سورس کد و الگوریتم

در این مطلب درباره تبدیل تاریخ میلادی به شمسی صحبت خواهیم کرد. همچنین به بررسی الگوریتم و نمونه کد که برای تبدیل تاریخ میلادی به شمسی استفاده می شود خواهیم پرداخت. نمونه سورس کد پیش رو برای آگاهی شما از تاریخ جلالی پست شده تا دید کلی نسبت به این قضیه پیدا کنید. الگوریتم مورد نظر برای زبان برنامه نویسی swift نوشته شده که برروی شبیه ساز ios و mac تست شده است. لازم به ذکر است از ابزار های swift 2.1.1 و نیز xcode7.2 استفاده شده است . اولین انتشار در تاریخ 1395 می باشد .

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

الگوریتم تبدیل تاریخ میلادی به شمسی

  1. برای نوشتن الگوریتم به اختلاف روز های میان اولین روز سال میلادی ( 1 ژانویه ) و اولین روز سال شمسی ( 20 مارس ) نیاز داریم که برابر با "79" می باشد . 
  2. در این مرحله باید تشخیص دهیم که سال میلادی کبیسه است یا خیر . برای اینکار باید سال میلادی داده شده را بر 4 تقسیم کنیم ، اگر بخشپذیر بود ( باقیمانده برابر صفر ) سال کبیسه است در غیر اینصورت سال میلادی کبیسه نیست . 
  3. با توجه به کبیسه بودن یا کبیسه نبودن سال مشخص می کنیم که در کدامین روز سال میلادی قرار داریم ، که در اینصورت با دو حالت روبرو خواهیم شد : 

 1-3- سال کبیسه باشد

1-1-3- روزی که در آن قرار داریم از 79 بیشتر باشد

به این معنی است که در ماههای بعد از فروردین قرار داریم . حال باید مشخص کنیم که در 6 ماه اول سال شمسی قرار داریم یا در 6 ماه دوم سال قرار داریم . برای اینکار ابتدا " 79 " روز از تعداد روز ها کم می کنیم تا در اول فروردین ماه قرار بگیریم . اگر تعداد روز های بدست آمده از  " 186  " ( 31 * 6 ) کمتر باشد یعنی در 6 ماه اول سال شمسی قرار داریم ، در غیر اینصورت در 6 ماه دوم قرار داریم .                              

1-1-1-3- اگر در 6 ماه اول سال قرار گرفته باشیم ( dates <= 186 )


تعداد روزها را بر " 31 " تقسیم می کنیم ( چرا بر 31 تقسیم کنیم ؟ به این دلیل که در 6 ماه اول سال شمسی قرار داریم . ) ، اگر باقیمانده این تقسیم صفر شد ، خارج قسمت تقسیم برابر با ماه شمسی می شود و روز شمسی برابر با 31 می شود . در غیر اینصورت اگر باقیمانده صفر نشود ماه شمسی برابر با خارج قسمت به اضافه ی یک می شود و روز شمسی همان باقیمانده است .                                                                                        

2-1-1-3- اگر در 6 ماه دوم سال قرار گرفته باشیم


" 186 " روز از تعداد روز ها کم می کنیم و آن را بر " 30 " تقسیم می کنیم ( چرا بر 30 تقسیم می کنیم ؟ چون در 6 ماه دوم سال قرار گرفته ایم  و ماه ها 30 روزه می باشند . ) . اگر باقیمانده این تقسیم صفر شد ، خارج قسمت تقسیم به اضافه " 6 " و برابر ماه شمسی قرار خواهد گرفت و روز شمسی برابر  با  30 می شود . اگر باقیمانده صفر نشود ماه شمسی برابر با خارج قسمت به اضافه " 7 " می شود و روز شمسی همان باقیمانده است و در نهایت سال شمسی از تفاضل سال میلادی با " 621 "  بدست می آید .چرا برای بدست آوردن سال شمسی ، سال میلادی را از   621  کم کردیم ؟  همان طور که در بالا ( 3-1-1 ) ذکر کردیم ، یعنی روز مورد نظر بین اول فروردین تا 11 دی می باشد . 

2-1-3- روزی که در آن قرار داریم کمتر از " 79 " است                

به این معنی است که در روزهای بین اولین روز سال میلادی تا اولین روز سال شمسی ( دی ، بهمن ، اسفند ) قرار داریم . اختلاف روز بین اولین روز سال میلادی داده شده و اولین روز دی ماه در سال شمسی را در نظر می گیریم که این اختلاف برای سال کبیسه  " 11 " و برای سال غیر کبیسه  " 10 " می باشد .        

  • تــوجــه : در این الگوریتم برای مشخص کردن این اختلاف باید سال قبل از سال داده شده را در نظر بگیریم ، به این دلیل که سال قبل بر روی اولین روز سال میلادی تاثیر می گزارد .                    

در نهایت اختلاف تاریخ بدست آمده را با تعداد روز ها جمع می کنیم و آن را بر " 30 "  تقسیم می کنیم ( 3 ماه آخر سال شمسی 30 روزه است . ) ، اگر باقیمانده این تقسیم صفر شود ، خارج قسمت تقسیم به اضافه ی " 9 " برابر  با ماه برابر با خارج قسمت به اضافه " 10 " می شود و روز شمسی همان باقیمانده است . در این حالت سال شمسی از تفاضل سال میلادی با " 622 " بدست می آید . ( چون بین 11 دی تا آخر اسفند قرار داریم . )     

 2-3- سال کبیسه نباشد

 دقیقا به مانند الگوریتم سال کبیسه عمل می کنیم ، البته با کمی تفاوت که با مطالعه ی SourcCode متوجه آن خواهید شد . 

راهنما 

1- بهتر است برای هر دو سال های میلادی کبیسه و غیر کبیسه یک آرایه ی جداگانه در نظر گرفته شود  .

2- برای مقدار دهی به آرایه های سال کبیسه و غیر کبیسه ، در این الگوریتم باید با توجه به جدول زیر  عمل کنیم : 

پارامتر های تبدیل تاریخ میلادی به شمسی

به طور مثال ) می خواهیم آرایه ای از سال غیر کبیسه ( not_leap_year ) را با توجه به جدول بالا مقدار دهی کنیم :

مقدار دهی آرایه به این شکل است که :  عنصر قبل  + عنصر بعد  ،  با این شرط که اولین عنصر از آرایه مقدار صفر (0) را دارد .

not_leap_year = [ 0 , January + 0 , ( January + 0 ) + 28 , .... ]
 not_leap_year = [ 0 , 0 + 31 , 31 + 28 , 59 + 31 , 90 + 30 , 120 + 31 , 151 + 30 , 181 + 31 , 212 + 31 , 
243 + 30 , 273 + 31 , 304 + 30 ]
  • نـکتـه 1 : برای not_leap_year ( سال غیر کبیسه ای ) عدد 28 را در نظر می گیریم . برای is_leap_year (سال کبیسه ای ) عدد 29 را در نظر می گیریم . 
  • نـکتـه 2 : باید دقت داشته باشید که طول آرایه از عدد 12 تجاوز نکند ، چون هر سال 12 ماه دارد . 

کد تبدیل تاریخ میلادی به شمسی

در ادامه بپردازیم به سورس کد تبدیل تاریخ میلادی به شمسی. تابع calcSolarCalendar به صورت یک method تعریف شده و عینا مانند الگوریتم بالا می باشد  . از ویژگی های این الگوریتم : 

  • بدست آوردن تاریخ شمسی از میلادی 
  • بدست آوردن ماه شمسی 
  • بدست آودن روز شمسی 

نــکــته : دوستان دقت داشته باشید برای تست این الگوریتم فقط از سایت Time.ir استفاده کنید . بقیه سایت ها رو که تست کردم الگوریتم درستی نداشتند.

/** in Swift2.1.1 and XCode7.2 **/

import UNIKit
import Foundation

class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. //call the solarcalendar method CalcSolarCalendar() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }

// calcSolarDate method
internal func CalcSolarCalendar(){ var difference_between_days:Int = 0
var strMonth = "" var date:Int = 0 var month:Int = 0 var year:Int = 0 //get day , month and year from your divice let date_miladi = NSDate() let calendar = NSCalendar.currentCalendar() let components = calendar.components([.Day , .Month , .Year], fromDate : date_miladi) let year_miladi = components.year let month_miladi = components.month let day_miladi = components.day


//date convert to string and send to the getDayOfWeek method let dateFormater = NSDateFormatter() dateFormater.dateFormat = "yyy-MM-dd" let dateString = dateFormater.stringFromDate(date_miladi)

//day of month let not_leap_year = [0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334] let is_leap_year = [0 , 31 , 60 , 91 , 121 , 152 , 182 , 213 , 244 , 274 , 305 , 335] if ((year_miladi % 4 ) != 0) { date = not_leap_year[month_miladi - 1 ] + day_miladi if(date > 79){ date = date - 79 if(date <= 186){ switch (date % 31){ case 0: month = date / 31 date = 31 break ; default: month = (date / 31) + 1 date = (date % 31) break ; } year = year_miladi - 621 ; }else{ date = date - 186; switch(date % 30){ case 0 : month = (date / 30 ) + 6 date = 30 break; default: month = (date / 30 ) + 7 date = (date % 30) break; } year = year_miladi - 621 } }else{ if((year_miladi > 1996) && (year_miladi % 4) == 1 ){ difference_between_days = 11 }else{ difference_between_days = 10 } date = date + difference_between_days switch(date % 30){ case 0 : month = (date / 30) + 9 date = 30 break; default: month = (date / 30) + 10 date = (date % 30) break; } year = year_miladi - 622; } }else{ date = is_leap_year[month_miladi - 1] + day_miladi if(year_miladi >= 1996){ difference_between_days = 79 }else{ difference_between_days = 80 } if(date > difference_between_days){ date = date - difference_between_days if(date <= 186){ switch (date % 31) { case 0 : month = (date / 31) date = 31 break; default: month = (date / 31) + 1 date = (date % 31) break; } year = year_miladi - 621 }else{ date = date - 186 switch( date % 30){ case 0 : month = (date / 30 ) + 6 date = 30 break; default: month = (date / 30 ) + 7 date = (date % 30 ) break; } year = year_miladi - 621 } }else{ date = date + 10 switch (date % 30){ case 0 : month = (date / 30 ) + 9 date = 30 break; default: month = (date / 30 ) + 10 date = (date % 30) break; } year = year_miladi - 622; } } switch(month){ case 1: strMonth = "فرودین" break; case 2: strMonth = "اردیبهشت" break; case 3: strMonth = "خرداد" break; case 4: strMonth = "تیر" break; case 5: strMonth = "مرداد" break; case 6: strMonth = "شهریور" break; case 7: strMonth = "مهر" break; case 8: strMonth = "آبان" break; case 9: strMonth = "آذر" break; case 10: strMonth = "دی" break; case 11: strMonth = "بهمن" break; case 12: strMonth = "اسفند" break; default: break; } let dateFormatter = NSDateFormatter() dateFormatter.locale = NSLocale(localeIdentifier: "en_US") //casting int to string let int_year_solar:Int = year let String_year = String(int_year_solar) //Converting to Solar date extention (YYY/MM/DD) let format_month = String(format:"%02d" , month) let format_date = String(format: "%02d" , date) print("date Solar is : " + String_year + "/" + format_month + "/" + format_date) print("Month is : " + strMonth)


// date string sened to DayOfWeek Method getDayOfWeek(dateString)
}

// getDayOfWeek method func getDayOfWeek (today:String) { let formatter = NSDateFormatter() formatter.dateFormat = "yyy-MM-dd"
if let todayDate = formatter.dateFromString(today){
let myCalendar = NSCalendar(calendarIdentifier: "gregorian") let myComponents = myCalendar?.components(.Weekday, fromDate: todayDate) let weekDay = myComponents?.weekday let weekDay_solar = ["شنبه" , "یکشنبه" , "‍ دو شنبه" , "سه شنبه" , "چهارشنبه" , "پنج شنبه" , "جمعه"] if(weekDay != 7){ for var i=0 ; i <= weekDay_solar.count ; i++ { if(weekDay == i){ print("day is : " + weekDay_solar[i]) } } }else{ print("day is : " + weekDay_solar[0]) } } } }

/*
output is :
date solar is : 1395/07/02
month is : مهر
day is : جمعه
*/

اگر قصد دارید مقادیر تاریخ میلادی را دستی وارد کنید و یا کاربر خودش دستی وارد کند می توانید به روش زیر و با توجه به کد بالا مقادیر را وارد کنید :

let year_miladi = 2016
let month_miladi = 9 let day_miladi = 23


        /*
output is :
date solar is : 1395/07/02
month is : مهر
day is : جمعه
*/


من در سورس کد بالا که کار تبدیل تاریخ میلادی به شمسی را انجام می دهد، علاوه بر تبدیل تاریخ و بدست آوردن ماه شمسی  ، متدی برای بدست آوردن روز های هفته با استفاده از Swift نوشتم و برای اینکه درک source code بالا برای شما مشکل نباشه آن ( func getDayOfWeek ) را به صورت جداگانه در این تاپیک قرار می دهم . 

/** Tested in the Swift2.1.1 and XCode7.2 **/
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib.
// get day , month and year form your device let date_miladi = NSDate() let calendar = NSCalendar.currentCalendar() let components = calendar.components([.Day , .Month , .Year], fromDate : date_miladi) //date convert to string let dateFormater = NSDateFormatter() dateFormater.dateFormat = "yyy-MM-dd" let dateString = dateFormater.stringFromDate(date_miladi)
// call the method getDayOfWeek(dateString) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // getDayOfWeek method func getDayOfWeek (today:String) { let formatter = NSDateFormatter() formatter.dateFormat = "yyy-MM-dd" if let todayDate = formatter.dateFromString(today){ let myCalendar = NSCalendar(calendarIdentifier: "gregorian") let myComponents = myCalendar?.components(.Weekday, fromDate: todayDate) let weekDay = myComponents?.weekday let weekDay_solar = ["شنبه" , "یکشنبه" , "‍ دو شنبه" , "سه شنبه" , "چهارشنبه" , "پنج شنبه" , "جمعه"] if(weekDay != 7){ for var i=0 ; i <= weekDay_solar.count ; i++ { if(weekDay == i){ print("day is : " + weekDay_solar[i]) } } }else{ print("day is : " + weekDay_solar[0]) } } } }

نکــته : در هنگام تعریف آرایه در زبان swift وقتی عناصر فارسی داخل آرایه تعریف می کنید باید دقت داشته باشید که عناصر فارسی از سمت راست index گزاری می شوند و اگر اشتباه نکنم این ویژگی در زبان برنامه نویسی جاوا بر عکس است . 

سوال ) می خوام ورودی را با استفاده از EditText و از کاربر دریافت کنم ولی روز مورد نظر را به درستی برای من نمایش نمی دهد باید چیکار کنم ؟ 

جواب : کاملا حق با شماست به این دلیل که من فقط و فقط تاریخ سیستم را به متد getDayOfWeek ای که نوشتم ارسال می کنم و نه تاریخ ورودی کاربر . بنابراین برای زمانی که بخواهیم ورودی را از کاربر دریافت کنیم باید به شیوه ی زیر الگوریتم را تغییر دهیم :

//getting input from the user
let year_miladi = 1932
let month_miladi = 9
let day_miladi = 23

//Casting int variable to String
let stryear= String(year_miladi)
let strmonth = String(month_miladi)
let strday = String(day_miladi)

//format (yyy-MM-dd)
let totaldate = stryear + "-" + strmonth + "-" + strday

// send totaldate to getDayOfWeek Method
getDayOfWeek(totaldate)


/*
output is :
date solar is : 1395/07/01
Month is : مهر
day is : جمعه
*/

حسن  سهرابیان
حسن سهرابیان

Developer

برنامه نویس و فارغ التحصیل رشته مهندسی کامپیوتر / نرم افزار . عاشق یادگیری و هر روز رو بهتر از دیروز میدونه . سعی میکنه دانش خودش رو بدون نویز در اختیار دنیای وب قرار بده . از القابی نظیر : مهندس ، دکتر ، GEEK , NERD ، FullStack و.. به شدت دوری کرده و هیچ اهمیتی به آنها نمی دهد و در نظر ایشان بر چسب ها همانند Show off می مانند

نظرات