--- Islamic calendar conversions and holidays. -- Ported from "Calendrical Calculations" (4th edition) -- by Nachum Dershowitz and Edward M. Reingold. -- Original Lisp code (CALENDRICA 4.0) is Apache 2.0 licensed. -- -- This module also includes Islamic calendar variants that are **not** from the -- book: the TBLA (astronomical/Thursday epoch), Umm al-Qura, and Turkish (Diyanet) -- calendars. Such additions are marked individually, with their sources, at their -- definitions. -- @module calendrica-islamic -- @release 0.2 2026-10-13 local M = {} local basic = require("calendrica-basic") local julian = require("calendrica-julian") local gregorian = require("calendrica-gregorian") -- === Epochs === -- Friday epoch: CE 622 July 16 (Julian) — used by arithmetic (civil) calendar. local ISLAMIC_EPOCH = julian.fixed_from_julian( julian.julian_date(julian.ce(622), julian.JULY, 16) ) -- Thursday epoch: CE 622 July 15 (Julian) — used by TBLA variant. local ISLAMIC_EPOCH_TBLA = julian.fixed_from_julian( julian.julian_date(julian.ce(622), julian.JULY, 15) ) -- === Date constructor === --- Construct an Islamic date {year, month, day}. -- @tparam number year Islamic year. -- @tparam number month Islamic month. -- @tparam number day Islamic day. -- @treturn table {year, month, day} function M.islamic_date(year, month, day) return {year, month, day} end local islamic_date = M.islamic_date -- === Leap year === -- True if i_year is an Islamic leap year. local function islamic_leap_year(i_year) return (14 + 11 * i_year) % 30 < 11 end -- === Conversion === --- Fixed date equivalent to Islamic date `i_date`. -- @tparam table i_date Islamic date {year, month, day}. -- @treturn number Fixed date. function M.fixed_from_islamic(i_date) local month = basic.standard_month(i_date) local day = basic.standard_day(i_date) local year = basic.standard_year(i_date) return (ISLAMIC_EPOCH - 1) -- Days before start of calendar. + (year - 1) * 354 -- Ordinary days since epoch. + basic.quotient(3 + 11 * year, 30) -- Leap days since epoch. + 29 * (month - 1) -- Days in prior months this year. + basic.quotient(month, 2) + day -- Days so far this month. end local fixed_from_islamic = M.fixed_from_islamic --- Islamic date {year, month, day} corresponding to fixed `date`. -- @tparam number date Fixed date. -- @treturn table {year, month, day} function M.islamic_from_fixed(date) local year = basic.quotient( 30 * (date - ISLAMIC_EPOCH) + 10646, 10631 ) local prior_days = date - fixed_from_islamic(islamic_date(year, 1, 1)) local month = basic.quotient(11 * prior_days + 330, 325) local day = 1 + date - fixed_from_islamic(islamic_date(year, month, 1)) return islamic_date(year, month, day) end local islamic_from_fixed = M.islamic_from_fixed -- === TBLA variant (Thursday epoch) === -- -- Not from the book. The `islamic-tbla` variant of Unicode CLDR/ICU: the tabular -- Islamic calendar with the astronomical epoch (CE 622 July 15, Julian). Verified -- against ICU 77.1. See -- and . --- Fixed date equivalent to Islamic TBLA date `i_date`. -- Identical to the civil calendar but uses the Thursday epoch (one day earlier). -- @tparam table i_date Islamic date {year, month, day}. -- @treturn number Fixed date. function M.fixed_from_islamic_tbla(i_date) local month = basic.standard_month(i_date) local day = basic.standard_day(i_date) local year = basic.standard_year(i_date) return (ISLAMIC_EPOCH_TBLA - 1) + (year - 1) * 354 + basic.quotient(3 + 11 * year, 30) + 29 * (month - 1) + basic.quotient(month, 2) + day end local fixed_from_islamic_tbla = M.fixed_from_islamic_tbla --- Islamic TBLA date {year, month, day} corresponding to fixed `date`. -- @tparam number date Fixed date. -- @treturn table {year, month, day} function M.islamic_tbla_from_fixed(date) local year = basic.quotient( 30 * (date - ISLAMIC_EPOCH_TBLA) + 10646, 10631 ) local prior_days = date - fixed_from_islamic_tbla(islamic_date(year, 1, 1)) local month = basic.quotient(11 * prior_days + 330, 325) local day = 1 + date - fixed_from_islamic_tbla(islamic_date(year, month, 1)) return islamic_date(year, month, day) end -- === Umm al-Qura variant === -- Precomputed month lengths for AH 1300-1600 (bit-packed: 1=30 days, 0=29 days). -- Each entry is a 12-bit value, one bit per month (MSB = month 1). -- Not from the book. Source: ICU UMALQURA_MONTHLENGTH table, encoding the official -- Saudi Umm al-Qura calendar (KACST). Verified against ICU 77.1. Note: KACST -- periodically revises the official tables, so implementations pinned to an earlier -- revision can differ by a day, chiefly for projected future dates. -- See (Umm al-Qura) and -- . local UMALQURA_YEAR_START = 1300 local UMALQURA_YEAR_END = 1600 local UMALQURA_DATA = { 0x0AAA,0x0D54,0x0EC9,0x06D4,0x06EA,0x036C,0x0AAD,0x0555,0x06A9,0x0792, 0x0BA9,0x05D4,0x0ADA,0x055C,0x0D2D,0x0695,0x074A,0x0B54,0x0B6A,0x05AD, 0x04AE,0x0A4F,0x0517,0x068B,0x06A5,0x0AD5,0x02D6,0x095B,0x049D,0x0A4D, 0x0D26,0x0D95,0x05AC,0x09B6,0x02BA,0x0A5B,0x052B,0x0A95,0x06CA,0x0AE9, 0x02F4,0x0976,0x02B6,0x0956,0x0ACA,0x0BA4,0x0BD2,0x05D9,0x02DC,0x096D, 0x054D,0x0AA5,0x0B52,0x0BA5,0x05B4,0x09B6,0x0557,0x0297,0x054B,0x06A3, 0x0752,0x0B65,0x056A,0x0AAB,0x052B,0x0C95,0x0D4A,0x0DA5,0x05CA,0x0AD6, 0x0957,0x04AB,0x094B,0x0AA5,0x0B52,0x0B6A,0x0575,0x0276,0x08B7,0x045B, 0x0555,0x05A9,0x05B4,0x09DA,0x04DD,0x026E,0x0936,0x0AAA,0x0D54,0x0DB2, 0x05D5,0x02DA,0x095B,0x04AB,0x0A55,0x0B49,0x0B64,0x0B71,0x05B4,0x0AB5, 0x0A55,0x0D25,0x0E92,0x0EC9,0x06D4,0x0AE9,0x096B,0x04AB,0x0A93,0x0D49, 0x0DA4,0x0DB2,0x0AB9,0x04BA,0x0A5B,0x052B,0x0A95,0x0B2A,0x0B55,0x055C, 0x04BD,0x023D,0x091D,0x0A95,0x0B4A,0x0B5A,0x056D,0x02B6,0x093B,0x049B, 0x0655,0x06A9,0x0754,0x0B6A,0x056C,0x0AAD,0x0555,0x0B29,0x0B92,0x0BA9, 0x05D4,0x0ADA,0x055A,0x0AAB,0x0595,0x0749,0x0764,0x0BAA,0x05B5,0x02B6, 0x0A56,0x0E4D,0x0B25,0x0B52,0x0B6A,0x05AD,0x02AE,0x092F,0x0497,0x064B, 0x06A5,0x06AC,0x0AD6,0x055D,0x049D,0x0A4D,0x0D16,0x0D95,0x05AA,0x05B5, 0x02DA,0x095B,0x04AD,0x0595,0x06CA,0x06E4,0x0AEA,0x04F5,0x02B6,0x0956, 0x0AAA,0x0B54,0x0BD2,0x05D9,0x02EA,0x096D,0x04AD,0x0A95,0x0B4A,0x0BA5, 0x05B2,0x09B5,0x04D6,0x0A97,0x0547,0x0693,0x0749,0x0B55,0x056A,0x0A6B, 0x052B,0x0A8B,0x0D46,0x0DA3,0x05CA,0x0AD6,0x04DB,0x026B,0x094B,0x0AA5, 0x0B52,0x0B69,0x0575,0x0176,0x08B7,0x025B,0x052B,0x0565,0x05B4,0x09DA, 0x04ED,0x016D,0x08B6,0x0AA6,0x0D52,0x0DA9,0x05D4,0x0ADA,0x095B,0x04AB, 0x0653,0x0729,0x0762,0x0BA9,0x05B2,0x0AB5,0x0555,0x0B25,0x0D92,0x0EC9, 0x06D2,0x0AE9,0x056B,0x04AB,0x0A55,0x0D29,0x0D54,0x0DAA,0x09B5,0x04BA, 0x0A3B,0x049B,0x0A4D,0x0AAA,0x0AD5,0x02DA,0x095D,0x045E,0x0A2E,0x0C9A, 0x0D55,0x06B2,0x06B9,0x04BA,0x0A5D,0x052D,0x0A95,0x0B52,0x0BA8,0x0BB4, 0x05B9,0x02DA,0x095A,0x0B4A,0x0DA4,0x0ED1,0x06E8,0x0B6A,0x056D,0x0535, 0x0695,0x0D4A,0x0DA8,0x0DD4,0x06DA,0x055B,0x029D,0x062B,0x0B15,0x0B4A, 0x0B95,0x05AA,0x0AAE,0x092E,0x0C8F,0x0527,0x0695,0x06AA,0x0AD6,0x055D,0x029D, } -- Length (29 or 30 days) of month `month` in a tabulated Umm al-Qura year. local function umalqura_month_length(year, month) local bits = UMALQURA_DATA[year - UMALQURA_YEAR_START + 1] local mask = 0x800 >> (month - 1) return (bits & mask ~= 0) and 30 or 29 end -- Fixed date of Umm al-Qura AH 1300-01-01 (Gregorian 1882-11-12, per ICU). The -- tabulated year starts are accumulated from this single epoch. local UMALQURA_EPOCH = gregorian.fixed_from_gregorian( gregorian.gregorian_date(1882, 11, 12)) -- Fixed date of the first day of each tabulated year (index 1 = UMALQURA_YEAR_START). -- The final entry is the first day of the year after UMALQURA_YEAR_END. local UMALQURA_YEAR_FIXED = {} do local acc = UMALQURA_EPOCH for i = 1, #UMALQURA_DATA do UMALQURA_YEAR_FIXED[i] = acc local bits = UMALQURA_DATA[i] for m = 1, 12 do acc = acc + (((bits & (0x800 >> (m - 1))) ~= 0) and 30 or 29) end end UMALQURA_YEAR_FIXED[#UMALQURA_DATA + 1] = acc end --- Fixed date equivalent to Umm al-Qura Islamic date `i_date`. -- The Umm al-Qura calendar is only defined over its published table (AH 1300–1600); -- a year outside that range raises an error. For a computed estimate beyond the table, -- use the astronomical Saudi calendar (`saudi_islamic`) in `calendrica-astronomical-lunar`. -- @tparam table i_date Islamic date {year, month, day}. -- @treturn number Fixed date. -- @raise If the year is outside AH 1300–1600. function M.fixed_from_islamic_umalqura(i_date) local month = basic.standard_month(i_date) local day = basic.standard_day(i_date) local year = basic.standard_year(i_date) if year < UMALQURA_YEAR_START or year > UMALQURA_YEAR_END then error(string.format( "Umm al-Qura calendar undefined for AH %d (tabulated range is AH %d-%d)", year, UMALQURA_YEAR_START, UMALQURA_YEAR_END), 2) end local d = UMALQURA_YEAR_FIXED[year - UMALQURA_YEAR_START + 1] for m = 1, month - 1 do d = d + umalqura_month_length(year, m) end return d + day - 1 end --- Umm al-Qura Islamic date {year, month, day} corresponding to fixed `date`. -- The Umm al-Qura calendar is only defined over its published table (AH 1300–1600); -- a date outside that range raises an error. For a computed estimate beyond the table, -- use the astronomical Saudi calendar (`saudi_islamic`) in `calendrica-astronomical-lunar`. -- @tparam number date Fixed date. -- @treturn table {year, month, day} -- @raise If `date` is outside the tabulated range (AH 1300–1600). function M.islamic_umalqura_from_fixed(date) if date < UMALQURA_YEAR_FIXED[1] or date >= UMALQURA_YEAR_FIXED[#UMALQURA_DATA + 1] then error(string.format( "Umm al-Qura calendar undefined for RD %d (tabulated range is AH %d-%d)", date, UMALQURA_YEAR_START, UMALQURA_YEAR_END), 2) end local idx = 1 while UMALQURA_YEAR_FIXED[idx + 1] <= date do idx = idx + 1 end local year = UMALQURA_YEAR_START + idx - 1 local month = 1 local d = UMALQURA_YEAR_FIXED[idx] while month < 12 and d + umalqura_month_length(year, month) <= date do d = d + umalqura_month_length(year, month) month = month + 1 end return islamic_date(year, month, 1 + date - d) end -- === Turkish (Diyanet) calendar (table) === -- -- Not from the book. The published calendar of the Turkish Directorate of Religious -- Affairs (Diyanet İşleri Başkanlığı) -- the Türkiye Takvimi. `diyanet_dat` holds the -- Modified Chronological Julian Day Number (MCJDN = RD - 678575) of the first day of -- each tabulated lunation. This is the authoritative form of the calendar; for a -- computed estimate beyond the table use the astronomical Turkish calendar in -- `calendrica-astronomical-lunar`. -- Source: R. H. van Gent, "The Islamic Calendar of Turkey": -- . -- Diyanet lunation-start table: MCJDN (= RD - 678575) of the first day of each -- tabulated lunation, from R. H. van Gent's diyanet_dat (see section header). local diyanet_dat = { 15141,15171,15200,15230,15259,15289,15318,15348,15377,15407, 15436,15466,15495,15525,15554,15584,15613,15643,15672,15702, 15731,15761,15790,15820,15850,15880,15909,15939,15968,15998, 16027,16057,16086,16116,16145,16175,16204,16234,16263,16293, 16322,16352,16381,16411,16440,16470,16499,16529,16558,16588, 16617,16647,16676,16706,16735,16765,16794,16824,16853,16883, 16913,16943,16972,17002,17031,17061,17090,17120,17149,17179, 17208,17238,17267,17297,17326,17356,17385,17415,17444,17474, 17503,17533,17562,17592,17621,17651,17680,17710,17739,17769, 17798,17828,17857,17887,17916,17946,17976,18006,18035,18065, 18094,18124,18153,18183,18212,18242,18271,18301,18330,18360, 18389,18419,18448,18478,18507,18537,18566,18596,18625,18655, 18685,18715,18744,18774,18803,18833,18862,18892,18921,18951, 18980,19010,19039,19069,19098,19128,19157,19187,19216,19246, 19275,19305,19334,19364,19393,19423,19452,19482,19511,19541, 19570,19600,19629,19659,19688,19718,19748,19778,19807,19837, 19866,19896,19925,19955,19984,20014,20043,20073,20102,20132, 20161,20191,20220,20250,20279,20309,20338,20368,20397,20427, 20456,20486,20515,20545,20574,20604,20633,20663,20692,20722, 20751,20781,20811,20841,20870,20900,20929,20959,20988,21018, 21047,21077,21106,21136,21165,21195,21224,21254,21283,21313, 21342,21372,21401,21431,21460,21490,21519,21549,21578,21608, 21637,21667,21696,21726,21755,21785,21814,21844,21874,21904, 21933,21963,21992,22022,22051,22081,22110,22140,22169,22199, 22228,22258,22287,22317,22346,22376,22405,22435,22464,22494, 22523,22553,22583,22613,22642,22672,22701,22731,22760,22790, 22819,22849,22878,22908,22937,22967,22996,23026,23055,23085, 23114,23144,23173,23203,23232,23262,23291,23321,23350,23380, 23409,23439,23468,23498,23527,23557,23586,23616,23646,23676, 23705,23735,23764,23794,23823,23853,23882,23912,23941,23971, 24000,24030,24059,24089,24118,24148,24177,24207,24236,24266, 24295,24325,24354,24384,24413,24443,24472,24502,24531,24561, 24590,24619,24648,24678,24708,24738,24768,24797,24827,24857, 24886,24916,24945,24974,25004,25033,25063,25092,25122,25151, 25181,25211,25241,25270,25300,25329,25359,25388,25417,25446, 25476,25505,25535,25565,25595,25624,25654,25684,25713,25743, 25772,25801,25830,25860,25889,25919,25949,25978,26008,26038, 26067,26097,26126,26156,26185,26214,26244,26274,26303,26333, 26362,26392,26422,26451,26481,26510,26540,26569,26599,26628, 26658,26687,26716,26746,26776,26805,26835,26865,26895,26924, 26953,26983,27012,27042,27071,27100,27130,27159,27189,27219, 27248,27278,27308,27338,27367,27396,27426,27455,27484,27514, 27543,27573,27602,27632,27662,27692,27722,27751,27780,27809, 27839,27868,27898,27927,27957,27986,28016,28046,28076,28105, 28134,28164,28194,28223,28252,28282,28311,28340,28370,28400, 28430,28460,28489,28518,28548,28578,28607,28636,28666,28695, 28725,28754,28784,28814,28843,28872,28902,28932,28962,28991, 29020,29050,29079,29109,29138,29168,29197,29226,29256,29286, 29316,29345,29375,29404,29434,29463,29492,29522,29551,29581, 29610,29640,29670,29700,29729,29759,29789,29818,29847,29877, 29906,29935,29965,29994,30024,30054,30083,30113,30143,30172, 30202,30231,30261,30290,30319,30349,30378,30408,30438,30467, 30497,30526,30556,30586,30615,30645,30674,30703,30733,30762, 30792,30821,30851,30880,30910,30940,30969,30999,31028,31058, 31087,31117,31146,31176,31205,31235,31264,31294,31323,31353, 31383,31412,31442,31472,31501,31530,31560,31589,31618,31648, 31677,31707,31737,31766,31796,31826,31856,31885,31914,31944, 31973,32002,32032,32062,32091,32120,32150,32180,32210,32239, 32269,32298,32328,32357,32386,32416,32445,32475,32504,32534, 32564,32594,32623,32653,32682,32712,32741,32770,32800,32829, 32859,32888,32918,32948,32977,33007,33037,33066,33096,33125, 33154,33184,33213,33243,33272,33302,33331,33361,33391,33420, 33450,33479,33509,33539,33568,33598,33627,33656,33686,33715, 33745,33774,33804,33834,33863,33893,33923,33952,33982,34011, 34040,34070,34099,34129,34158,34188,34217,34247,34277,34307, 34336,34366,34395,34424,34454,34483,34512,34542,34571,34601, 34631,34661,34691,34720,34749,34779,34808,34838,34867,34896, 34926,34955,34985,35015,35045,35074,35104,35133,35163,35192, 35222,35251,35280,35310,35340,35369,35399,35428,35458,35488, 35517,35547,35576,35606,35635,35665,35694,35724,35753,35782, 35812,35841,35871,35901,35931,35960,35990,36019,36049,36078, 36108,36137,36166,36196,36225,36255,36285,36314,36344,36374, 36403,36433,36462,36491,36521,36550,36579,36609,36639,36668, 36698,36728,36758,36787,36817,36846,36875,36905,36934,36963, 36993,37023,37052,37082,37112,37141,37171,37200,37230,37259, 37289,37318,37348,37377,37406,37436,37466,37495,37525,37554, 37584,37614,37643,37673,37702,37732,37761,37790,37820,37849, 37879,37908,37938,37968,37997,38027,38057,38086,38116,38145, 38174,38204,38233,38263,38292,38322,38352,38381,38411,38441, 38470,38500,38529,38558,38588,38617,38646,38676,38706,38735, 38765,38795,38825,38854,38884,38913,38942,38972,39001,39030, 39060,39090,39119,39149,39179,39208,39238,39268,39297,39326, 39356,39385,39414,39444,39474,39503,39533,39562,39592,39622, 39651,39681,39710,39740,39769,39799,39828,39857,39887,39917, 39946,39976,40005,40035,40065,40094,40124,40153,40183,40212, 40241,40271,40300,40330,40360,40389,40419,40449,40478,40508, 40538,40567,40596,40626,40655,40684,40714,40743,40773,40803, 40833,40863,40892,40922,40951,40980,41010,41039,41068,41098, 41127,41157,41187,41217,41246,41276,41305,41335,41364,41394, 41423,41452,41482,41511,41541,41571,41600,41630,41659,41689, 41719,41748,41778,41807,41836,41866,41895,41925,41954,41984, 42013,42043,42073,42103,42132,42162,42191,42220,42250,42280, 42309,42338,42367,42397,42427,42457,42486,42516,42546,42575, 42604,42634,42663,42692,42722,42751,42781,42811,42840,42870, 42900,42929,42959,42989,43018,43047,43076,43106,43135,43165, 43194,43224,43254,43283,43313,43343,43372,43402,43431,43461, 43490,43519,43549,43578,43608,43638,43667,43697,43727,43756, 43786,43815,43844,43874,43903,43933,43962,43992,44021,44051, 44081,44110,44140,44169,44199,44228,44258,44287,44317,44346, 44375,44405,44434,44464,44494,44523,44553,44583,44612,44642, 44671,44701,44730,44760,44789,44818,44848,44877,44907,44937, 44967,44996,45026,45055,45085,45114,45144,45173,45202,45231, 45261,45291,45321,45350,45380,45410,45439,45469,45498,45528, 45557,45586,45615,45645,45675,45704,45734,45764,45794,45823, 45853,45882,45911,45941,45970,46000,46029,46059,46088,46118, 46148,46177,46207,46237,46266,46295,46325,46354,46384,46413, 46442,46472,46502,46531,46561,46591,46620,46650,46679,46709, 46738,46768,46797,46827,46856,46886,46915,46945,46974,47004, 47034,47063,47093,47122,47152,47181,47211,47240,47270,47299, 47328,47358,47388,47417,47447,47477,47506,47536,47565,47595, 47624,47653,47683,47712,47742,47771,47801,47831,47860,47890, 47920,47949,47979,48008,48037,48067,48096,48126,48155,48185, 48215,48244,48274,48304,48333,48363,48392,48422,48451,48480, 48509,48539,48569,48598,48628,48658,48688,48717,48747,48776, 48806,48835,48864,48893,48923,48953,48982,49012,49042,49071, 49101,49131,49160,49189,49219,49248,49278,49307,49336,49366, 49396,49425,49455,49485,49515,49544,49573,49603,49632,49662, 49691,49720,49750,49780,49809,49839,49869,49898,49928,49957, 49987,50016,50046,50075,50104,50134,50164,50193,50223,50252, 50282,50311,50341,50371,50400,50430,50459,50489,50518,50548, 50578,50607,50636,50666,50695,50725,50755,50784,50814,50843, 50873,50902,50931,50961,50990,51020,51049,51079,51109,51138, 51168,51198,51227,51257,51286,51315,51345,51374,51404,51433, 51463,51492,51522,51552,51582,51611,51641,51670,51700,51729, 51758,51787,51817,51846,51876,51906,51936,51965,51995,52025, 52054,52084,52113,52142,52171,52201,52230,52260,52290,52319, 52349,52379,52409,52438,52468,52497,52526,52555,52585,52614, 52644,52673,52703,52733,52763,52792,52822,52851,52881,52910, 52940,52969,52998,53028,53057,53087,53117,53146,53176,53206, 53235,53265,53294,53324,53353,53382,53412,53441,53471,53500, 53530,53560,53589,53619,53649,53678,53708,53737,53767,53796, 53825,53855,53884,53914,53943,53973,54003,54032,54062,54092, 54121,54151,54180,54209,54239,54268,54298,54327,54357,54386, 54416,54446,54476,54505,54535,54564,54593,54623,54652,54682, 54711,54740,54770,54800,54830,54859,54889,54918,54948,54977, 55007,55036,55065,55095,55124,55154,55183,55213,55243,55273, 55302,55332,55361,55391,55420,55449,55479,55508,55538,55567, 55597,55627,55656,55686,55716,55745,55775,55804,55833,55863, 55892,55922,55951,55981,56010,56040,56070,56100,56129,56159, 56188,56217,56247,56276,56306,56335,56365,56394,56424,56454, 56483,56513,56543,56572,56601,56631,56660,56690,56719,56749, 56778,56808,56837,56867,56897,56926,56956,56986,57015,57045, 57074,57103,57133,57162,57192,57221,57251,57281,57310,57340, 57369,57399,57429,57458,57487,57517,57546,57575,57605,57635, 57664,57694,57724,57753,57783,57813,57842,57871,57901,57930, 57959,57989,58018,58048,58077,58107,58137,58167,58197,58226, 58255,58285,58314,58343,58373,58402,58432,58461,58491,58521, 58551,58580,58610,58639,58669,58698,58727,58757,58786,58816, 58845,58875,58905,58934,58964,58994,59023,59053,59082,59111, 59141,59170,59200,59229,59259,59288,59318,59348,59377,59407, 59436,59466,59495,59525,59554,59584,59613,59643,59672,59702, 59731,59761,59791,59820,59850,59880,59909,59938,59968,59997, 60027,60056,60086,60115,60145,60174,60204,60234,60263,60293, 60322,60352,60381,60411,60440,60469,60499,60528,60558,60588, 60618,60647,60677,60707,60736,60765,60795,60824,60853,60883, 60912,60942,60972,61001,61031,61061,61091,61120,61149,61179, 61208,61237,61267,61296,61326,61355,61385,61415,61445,61474, 61504,61533,61563,61592,61621,61651,61680,61710,61739,61769, } -- MCJDN = RD - DIYANET_RD_TO_MCJDN (2400000 - 1721425). local DIYANET_RD_TO_MCJDN = 678575 -- Lunation number iln = (1-based table index) + DIYANET_LUNATION_OFFSET. local DIYANET_LUNATION_OFFSET = 15803 --- Fixed date equivalent to Turkish (Diyanet) date `i_date`. -- Defined only over the tabulated range; a date outside it raises an error. -- @tparam table i_date Islamic date {year, month, day}. -- @treturn number Fixed date. -- @raise If the date is outside the tabulated range. function M.fixed_from_diyanet(i_date) local year = basic.standard_year(i_date) local month = basic.standard_month(i_date) local day = basic.standard_day(i_date) local k = 12 * (year - 1) + month - DIYANET_LUNATION_OFFSET if k < 2 or k > #diyanet_dat then error(string.format( "Turkish (Diyanet) calendar undefined for AH %d-%d (outside the tabulated range)", year, month), 2) end return diyanet_dat[k - 1] + DIYANET_RD_TO_MCJDN + day - 1 end --- Turkish (Diyanet) date {year, month, day} corresponding to fixed `date`. -- Defined only over the tabulated range; a date outside it raises an error. -- @tparam number date Fixed date. -- @treturn table {year, month, day} -- @raise If `date` is outside the tabulated range. function M.diyanet_from_fixed(date) local mcjdn = date - DIYANET_RD_TO_MCJDN if mcjdn < diyanet_dat[1] or mcjdn >= diyanet_dat[#diyanet_dat] then error(string.format( "Turkish (Diyanet) calendar undefined for RD %d (outside the tabulated range)", date), 2) end local k = 2 while diyanet_dat[k] <= mcjdn do k = k + 1 end local iln = k + DIYANET_LUNATION_OFFSET local ii = basic.quotient(iln - 1, 12) return islamic_date(ii + 1, iln - 12 * ii, mcjdn - diyanet_dat[k - 1] + 1) end -- === Islamic date in Gregorian year === -- Fixed dates of Islamic i_month/i_day that fall in Gregorian year g_year. local function islamic_in_gregorian(i_month, i_day, g_year) local jan1 = gregorian.gregorian_new_year(g_year) local y = basic.standard_year(islamic_from_fixed(jan1)) local date0 = fixed_from_islamic(islamic_date(y, i_month, i_day)) local date1 = fixed_from_islamic(islamic_date(y + 1, i_month, i_day)) local date2 = fixed_from_islamic(islamic_date(y + 2, i_month, i_day)) return basic.list_range( {date0, date1, date2}, gregorian.gregorian_year_range(g_year) ) end -- === Islamic holidays === --- Fixed dates of Ramadan start (month 9, day 1) in Gregorian year `g_year`. -- @tparam number g_year Gregorian year. -- @treturn {number,...} Fixed dates. function M.ramadan(g_year) return islamic_in_gregorian(9, 1, g_year) end --- Fixed dates of Eid al-Fitr (month 10, day 1) in Gregorian year `g_year`. -- @tparam number g_year Gregorian year. -- @treturn {number,...} Fixed dates. function M.eid_al_fitr(g_year) return islamic_in_gregorian(10, 1, g_year) end --- Fixed dates of Eid al-Adha (month 12, day 10) in Gregorian year `g_year`. -- @tparam number g_year Gregorian year. -- @treturn {number,...} Fixed dates. function M.eid_al_adha(g_year) return islamic_in_gregorian(12, 10, g_year) end --- Fixed dates of Islamic New Year (Muharram 1) occurring in Gregorian year `g_year`. -- @tparam number g_year Gregorian year. -- @treturn {number,...} Fixed dates. function M.islamic_new_year(g_year) return islamic_in_gregorian(1, 1, g_year) end --- Fixed dates of Mawlid an-Nabi occurring in Gregorian year `g_year`. -- @tparam number g_year Gregorian year. -- @treturn table List of fixed dates. function M.mawlid(g_year) return islamic_in_gregorian(3, 12, g_year) end -- === Exports === --- Fixed dates of Islamic month/day `i_month`/`i_day` falling in Gregorian year `g_year`. -- @function islamic_in_gregorian -- @tparam number i_month Islamic month. -- @tparam number i_day Islamic day. -- @tparam number g_year Gregorian year. -- @treturn {number,...} Fixed dates. M.islamic_in_gregorian = islamic_in_gregorian --- True if Islamic year `i_year` is a leap year (355 days). -- @function islamic_leap_year -- @tparam number i_year Islamic year. -- @treturn boolean M.islamic_leap_year = islamic_leap_year --- Fixed date of start of the Islamic calendar (July 16, 622 CE Julian). M.ISLAMIC_EPOCH = ISLAMIC_EPOCH --- Fixed date of start of the Islamic TBLA calendar (July 15, 622 CE Julian). M.ISLAMIC_EPOCH_TBLA = ISLAMIC_EPOCH_TBLA return M