UNPKG

prs-utils

Version:

Prs Utilities

830 lines (769 loc) 25.7 kB
// Multi calendar prs-multi-calendar.js // This calendar supports Gregorian, Persian (Jalalian) and // Arabic (Lunar) calendar types: // 2020/11/27 (Gregorian) // 1399/09/07 (Persian Jalali) // 1442/04/11 (Lunar Arabic) // By: Ahmad Parszadeh parszadeh.ahmad@gmail.com function MultiCalendar() { /*Global Values*/ var GREG_ORG_GDP = 0 /* The origine of Gerigorian calendar (0001/01/01 Greg)*/ var GREG_MAX_GDP = 3652058 /* Days passd from 1/1/1 AD to 9999 Dec 31 AD which is the maximum supported date in gregorian calendar (9999/12/31 Greg)*/ var JAL_MAX_GDP = 3652058 var JAL_ORG_GDP = 226894 var LUN_MAX_GDP = 3652058 var LUN_ORG_GDP = JAL_ORG_GDP + 119 /*BIAS*/ /*Gregorian Section*/ let Greg = { greg_week_days: ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], greg_week_days_abbr: ["Sat", "Sun", "Mon", "Tue", "Wed", "Thr", "Fri"], greg_months: [ "January", "February", "March", "April", "May", "June", "July", "August", "Septamber", "October", "November", "December", ], greg_months_abbr: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], greg_months_fa: [ "زانويه", "فوريه", "مارچ", "آوريل", "مي", "ژون", "جولاي", "آگوست", "سپتامبر", "اکتبر", "نوامبر", "دسامبر", ], gregToGdp: function (Year, Month, DayOfMonth) { var c = 0 var y = 1 var d = 0 var M = [] while ((c + 1) * 100 < Year) { c++ if (c % 4 == 0) d += 36525 else d += 36524 } while (c * 100 + y < Year) { if (Greg.isGregLeapYear(c * 100 + y)) d += 366 else d += 365 y++ } if (Greg.isGregLeapYear(Year)) M = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] else M = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] for (var m = 1; m < Month; m++) { d += M[m - 1] } d += DayOfMonth return d - 1 }, isValidDate(year, month, day) { if (year < 1) return false if (year > 9999) return false if (month < 1) return false if (month > 12) return false if (day < 1) return false if (day > 31) return false var M if (Greg.isGregLeapYear(year)) M = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] else M = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if (!Greg.isGregLeapYear(year)) { if (month == 2) if (day > 28) return false } else { if (month == 2) if (day > 29) return false } if (month == 4 || month == 6 || month == 9 || month == 11) if (day > 30) return false return true }, daysInYear: function (year) { var y1 = Greg.gregToGdp(year, 1, 1) var y2 = Greg.gregToGdp(year + 1, 1, 1) return y2 - y1 }, daysInMonth: function (year, month) { var g1 = Greg.gregToGdp(year, month, 1) var m = month + 1 var y = year if (m == 13) { m = 1 y++ } var g2 = Greg.gregToGdp(y, m, 1) return g2 - g1 }, isGregLeapYear: function (AYear) { if (AYear <= 0) return false if (AYear % 4 != 0) return false if (AYear % 100 == 0) { if (AYear % 400 == 0) return true else return false } return true }, getGregCentury: function (GregDaysPassed) { var RemainingDays = 0 var d = 0 var c = 0 var c_days = 0 while (true) { c++ if (c % 4 == 0) c_days = 36525 else c_days = 36524 if (d + c_days > GregDaysPassed) break d += c_days } RemainingDays = GregDaysPassed - d return { Century: c, RemainingDays: RemainingDays, } }, getGregYear: function (GregDaysPassed) { var RemainingDays = 0 if (GregDaysPassed < GREG_ORG_GDP) return -1 if (GregDaysPassed > GREG_MAX_GDP) return -1 var res = Greg.getGregCentury(GregDaysPassed) var c = res.Century var rem = res.RemainingDays var d = 0 var y = 0 var y_days = 0 while (true) { y++ if (Greg.isGregLeapYear(y + (c - 1) * 100)) y_days = 366 else y_days = 365 if (d + y_days > rem) break d += y_days } RemainingDays = rem - d var g = y + (c - 1) * 100 return { GregYear: g, RemainingDays: RemainingDays, } }, getGregMonth: function (IsLeapYear, YearDaysPassed) { var RemainingDays = 0 if (YearDaysPassed > 366) return -1 if (YearDaysPassed < 0) return -1 var M = [] if (IsLeapYear) M = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] else M = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] var d = 0 var m = 1 while (d + M[m - 1] <= YearDaysPassed) { d += M[m - 1] m++ } RemainingDays = YearDaysPassed - d return { GregMonth: m, RemainingDays: RemainingDays, } }, } // end of Greg /*Jalali (Persian Solar) Section*/ let Jal = { week_days_abbr: ["ش", "ی", "د", "س", "چ", "پ", "ج"], week_days: ["شنبه", "یکشنبه", "دوشنبه", "سه شنبه", "چهار شنبه", "پنج شنبه", "جمعه"], month_titles: [ "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", ], isJalLeapYear: function (jalYear) { for (var i = 0; i < 7; i++) if ((jalYear - (i * 4 - 7)) % 33 == 0) return true if ((jalYear - (7 * 4 - 6)) % 33 == 0) return true return false }, getJalYear: function (GregDaysPassed) { function GetJalLeapSequence(GregDaysPassed) { var remaining_days = 0 var jal_days_passed = GregDaysPassed - JAL_ORG_GDP var n = Math.floor((jal_days_passed + 2922) / 12053) if (n == 0) { remaining_days = jal_days_passed return { seq: n, rem: remaining_days, } } else if (n == 1) { remaining_days = jal_days_passed - 9131 return { seq: n, rem: remaining_days, } } else { remaining_days = jal_days_passed - (9131 + (n - 1) * 12053) return { seq: n, rem: remaining_days, } } } var RemainingDays = 0 if (GregDaysPassed < JAL_ORG_GDP) return { year: 0, rem: 0, err: "GDP " + GregDaysPassed + " is less than minimum value " + JAL_ORG_GDP, } if (GregDaysPassed > JAL_MAX_GDP) return { year: 0, rem: 0, err: "GDP " + GregDaysPassed + " is more than maximum value " + JAL_MAX_GDP, } var d = 0 var y = 0 var obj = GetJalLeapSequence(GregDaysPassed) var Rem = obj.rem var n = obj.seq if (n == 0) y = 0 else y = n * 33 - 8 var y_days = 0 while (true) { y++ if (Jal.isJalLeapYear(y)) y_days = 366 else y_days = 365 if (d + y_days > Rem) break d += y_days } RemainingDays = Rem - d return { year: y, rem: RemainingDays, err: "", } }, getJalMonth: function (IsLeapYear, YearDaysPassed) { var RemainingDays = 0 if (YearDaysPassed > 366) return -1 if (YearDaysPassed < 0) return -1 var M = [] if (IsLeapYear) M = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30] else M = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29] var d = 0 var m = 1 while (d + M[m - 1] <= YearDaysPassed) { d += M[m - 1] m++ } RemainingDays = YearDaysPassed - d return { month: m, rem: RemainingDays, } }, jalToGdp: function (Year, Month, DayOfMonth) { if (Jal.isValidJalDate(Year, Month, DayOfMonth) == false) return null var n = Math.floor((Year + 7) / 33) var y = 0 var d = 0 var m = 1 var M = [] if (n == 0) { d = 0 y = 1 } else { d = 9131 + (n - 1) * 12053 y = n * 33 - 7 } while (y < Year) { if (Jal.isJalLeapYear(y)) d += 366 else d += 365 y++ } if (Jal.isJalLeapYear(y)) M = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30] else M = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29] while (m < Month) { d += M[m - 1] m++ } d += DayOfMonth d += JAL_ORG_GDP return d - 1 }, isValidJalDate: function (JalYear, JalMonth, JalDayOfMonth) { if (JalYear < 0) return false if (JalYear > 9999) return false if (JalMonth < 0) return false if (JalMonth > 12) return false if (JalDayOfMonth < 0) return false if (JalDayOfMonth > 31) return false if (JalMonth > 6 && JalDayOfMonth > 30) return false var is_leap = Jal.isJalLeapYear(JalYear) if (!is_leap && JalMonth == 12 && JalDayOfMonth > 29) return false if (is_leap && JalMonth == 12 && JalDayOfMonth > 30) return false return true }, } // end of Jal /*Lunar (Arabic) Section*/ let Lun = { lun_week_days: ["السبت", "الاحد", "الاثنین", "الثلاثاء", "الارباء", "الخمیس", "الجمعه"], lun_months: [ "محرم", "صفر", "ربیع الاول", "ربیع الثانی", "جمادی الاول", "جمادی الثانی", "رجب", "شعبان", "رمضان", "شوال", "ذی القعده", "ذی الحجه", ], gdpToLun: function (gdp) { var gdp_lun_org = LUN_ORG_GDP var oly = 354.367 /* One Average Lunar Year measured in days */ var dph = Math.floor(gdp) - gdp_lun_org /* Days Passed after Lunar Gdp upto currend gdp */ var ay = dph / oly /*Arabic Year(float)*/ var arabic_year = Math.ceil(ay) var rem_year = (ay - Math.floor(ay)) * oly /*year remainder measured in days (float)*/ var dpm = 29.530588 /* Days Per Lunar Month */ var am = rem_year / dpm /*arabic month (float)*/ var arabic_month = Math.ceil(am) var rem_month = (am - Math.floor(am)) * dpm var arabic_day_of_month = Math.ceil(rem_month) var rem = gdp - Math.floor(gdp) var date_str = fillz(arabic_year, 4) + "/" + fillz(arabic_month) + "/" + fillz(arabic_day_of_month) return { date_str, arabic_year, arabic_month, arabic_day_of_month, rem, } }, lunToGdp: function (year, month, day) { var target_date_str = fillz(year, 4) + "/" + fillz(month) + "/" + fillz(day) var gs = LUN_ORG_GDP, ge = LUN_MAX_GDP var g var finder_date_str var n = 0 var hit = false while (gs < ge) { g = Math.floor((gs + ge) / 2) let gtl = Lun.gdpToLun(g) finder_date_str = gtl["date_str"] if (finder_date_str == target_date_str) { hit = true break } else if (finder_date_str < target_date_str) { gs = g } else { ge = g } n++ if (n > 100) break } return { gdp: g, success: hit, iterations: n } }, daysInMonth: function (gdp, currentArabicMonth, currentDayOfMonth) { var am, lc var g = gdp var days_in_month = currentDayOfMonth while (true) { var lc = Lun.gdpToLun(g) am = lc["arabic_month"] if (am != currentArabicMonth) break days_in_month++ g++ } return days_in_month }, monthInfo: function (year, month) { var ltg1 = Lun.lunToGdp(year, month, 1) if (ltg1["success"] == 0) return { GdpStart: 0, GdpEnd: 0, DaysInYear: 0, success: 0 } var y = year var m = month m++ if (m == 13) { m = 1 y++ } var ltg2 = Lun.lunToGdp(y, m, 1) if (ltg2["success"] == 0) return { GdpStart: 0, GdpEnd: 0, DaysInYear: 0, success: 0 } return { GdpStart: ltg1["gdp"], GdpEnd: ltg2["gdp"] - 1, DaysInMonth: ltg2["gdp"] - ltg1["gdp"], success: 1, } }, yearInfo: function (year) { var ltg1 = Lun.lunToGdp(year, 1, 1) if (ltg1["success"] == 0) return { GdpStart: 0, GdpEnd: 0, DaysInYear: 0, success: 0 } var ltg2 = Lun.lunToGdp(year + 1, 1, 1) if (ltg2["success"] == 0) return { GdpStart: 0, GdpEnd: 0, DaysInYear: 0, success: 0 } return { GdpStart: ltg1["gdp"], GdpEnd: ltg2["gdp"] - 1, DaysInYear: ltg2["gdp"] - ltg1["gdp"], success: 1, } }, } // end of Lun function fillz(n, m = 2) { var res = "" + n while (res.length < m) res = "0" + res return res } /*Calculate 24hours time from given fraction[0.0 to 1.0]*/ function getTime(frac = 0) { var rem = frac var hour24 = rem * 24 rem = hour24 - Math.floor(hour24) var minutes = rem * 60 rem = minutes - Math.floor(minutes) var seconds = rem * 60 rem = seconds - Math.floor(seconds) hour24 = Math.floor(hour24) minutes = Math.floor(minutes) seconds = Math.floor(seconds) var time_str = fillz(hour24) + ":" + fillz(minutes) + ":" + fillz(seconds) return { time_str, hour24, minutes, seconds, rem } } /*Provides GDP from given date info and calendar type*/ let getGdp = function (year, month, dayOfMonth, calendarType) { var gdp = 0 var success = false var cp = calendarType.toLowerCase() if (cp == "g" || cp == "greg") { gdp = Greg.gregToGdp(year, month, dayOfMonth) success = Greg.isValidDate(year, month, dayOfMonth) } else if (cp == "j" || cp == "jal") { gdp = Jal.jalToGdp(year, month, dayOfMonth) success = Jal.isValidJalDate(year, month, dayOfMonth) } else if (cp == "l" || cp == "lun") { var res = Lun.lunToGdp(year, month, dayOfMonth) gdp = res["gdp"] success = res["success"] gdp = res["gdp"] } return { gdp, success } } /*Gets date Parts comprising year, month and day of month*/ let getDateParts = function (dateStr) { var y = 0 var m = 0 var d = 0 try { // var parts = dateStr.trim().split("/") var parts = dateStr .trim() .split(/-|\//gi) .filter((x) => x.trim() != "") if (parts.length != 3) return null y = parseInt(parts[0]) m = parseInt(parts[1]) || 1 d = parseInt(parts[2]) || 1 return { year: y, month: m, day: d, } } catch (e) { return null } } /*Provides GDP from given date info and calendar type*/ let getGdps = function (dateStr, calendarType) { var year, month, dayOfMonth var res = getDateParts(dateStr) if (res == null) return { gdp: 0, success: 0, err: "bad date string: " + dateStr } year = res["year"] month = res["month"] dayOfMonth = res["day"] return getGdp(year, month, dayOfMonth, calendarType) } /*Checks if the given Date is valid*/ let isValid = function (year, month, dayOfMonth, calendarType = "g") { var res = getGdp(year, month, dayOfMonth, calendarType) return res["success"] } /*Checks if the given Date is valid*/ let isValids = function (dateStr, calendarType = "g") { var res = getDateParts(dateStr) if (res == null) return { gdp: 0, success: 0, err: "bad date string: " + dateStr } var year = res["year"] var month = res["month"] var dayOfMonth = res["day"] return isValid(year, month, dayOfMonth, calendarType) } /*Gets GDP from client date and time*/ let getGdpClientSide = function () { var year, month, dayOfMonth var d = new Date() year = d.getFullYear() month = d.getMonth() + 1 dayOfMonth = d.getDate() return getGdp(year, month, dayOfMonth, "g") } /*Provides Date Info from given GDP and calendar type*/ let getDateInfo = function (gdp, calendarType = "g") { if (calendarType == null) return calendarType = calendarType.toLowerCase() // Jalalian Calendar if (calendarType == "j" || calendarType == "jal") { // --- var err = "" var jal_year = 0 var jal_month = 0 var jal_day_of_month = 0 var jal_year_result = Jal.getJalYear(gdp) jal_year = jal_year_result["year"] var rem = jal_year_result["rem"] if (jal_year_result["err"] != "") err += jal_year_result["err"] + " " var is_leap = Jal.isJalLeapYear(jal_year) var jal_month_result = Jal.getJalMonth(is_leap, rem) jal_month = jal_month_result["month"] jal_day_of_month = Math.floor(jal_month_result["rem"]) + 1 var date_str = "" date_str += fillz(jal_year, 4) + "/" date_str += fillz(jal_month) + "/" date_str += fillz(jal_day_of_month) var day_of_week_number = (Math.floor(gdp) + 2) % 7 var day_title = Jal.week_days[day_of_week_number] var day_title_abbr = Jal.week_days_abbr[day_of_week_number] var month_title = Jal.month_titles[jal_month - 1] var full_date_str = "" full_date_str += day_title + " " full_date_str += jal_day_of_month + " " full_date_str += month_title + " " full_date_str += jal_year var days_in_year = 365 if (is_leap) days_in_year++ var days_in_month = 31 if (7 <= jal_month && jal_month <= 11) days_in_month = 30 if (jal_month == 12) { if (is_leap) days_in_month = 30 else days_in_month = 29 } rem = jal_month_result["rem"] - Math.floor(jal_month_result["rem"]) var tr = getTime(rem) var hour24 = tr["hour24"], minutes = tr["minutes"], seconds = tr["seconds"] rem = tr["rem"] var time_str = tr["time_str"] return { DateString: date_str, Year: jal_year, Month: jal_month, DayOfMonth: jal_day_of_month, DayOfWeek: day_of_week_number, DayTitle: day_title, MonthTitle: month_title, DayTitleAbbr: day_title_abbr, DaysInYear: days_in_year, DaysInMonth: days_in_month, Hours: hour24, Minutes: minutes, Seconds: seconds, Rem: rem, TimeString: time_str, Gdp: gdp, CalendarType: "jal", Err: err, } // --- } // end of jal calendar else if (calendarType == "g" || calendarType == "greg") { var err = "" var res = Greg.getGregYear(Math.floor(gdp)) var Rem = res["RemainingDays"] var Y = res["GregYear"] var ress = Greg.getGregMonth(Greg.isGregLeapYear(Y), Rem) var M = ress["GregMonth"] Rem = ress["RemainingDays"] var D = Rem + 1 var date_str = "" date_str += fillz(Y, 4) + "/" date_str += fillz(M) + "/" date_str += fillz(D) var day_of_week_number = (Math.floor(gdp) + 2) % 7 var day_title = Greg.greg_week_days[day_of_week_number] var day_title_abbr = Greg.greg_week_days_abbr[day_of_week_number] var month_title = Greg.greg_months_abbr[M - 1] var full_date_str = "" full_date_str += day_title + ", " full_date_str += month_title + ", " full_date_str += D + ", " full_date_str += Y var rem = gdp - Math.floor(gdp) var tr = getTime(rem) var hour24 = tr["hour24"], minutes = tr["minutes"], seconds = tr["seconds"] rem = tr["rem"] var time_str = tr["time_str"] var days_in_year = Greg.daysInYear(Y) var days_in_month = Greg.daysInMonth(Y, M) if (gdp < GREG_ORG_GDP) err = "GDP " + gdp + " is less than minimum value " + GREG_ORG_GDP if (gdp > GREG_MAX_GDP) err = "GDP " + gdp + " is more than maximum value " + GREG_MAX_GDP return { DateString: date_str, FullDateString: full_date_str, Year: Y, Month: M, DayOfMonth: D, DayOfWeek: day_of_week_number, DayTitle: day_title, MonthTitle: month_title, DayTitleAbbr: day_title_abbr, DaysInYear: days_in_year, DaysInMonth: days_in_month, Hours: hour24, Minutes: minutes, Seconds: seconds, Rem: rem, TimeString: time_str, Gdp: gdp, CalendarType: "greg", Err: err, } } // end of greg calendar else if (calendarType == "l" || calendarType == "lun") { var err = "" var fr = Lun.gdpToLun(gdp) var arabic_year = fr["arabic_year"] var arabic_month = fr["arabic_month"] var arabic_day_of_month = fr["arabic_day_of_month"] var date_str = fr["date_str"] var day_of_week_number = (Math.floor(gdp) + 2) % 7 var days_in_month = Lun.daysInMonth(gdp, arabic_month, arabic_day_of_month) var rem = fr["rem"] var tr = getTime(rem) var hour24 = tr["hour24"], minutes = tr["minutes"], seconds = tr["seconds"] rem = tr["rem"] var time_str = tr["time_str"] var year_info = Lun.yearInfo(arabic_year) var days_in_year = year_info["DaysInYear"] var month_info = Lun.monthInfo(arabic_year, arabic_month) var day_title = Lun.lun_week_days[day_of_week_number] var month_title = Lun.lun_months[arabic_month - 1] if (gdp < LUN_ORG_GDP) err = "GDP " + gdp + " is less than minimum value " + LUN_ORG_GDP if (gdp > LUN_MAX_GDP) err = "GDP " + gdp + " is more than maximum value " + LUN_MAX_GDP return { DateString: date_str, Year: arabic_year, Month: arabic_month, DayOfMonth: arabic_day_of_month, DayOfWeek: day_of_week_number, DayTitle: day_title, MonthTitle: month_title, DayTitleAbbr: day_title, DaysInYear: days_in_year, DaysInMonth: days_in_month, Hours: hour24, Minutes: minutes, Seconds: seconds, Rem: rem, TimeString: time_str, Gdp: gdp, CalendarType: "lun", Err: err, YearInfo: year_info, MonthInfo: month_info, } } // end of lunar calendar else { return { DateString: "", Year: 0, Month: 0, DayOfMonth: 0, DayOfWeek: 0, DayTitle: "", MonthTitle: "", DayTitleAbbr: "", DaysInYear: 0, DaysInMonth: 0, Hours: 0, Minutes: 0, Seconds: 0, Rem: 0, TimeString: "", Gdp: 0, CalendarType: "", Err: "Unknown calendar type. Use greg, jal, or lun", } } } /*Converts a given date from source calendar type to target*/ let convert = function (year, month, dayOfMonth, sourceCalendarType = "g", targetCalendarType = "j") { var res = getGdp(year, month, dayOfMonth, sourceCalendarType) if (res["success"] == false) return { err: "invalid date" } return getDateInfo(res["gdp"], targetCalendarType) } /*Converts a given date from source calendar type to target*/ let converts = function (dateStr, sourceCalendarType = "g", targetCalendarType = "j") { var res = getDateParts(dateStr) if (res == null) return { err: "bad date string" } var year = res["year"] var month = res["month"] var dayOfMonth = res["day"] return convert(year, month, dayOfMonth, sourceCalendarType, targetCalendarType) } /*Provides Date String from given GDP and calendar type*/ let getDateStr = function (gdp, calendarType = "g") { var di = getDateInfo(gdp, calendarType) return di["DateString"] } /*Calculates days between two dates*/ let getDateDiff = function (dateStrFrom, dateStrTo, calendarType = "g") { if (!isValids(dateStrFrom, calendarType)) return 0 if (!isValids(dateStrTo, calendarType)) return 0 var g_from = getGdps(dateStrFrom, calendarType)["gdp"] var g_to = getGdps(dateStrTo, calendarType)["gdp"] return g_to - g_from } /*Adds given days to supplied date*/ let addDays = function (dateStr, days, calendarType = "g") { if (!isValids(dateStr, calendarType)) return "" var g = getGdps(dateStr, calendarType)["gdp"] return getDateStr(g + days, calendarType) } /*Gets client side date string*/ let getDateStrClientSide = function (calendarType = "g") { var g = getGdpClientSide()["gdp"] return getDateStr(g, calendarType) } return { convert, converts, isValid, isValid, getDateDiff, addDays, getDateStrClientSide, } } export default MultiCalendar