1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 7 namespace System.Globalization 8 { 9 /* 10 ** Calendar support range: 11 ** Calendar Minimum Maximum 12 ** ========== ========== ========== 13 ** Gregorian 1900/04/30 2077/05/13 14 ** UmAlQura 1318/01/01 1500/12/30 15 */ 16 17 public partial class UmAlQuraCalendar : Calendar 18 { 19 internal const int MinCalendarYear = 1318; 20 internal const int MaxCalendarYear = 1500; 21 22 internal struct DateMapping 23 { DateMappingSystem.Globalization.UmAlQuraCalendar.DateMapping24 internal DateMapping(int MonthsLengthFlags, int GYear, int GMonth, int GDay) 25 { 26 HijriMonthsLengthFlags = MonthsLengthFlags; 27 GregorianDate = new DateTime(GYear, GMonth, GDay); 28 } 29 internal int HijriMonthsLengthFlags; 30 internal DateTime GregorianDate; 31 } 32 33 private static readonly DateMapping[] s_hijriYearInfo = InitDateMapping(); 34 InitDateMapping()35 private static DateMapping[] InitDateMapping() 36 { 37 short[] rawData = new short[] 38 { 39 //These data is taken from Tables/Excel/UmAlQura.xls please make sure that the two places are in sync 40 /* DaysPerM GY GM GD D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 41 1318*/0x02EA, 1900, 4, 30,/* 0 1 0 1 0 1 1 1 0 1 0 0 4/30/1900 42 1319*/0x06E9, 1901, 4, 19,/* 1 0 0 1 0 1 1 1 0 1 1 0 4/19/1901 43 1320*/0x0ED2, 1902, 4, 9,/* 0 1 0 0 1 0 1 1 0 1 1 1 4/9/1902 44 1321*/0x0EA4, 1903, 3, 30,/* 0 0 1 0 0 1 0 1 0 1 1 1 3/30/1903 45 1322*/0x0D4A, 1904, 3, 18,/* 0 1 0 1 0 0 1 0 1 0 1 1 3/18/1904 46 1323*/0x0A96, 1905, 3, 7,/* 0 1 1 0 1 0 0 1 0 1 0 1 3/7/1905 47 1324*/0x0536, 1906, 2, 24,/* 0 1 1 0 1 1 0 0 1 0 1 0 2/24/1906 48 1325*/0x0AB5, 1907, 2, 13,/* 1 0 1 0 1 1 0 1 0 1 0 1 2/13/1907 49 1326*/0x0DAA, 1908, 2, 3,/* 0 1 0 1 0 1 0 1 1 0 1 1 2/3/1908 50 1327*/0x0BA4, 1909, 1, 23,/* 0 0 1 0 0 1 0 1 1 1 0 1 1/23/1909 51 1328*/0x0B49, 1910, 1, 12,/* 1 0 0 1 0 0 1 0 1 1 0 1 1/12/1910 52 1329*/0x0A93, 1911, 1, 1,/* 1 1 0 0 1 0 0 1 0 1 0 1 1/1/1911 53 1330*/0x052B, 1911, 12, 21,/* 1 1 0 1 0 1 0 0 1 0 1 0 12/21/1911 54 1331*/0x0A57, 1912, 12, 9,/* 1 1 1 0 1 0 1 0 0 1 0 1 12/9/1912 55 1332*/0x04B6, 1913, 11, 29,/* 0 1 1 0 1 1 0 1 0 0 1 0 11/29/1913 56 1333*/0x0AB5, 1914, 11, 18,/* 1 0 1 0 1 1 0 1 0 1 0 1 11/18/1914 57 1334*/0x05AA, 1915, 11, 8,/* 0 1 0 1 0 1 0 1 1 0 1 0 11/8/1915 58 1335*/0x0D55, 1916, 10, 27,/* 1 0 1 0 1 0 1 0 1 0 1 1 10/27/1916 59 1336*/0x0D2A, 1917, 10, 17,/* 0 1 0 1 0 1 0 0 1 0 1 1 10/17/1917 60 1337*/0x0A56, 1918, 10, 6,/* 0 1 1 0 1 0 1 0 0 1 0 1 10/6/1918 61 1338*/0x04AE, 1919, 9, 25,/* 0 1 1 1 0 1 0 1 0 0 1 0 9/25/1919 62 1339*/0x095D, 1920, 9, 13,/* 1 0 1 1 1 0 1 0 1 0 0 1 9/13/1920 63 1340*/0x02EC, 1921, 9, 3,/* 0 0 1 1 0 1 1 1 0 1 0 0 9/3/1921 64 1341*/0x06D5, 1922, 8, 23,/* 1 0 1 0 1 0 1 1 0 1 1 0 8/23/1922 65 1342*/0x06AA, 1923, 8, 13,/* 0 1 0 1 0 1 0 1 0 1 1 0 8/13/1923 66 1343*/0x0555, 1924, 8, 1,/* 1 0 1 0 1 0 1 0 1 0 1 0 8/1/1924 67 1344*/0x04AB, 1925, 7, 21,/* 1 1 0 1 0 1 0 1 0 0 1 0 7/21/1925 68 1345*/0x095B, 1926, 7, 10,/* 1 1 0 1 1 0 1 0 1 0 0 1 7/10/1926 69 1346*/0x02BA, 1927, 6, 30,/* 0 1 0 1 1 1 0 1 0 1 0 0 6/30/1927 70 1347*/0x0575, 1928, 6, 18,/* 1 0 1 0 1 1 1 0 1 0 1 0 6/18/1928 71 1348*/0x0BB2, 1929, 6, 8,/* 0 1 0 0 1 1 0 1 1 1 0 1 6/8/1929 72 1349*/0x0764, 1930, 5, 29,/* 0 0 1 0 0 1 1 0 1 1 1 0 5/29/1930 73 1350*/0x0749, 1931, 5, 18,/* 1 0 0 1 0 0 1 0 1 1 1 0 5/18/1931 74 1351*/0x0655, 1932, 5, 6,/* 1 0 1 0 1 0 1 0 0 1 1 0 5/6/1932 75 1352*/0x02AB, 1933, 4, 25,/* 1 1 0 1 0 1 0 1 0 1 0 0 4/25/1933 76 1353*/0x055B, 1934, 4, 14,/* 1 1 0 1 1 0 1 0 1 0 1 0 4/14/1934 77 1354*/0x0ADA, 1935, 4, 4,/* 0 1 0 1 1 0 1 1 0 1 0 1 4/4/1935 78 1355*/0x06D4, 1936, 3, 24,/* 0 0 1 0 1 0 1 1 0 1 1 0 3/24/1936 79 1356*/0x0EC9, 1937, 3, 13,/* 1 0 0 1 0 0 1 1 0 1 1 1 3/13/1937 80 1357*/0x0D92, 1938, 3, 3,/* 0 1 0 0 1 0 0 1 1 0 1 1 3/3/1938 81 1358*/0x0D25, 1939, 2, 20,/* 1 0 1 0 0 1 0 0 1 0 1 1 2/20/1939 82 1359*/0x0A4D, 1940, 2, 9,/* 1 0 1 1 0 0 1 0 0 1 0 1 2/9/1940 83 1360*/0x02AD, 1941, 1, 28,/* 1 0 1 1 0 1 0 1 0 1 0 0 1/28/1941 84 1361*/0x056D, 1942, 1, 17,/* 1 0 1 1 0 1 1 0 1 0 1 0 1/17/1942 85 1362*/0x0B6A, 1943, 1, 7,/* 0 1 0 1 0 1 1 0 1 1 0 1 1/7/1943 86 1363*/0x0B52, 1943, 12, 28,/* 0 1 0 0 1 0 1 0 1 1 0 1 12/28/1943 87 1364*/0x0AA5, 1944, 12, 16,/* 1 0 1 0 0 1 0 1 0 1 0 1 12/16/1944 88 1365*/0x0A4B, 1945, 12, 5,/* 1 1 0 1 0 0 1 0 0 1 0 1 12/5/1945 89 1366*/0x0497, 1946, 11, 24,/* 1 1 1 0 1 0 0 1 0 0 1 0 11/24/1946 90 1367*/0x0937, 1947, 11, 13,/* 1 1 1 0 1 1 0 0 1 0 0 1 11/13/1947 91 1368*/0x02B6, 1948, 11, 2,/* 0 1 1 0 1 1 0 1 0 1 0 0 11/2/1948 92 1369*/0x0575, 1949, 10, 22,/* 1 0 1 0 1 1 1 0 1 0 1 0 10/22/1949 93 1370*/0x0D6A, 1950, 10, 12,/* 0 1 0 1 0 1 1 0 1 0 1 1 10/12/1950 94 1371*/0x0D52, 1951, 10, 2,/* 0 1 0 0 1 0 1 0 1 0 1 1 10/2/1951 95 1372*/0x0A96, 1952, 9, 20,/* 0 1 1 0 1 0 0 1 0 1 0 1 9/20/1952 96 1373*/0x092D, 1953, 9, 9,/* 1 0 1 1 0 1 0 0 1 0 0 1 9/9/1953 97 1374*/0x025D, 1954, 8, 29,/* 1 0 1 1 1 0 1 0 0 1 0 0 8/29/1954 98 1375*/0x04DD, 1955, 8, 18,/* 1 0 1 1 1 0 1 1 0 0 1 0 8/18/1955 99 1376*/0x0ADA, 1956, 8, 7,/* 0 1 0 1 1 0 1 1 0 1 0 1 8/7/1956 100 1377*/0x05D4, 1957, 7, 28,/* 0 0 1 0 1 0 1 1 1 0 1 0 7/28/1957 101 1378*/0x0DA9, 1958, 7, 17,/* 1 0 0 1 0 1 0 1 1 0 1 1 7/17/1958 102 1379*/0x0D52, 1959, 7, 7,/* 0 1 0 0 1 0 1 0 1 0 1 1 7/7/1959 103 1380*/0x0AAA, 1960, 6, 25,/* 0 1 0 1 0 1 0 1 0 1 0 1 6/25/1960 104 1381*/0x04D6, 1961, 6, 14,/* 0 1 1 0 1 0 1 1 0 0 1 0 6/14/1961 105 1382*/0x09B6, 1962, 6, 3,/* 0 1 1 0 1 1 0 1 1 0 0 1 6/3/1962 106 1383*/0x0374, 1963, 5, 24,/* 0 0 1 0 1 1 1 0 1 1 0 0 5/24/1963 107 1384*/0x0769, 1964, 5, 12,/* 1 0 0 1 0 1 1 0 1 1 1 0 5/12/1964 108 1385*/0x0752, 1965, 5, 2,/* 0 1 0 0 1 0 1 0 1 1 1 0 5/2/1965 109 1386*/0x06A5, 1966, 4, 21,/* 1 0 1 0 0 1 0 1 0 1 1 0 4/21/1966 110 1387*/0x054B, 1967, 4, 10,/* 1 1 0 1 0 0 1 0 1 0 1 0 4/10/1967 111 1388*/0x0AAB, 1968, 3, 29,/* 1 1 0 1 0 1 0 1 0 1 0 1 3/29/1968 112 1389*/0x055A, 1969, 3, 19,/* 0 1 0 1 1 0 1 0 1 0 1 0 3/19/1969 113 1390*/0x0AD5, 1970, 3, 8,/* 1 0 1 0 1 0 1 1 0 1 0 1 3/8/1970 114 1391*/0x0DD2, 1971, 2, 26,/* 0 1 0 0 1 0 1 1 1 0 1 1 2/26/1971 115 1392*/0x0DA4, 1972, 2, 16,/* 0 0 1 0 0 1 0 1 1 0 1 1 2/16/1972 116 1393*/0x0D49, 1973, 2, 4,/* 1 0 0 1 0 0 1 0 1 0 1 1 2/4/1973 117 1394*/0x0A95, 1974, 1, 24,/* 1 0 1 0 1 0 0 1 0 1 0 1 1/24/1974 118 1395*/0x052D, 1975, 1, 13,/* 1 0 1 1 0 1 0 0 1 0 1 0 1/13/1975 119 1396*/0x0A5D, 1976, 1, 2,/* 1 0 1 1 1 0 1 0 0 1 0 1 1/2/1976 120 1397*/0x055A, 1976, 12, 22,/* 0 1 0 1 1 0 1 0 1 0 1 0 12/22/1976 121 1398*/0x0AD5, 1977, 12, 11,/* 1 0 1 0 1 0 1 1 0 1 0 1 12/11/1977 122 1399*/0x06AA, 1978, 12, 1,/* 0 1 0 1 0 1 0 1 0 1 1 0 12/1/1978 123 1400*/0x0695, 1979, 11, 20,/* 1 0 1 0 1 0 0 1 0 1 1 0 11/20/1979 124 1401*/0x052B, 1980, 11, 8,/* 1 1 0 1 0 1 0 0 1 0 1 0 11/8/1980 125 1402*/0x0A57, 1981, 10, 28,/* 1 1 1 0 1 0 1 0 0 1 0 1 10/28/1981 126 1403*/0x04AE, 1982, 10, 18,/* 0 1 1 1 0 1 0 1 0 0 1 0 10/18/1982 127 1404*/0x0976, 1983, 10, 7,/* 0 1 1 0 1 1 1 0 1 0 0 1 10/7/1983 128 1405*/0x056C, 1984, 9, 26,/* 0 0 1 1 0 1 1 0 1 0 1 0 9/26/1984 129 1406*/0x0B55, 1985, 9, 15,/* 1 0 1 0 1 0 1 0 1 1 0 1 9/15/1985 130 1407*/0x0AAA, 1986, 9, 5,/* 0 1 0 1 0 1 0 1 0 1 0 1 9/5/1986 131 1408*/0x0A55, 1987, 8, 25,/* 1 0 1 0 1 0 1 0 0 1 0 1 8/25/1987 132 1409*/0x04AD, 1988, 8, 13,/* 1 0 1 1 0 1 0 1 0 0 1 0 8/13/1988 133 1410*/0x095D, 1989, 8, 2,/* 1 0 1 1 1 0 1 0 1 0 0 1 8/2/1989 134 1411*/0x02DA, 1990, 7, 23,/* 0 1 0 1 1 0 1 1 0 1 0 0 7/23/1990 135 1412*/0x05D9, 1991, 7, 12,/* 1 0 0 1 1 0 1 1 1 0 1 0 7/12/1991 136 1413*/0x0DB2, 1992, 7, 1,/* 0 1 0 0 1 1 0 1 1 0 1 1 7/1/1992 137 1414*/0x0BA4, 1993, 6, 21,/* 0 0 1 0 0 1 0 1 1 1 0 1 6/21/1993 138 1415*/0x0B4A, 1994, 6, 10,/* 0 1 0 1 0 0 1 0 1 1 0 1 6/10/1994 139 1416*/0x0A55, 1995, 5, 30,/* 1 0 1 0 1 0 1 0 0 1 0 1 5/30/1995 140 1417*/0x02B5, 1996, 5, 18,/* 1 0 1 0 1 1 0 1 0 1 0 0 5/18/1996 141 1418*/0x0575, 1997, 5, 7,/* 1 0 1 0 1 1 1 0 1 0 1 0 5/7/1997 142 1419*/0x0B6A, 1998, 4, 27,/* 0 1 0 1 0 1 1 0 1 1 0 1 4/27/1998 143 1420*/0x0BD2, 1999, 4, 17,/* 0 1 0 0 1 0 1 1 1 1 0 1 4/17/1999 144 1421*/0x0BC4, 2000, 4, 6,/* 0 0 1 0 0 0 1 1 1 1 0 1 4/6/2000 145 1422*/0x0B89, 2001, 3, 26,/* 1 0 0 1 0 0 0 1 1 1 0 1 3/26/2001 146 1423*/0x0A95, 2002, 3, 15,/* 1 0 1 0 1 0 0 1 0 1 0 1 3/15/2002 147 1424*/0x052D, 2003, 3, 4,/* 1 0 1 1 0 1 0 0 1 0 1 0 3/4/2003 148 1425*/0x05AD, 2004, 2, 21,/* 1 0 1 1 0 1 0 1 1 0 1 0 2/21/2004 149 1426*/0x0B6A, 2005, 2, 10,/* 0 1 0 1 0 1 1 0 1 1 0 1 2/10/2005 150 1427*/0x06D4, 2006, 1, 31,/* 0 0 1 0 1 0 1 1 0 1 1 0 1/31/2006 151 1428*/0x0DC9, 2007, 1, 20,/* 1 0 0 1 0 0 1 1 1 0 1 1 1/20/2007 152 1429*/0x0D92, 2008, 1, 10,/* 0 1 0 0 1 0 0 1 1 0 1 1 1/10/2008 153 1430*/0x0AA6, 2008, 12, 29,/* 0 1 1 0 0 1 0 1 0 1 0 1 12/29/2008 154 1431*/0x0956, 2009, 12, 18,/* 0 1 1 0 1 0 1 0 1 0 0 1 12/18/2009 155 1432*/0x02AE, 2010, 12, 7,/* 0 1 1 1 0 1 0 1 0 1 0 0 12/7/2010 156 1433*/0x056D, 2011, 11, 26,/* 1 0 1 1 0 1 1 0 1 0 1 0 11/26/2011 157 1434*/0x036A, 2012, 11, 15,/* 0 1 0 1 0 1 1 0 1 1 0 0 11/15/2012 158 1435*/0x0B55, 2013, 11, 4,/* 1 0 1 0 1 0 1 0 1 1 0 1 11/4/2013 159 1436*/0x0AAA, 2014, 10, 25,/* 0 1 0 1 0 1 0 1 0 1 0 1 10/25/2014 160 1437*/0x094D, 2015, 10, 14,/* 1 0 1 1 0 0 1 0 1 0 0 1 10/14/2015 161 1438*/0x049D, 2016, 10, 2,/* 1 0 1 1 1 0 0 1 0 0 1 0 10/2/2016 162 1439*/0x095D, 2017, 9, 21,/* 1 0 1 1 1 0 1 0 1 0 0 1 9/21/2017 163 1440*/0x02BA, 2018, 9, 11,/* 0 1 0 1 1 1 0 1 0 1 0 0 9/11/2018 164 1441*/0x05B5, 2019, 8, 31,/* 1 0 1 0 1 1 0 1 1 0 1 0 8/31/2019 165 1442*/0x05AA, 2020, 8, 20,/* 0 1 0 1 0 1 0 1 1 0 1 0 8/20/2020 166 1443*/0x0D55, 2021, 8, 9,/* 1 0 1 0 1 0 1 0 1 0 1 1 8/9/2021 167 1444*/0x0A9A, 2022, 7, 30,/* 0 1 0 1 1 0 0 1 0 1 0 1 7/30/2022 168 1445*/0x092E, 2023, 7, 19,/* 0 1 1 1 0 1 0 0 1 0 0 1 7/19/2023 169 1446*/0x026E, 2024, 7, 7,/* 0 1 1 1 0 1 1 0 0 1 0 0 7/7/2024 170 1447*/0x055D, 2025, 6, 26,/* 1 0 1 1 1 0 1 0 1 0 1 0 6/26/2025 171 1448*/0x0ADA, 2026, 6, 16,/* 0 1 0 1 1 0 1 1 0 1 0 1 6/16/2026 172 1449*/0x06D4, 2027, 6, 6,/* 0 0 1 0 1 0 1 1 0 1 1 0 6/6/2027 173 1450*/0x06A5, 2028, 5, 25,/* 1 0 1 0 0 1 0 1 0 1 1 0 5/25/2028 174 1451*/0x054B, 2029, 5, 14,/* 1 1 0 1 0 0 1 0 1 0 1 0 5/14/2029 175 1452*/0x0A97, 2030, 5, 3,/* 1 1 1 0 1 0 0 1 0 1 0 1 5/3/2030 176 1453*/0x054E, 2031, 4, 23,/* 0 1 1 1 0 0 1 0 1 0 1 0 4/23/2031 177 1454*/0x0AAE, 2032, 4, 11,/* 0 1 1 1 0 1 0 1 0 1 0 1 4/11/2032 178 1455*/0x05AC, 2033, 4, 1,/* 0 0 1 1 0 1 0 1 1 0 1 0 4/1/2033 179 1456*/0x0BA9, 2034, 3, 21,/* 1 0 0 1 0 1 0 1 1 1 0 1 3/21/2034 180 1457*/0x0D92, 2035, 3, 11,/* 0 1 0 0 1 0 0 1 1 0 1 1 3/11/2035 181 1458*/0x0B25, 2036, 2, 28,/* 1 0 1 0 0 1 0 0 1 1 0 1 2/28/2036 182 1459*/0x064B, 2037, 2, 16,/* 1 1 0 1 0 0 1 0 0 1 1 0 2/16/2037 183 1460*/0x0CAB, 2038, 2, 5,/* 1 1 0 1 0 1 0 1 0 0 1 1 2/5/2038 184 1461*/0x055A, 2039, 1, 26,/* 0 1 0 1 1 0 1 0 1 0 1 0 1/26/2039 185 1462*/0x0B55, 2040, 1, 15,/* 1 0 1 0 1 0 1 0 1 1 0 1 1/15/2040 186 1463*/0x06D2, 2041, 1, 4,/* 0 1 0 0 1 0 1 1 0 1 1 0 1/4/2041 187 1464*/0x0EA5, 2041, 12, 24,/* 1 0 1 0 0 1 0 1 0 1 1 1 12/24/2041 188 1465*/0x0E4A, 2042, 12, 14,/* 0 1 0 1 0 0 1 0 0 1 1 1 12/14/2042 189 1466*/0x0A95, 2043, 12, 3,/* 1 0 1 0 1 0 0 1 0 1 0 1 12/3/2043 190 1467*/0x052D, 2044, 11, 21,/* 1 0 1 1 0 1 0 0 1 0 1 0 11/21/2044 191 1468*/0x0AAD, 2045, 11, 10,/* 1 0 1 1 0 1 0 1 0 1 0 1 11/10/2045 192 1469*/0x036C, 2046, 10, 31,/* 0 0 1 1 0 1 1 0 1 1 0 0 10/31/2046 193 1470*/0x0759, 2047, 10, 20,/* 1 0 0 1 1 0 1 0 1 1 1 0 10/20/2047 194 1471*/0x06D2, 2048, 10, 9,/* 0 1 0 0 1 0 1 1 0 1 1 0 10/9/2048 195 1472*/0x0695, 2049, 9, 28,/* 1 0 1 0 1 0 0 1 0 1 1 0 9/28/2049 196 1473*/0x052D, 2050, 9, 17,/* 1 0 1 1 0 1 0 0 1 0 1 0 9/17/2050 197 1474*/0x0A5B, 2051, 9, 6,/* 1 1 0 1 1 0 1 0 0 1 0 1 9/6/2051 198 1475*/0x04BA, 2052, 8, 26,/* 0 1 0 1 1 1 0 1 0 0 1 0 8/26/2052 199 1476*/0x09BA, 2053, 8, 15,/* 0 1 0 1 1 1 0 1 1 0 0 1 8/15/2053 200 1477*/0x03B4, 2054, 8, 5,/* 0 0 1 0 1 1 0 1 1 1 0 0 8/5/2054 201 1478*/0x0B69, 2055, 7, 25,/* 1 0 0 1 0 1 1 0 1 1 0 1 7/25/2055 202 1479*/0x0B52, 2056, 7, 14,/* 0 1 0 0 1 0 1 0 1 1 0 1 7/14/2056 203 1480*/0x0AA6, 2057, 7, 3,/* 0 1 1 0 0 1 0 1 0 1 0 1 7/3/2057 204 1481*/0x04B6, 2058, 6, 22,/* 0 1 1 0 1 1 0 1 0 0 1 0 6/22/2058 205 1482*/0x096D, 2059, 6, 11,/* 1 0 1 1 0 1 1 0 1 0 0 1 6/11/2059 206 1483*/0x02EC, 2060, 5, 31,/* 0 0 1 1 0 1 1 1 0 1 0 0 5/31/2060 207 1484*/0x06D9, 2061, 5, 20,/* 1 0 0 1 1 0 1 1 0 1 1 0 5/20/2061 208 1485*/0x0EB2, 2062, 5, 10,/* 0 1 0 0 1 1 0 1 0 1 1 1 5/10/2062 209 1486*/0x0D54, 2063, 4, 30,/* 0 0 1 0 1 0 1 0 1 0 1 1 4/30/2063 210 1487*/0x0D2A, 2064, 4, 18,/* 0 1 0 1 0 1 0 0 1 0 1 1 4/18/2064 211 1488*/0x0A56, 2065, 4, 7,/* 0 1 1 0 1 0 1 0 0 1 0 1 4/7/2065 212 1489*/0x04AE, 2066, 3, 27,/* 0 1 1 1 0 1 0 1 0 0 1 0 3/27/2066 213 1490*/0x096D, 2067, 3, 16,/* 1 0 1 1 0 1 1 0 1 0 0 1 3/16/2067 214 1491*/0x0D6A, 2068, 3, 5,/* 0 1 0 1 0 1 1 0 1 0 1 1 3/5/2068 215 1492*/0x0B54, 2069, 2, 23,/* 0 0 1 0 1 0 1 0 1 1 0 1 2/23/2069 216 1493*/0x0B29, 2070, 2, 12,/* 1 0 0 1 0 1 0 0 1 1 0 1 2/12/2070 217 1494*/0x0A93, 2071, 2, 1,/* 1 1 0 0 1 0 0 1 0 1 0 1 2/1/2071 218 1495*/0x052B, 2072, 1, 21,/* 1 1 0 1 0 1 0 0 1 0 1 0 1/21/2072 219 1496*/0x0A57, 2073, 1, 9,/* 1 1 1 0 1 0 1 0 0 1 0 1 1/9/2073 220 1497*/0x0536, 2073, 12, 30,/* 0 1 1 0 1 1 0 0 1 0 1 0 12/30/2073 221 1498*/0x0AB5, 2074, 12, 19,/* 1 0 1 0 1 1 0 1 0 1 0 1 12/19/2074 222 1499*/0x06AA, 2075, 12, 9,/* 0 1 0 1 0 1 0 1 0 1 1 0 12/9/2075 223 1500*/0x0E93, 2076, 11, 27,/* 1 1 0 0 1 0 0 1 0 1 1 1 11/27/2076 224 1501*/ 0, 2077, 11, 17,/* 0 0 0 0 0 0 0 0 0 0 0 0 11/17/2077 225 */ }; 226 // Direct inline initialization of DateMapping array would produce a lot of code bloat. 227 228 // We take advantage of C# compiler compiles inline initialization of primitive type array into very compact code. 229 // So we start with raw data stored in primitive type array, and initialize the DateMapping out of it 230 231 DateMapping[] mapping = new DateMapping[rawData.Length / 4]; 232 for (int i = 0; i < mapping.Length; i++) 233 mapping[i] = new DateMapping(rawData[i * 4], rawData[i * 4 + 1], rawData[i * 4 + 2], rawData[i * 4 + 3]); 234 return mapping; 235 } 236 237 public const int UmAlQuraEra = 1; 238 239 internal const int DateCycle = 30; 240 internal const int DatePartYear = 0; 241 internal const int DatePartDayOfYear = 1; 242 internal const int DatePartMonth = 2; 243 internal const int DatePartDay = 3; 244 245 246 // This is the minimal Gregorian date that we support in the UmAlQuraCalendar. 247 internal static DateTime minDate = new DateTime(1900, 4, 30); 248 internal static DateTime maxDate = new DateTime((new DateTime(2077, 11, 16, 23, 59, 59, 999)).Ticks + 9999); 249 250 public override DateTime MinSupportedDateTime 251 { 252 get 253 { 254 return (minDate); 255 } 256 } 257 258 public override DateTime MaxSupportedDateTime 259 { 260 get 261 { 262 return (maxDate); 263 } 264 } 265 266 public override CalendarAlgorithmType AlgorithmType 267 { 268 get 269 { 270 return CalendarAlgorithmType.LunarCalendar; 271 } 272 } 273 UmAlQuraCalendar()274 public UmAlQuraCalendar() 275 { 276 } 277 278 internal override CalendarId BaseCalendarID 279 { 280 get 281 { 282 return (CalendarId.HIJRI); 283 } 284 } 285 286 internal override CalendarId ID 287 { 288 get 289 { 290 return (CalendarId.UMALQURA); 291 } 292 } 293 294 protected override int DaysInYearBeforeMinSupportedYear 295 { 296 get 297 { 298 // HijriCalendar has same number of days as UmAlQuraCalendar for any given year 299 // HijriCalendar says year 1317 has 355 days. 300 return 355; 301 } 302 } 303 304 /*==========================ConvertHijriToGregorian========================== 305 ** Purpose: convert Hdate(year,month,day) to Gdate(year,month,day) 306 ** Arguments: 307 ** Input/Ouput: Hijrah date: year:yh, month:mh, day:dh 308 ** Output: Gregorian date: year:yg, month:mg, day:dg , day of week:dayweek 309 ** and returns flag found:1 not found:0 310 =========================ConvertHijriToGregorian============================*/ ConvertHijriToGregorian(int HijriYear, int HijriMonth, int HijriDay, ref int yg, ref int mg, ref int dg)311 private static void ConvertHijriToGregorian(int HijriYear, int HijriMonth, int HijriDay, ref int yg, ref int mg, ref int dg) 312 { 313 Debug.Assert((HijriYear >= MinCalendarYear) && (HijriYear <= MaxCalendarYear), "Hijri year is out of range."); 314 Debug.Assert(HijriMonth >= 1, "Hijri month is out of range."); 315 Debug.Assert(HijriDay >= 1, "Hijri day is out of range."); 316 int index, b, nDays = HijriDay - 1; 317 DateTime dt; 318 319 320 index = HijriYear - MinCalendarYear; 321 dt = s_hijriYearInfo[index].GregorianDate; 322 323 324 b = s_hijriYearInfo[index].HijriMonthsLengthFlags; 325 326 for (int m = 1; m < HijriMonth; m++) 327 { 328 nDays = nDays + 29 + (b & 1); /* Add the months lengths before mh */ 329 b = b >> 1; 330 } 331 332 dt = dt.AddDays(nDays); 333 dt.GetDatePart(out yg, out mg, out dg); 334 } 335 336 /*=================================GetAbsoluteDateUmAlQura========================== 337 **Action: Gets the Absolute date for the given UmAlQura date. The absolute date means 338 ** the number of days from January 1st, 1 A.D. 339 **Returns: 340 **Arguments: 341 **Exceptions: 342 ============================================================================*/ GetAbsoluteDateUmAlQura(int year, int month, int day)343 private static long GetAbsoluteDateUmAlQura(int year, int month, int day) 344 { 345 //Caller should check the validaty of year, month and day. 346 347 int yg = 0, mg = 0, dg = 0; 348 ConvertHijriToGregorian(year, month, day, ref yg, ref mg, ref dg); 349 return GregorianCalendar.GetAbsoluteDate(yg, mg, dg); 350 } 351 CheckTicksRange(long ticks)352 internal static void CheckTicksRange(long ticks) 353 { 354 if (ticks < minDate.Ticks || ticks > maxDate.Ticks) 355 { 356 throw new ArgumentOutOfRangeException( 357 "time", 358 String.Format( 359 CultureInfo.InvariantCulture, 360 SR.ArgumentOutOfRange_CalendarRange, 361 minDate, 362 maxDate)); 363 } 364 } 365 CheckEraRange(int era)366 internal static void CheckEraRange(int era) 367 { 368 if (era != CurrentEra && era != UmAlQuraEra) 369 { 370 throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue); 371 } 372 } 373 CheckYearRange(int year, int era)374 internal static void CheckYearRange(int year, int era) 375 { 376 CheckEraRange(era); 377 if (year < MinCalendarYear || year > MaxCalendarYear) 378 { 379 throw new ArgumentOutOfRangeException( 380 nameof(year), 381 String.Format( 382 CultureInfo.CurrentCulture, 383 SR.ArgumentOutOfRange_Range, 384 MinCalendarYear, 385 MaxCalendarYear)); 386 } 387 } 388 CheckYearMonthRange(int year, int month, int era)389 internal static void CheckYearMonthRange(int year, int month, int era) 390 { 391 CheckYearRange(year, era); 392 if (month < 1 || month > 12) 393 { 394 throw new ArgumentOutOfRangeException(nameof(month), SR.ArgumentOutOfRange_Month); 395 } 396 } 397 398 /*========================ConvertGregorianToHijri============================ 399 ** Purpose: convert DateTime to Hdate(year,month,day) 400 ** Arguments: 401 ** Input: DateTime 402 ** Output: Hijrah date: year:yh, month:mh, day:dh 403 ============================================================================*/ ConvertGregorianToHijri(DateTime time, ref int HijriYear, ref int HijriMonth, ref int HijriDay)404 private static void ConvertGregorianToHijri(DateTime time, ref int HijriYear, ref int HijriMonth, ref int HijriDay) 405 { 406 int index, b, DaysPerThisMonth; 407 double nDays; 408 TimeSpan ts; 409 int yh1 = 0, mh1 = 0, dh1 = 0; 410 411 Debug.Assert((time.Ticks >= minDate.Ticks) && (time.Ticks <= maxDate.Ticks), "Gregorian date is out of range."); 412 413 // Find the index where we should start our search by quessing the Hijri year that we will be in HijriYearInfo. 414 // A Hijri year is 354 or 355 days. Use 355 days so that we will search from a lower index. 415 416 index = (int)((time.Ticks - minDate.Ticks) / Calendar.TicksPerDay) / 355; 417 do 418 { 419 } while (time.CompareTo(s_hijriYearInfo[++index].GregorianDate) > 0); //while greater 420 421 if (time.CompareTo(s_hijriYearInfo[index].GregorianDate) != 0) 422 { 423 index--; 424 } 425 426 ts = time.Subtract(s_hijriYearInfo[index].GregorianDate); 427 yh1 = index + MinCalendarYear; 428 429 mh1 = 1; 430 dh1 = 1; 431 nDays = ts.TotalDays; 432 b = s_hijriYearInfo[index].HijriMonthsLengthFlags; 433 DaysPerThisMonth = 29 + (b & 1); 434 435 while (nDays >= DaysPerThisMonth) 436 { 437 nDays -= DaysPerThisMonth; 438 b = b >> 1; 439 DaysPerThisMonth = 29 + (b & 1); 440 mh1++; 441 } 442 dh1 += (int)nDays; 443 444 HijriDay = dh1; 445 HijriMonth = mh1; 446 HijriYear = yh1; 447 } 448 449 /*=================================GetDatePart========================== 450 **Action: Returns a given date part of this <i>DateTime</i>. This method is used 451 ** to compute the year, day-of-year, month, or day part. 452 **Returns: 453 **Arguments: 454 **Exceptions: ArgumentException if part is incorrect. 455 **Notes: 456 ** First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks. 457 ** Use the formula (((AbsoluteDate - 226894) * 33) / (33 * 365 + 8)) + 1, we can a rough value for the UmAlQura year. 458 ** In order to get the exact UmAlQura year, we compare the exact absolute date for UmAlQuraYear and (UmAlQuraYear + 1). 459 ** From here, we can get the correct UmAlQura year. 460 ============================================================================*/ 461 GetDatePart(DateTime time, int part)462 internal virtual int GetDatePart(DateTime time, int part) 463 { 464 int UmAlQuraYear = 0; // UmAlQura year 465 int UmAlQuraMonth = 0; // UmAlQura month 466 int UmAlQuraDay = 0; // UmAlQura day 467 long ticks = time.Ticks; 468 CheckTicksRange(ticks); 469 470 ConvertGregorianToHijri(time, ref UmAlQuraYear, ref UmAlQuraMonth, ref UmAlQuraDay); 471 472 if (part == DatePartYear) 473 return (UmAlQuraYear); 474 475 if (part == DatePartMonth) 476 return (UmAlQuraMonth); 477 478 if (part == DatePartDay) 479 return (UmAlQuraDay); 480 481 if (part == DatePartDayOfYear) 482 return (int)(GetAbsoluteDateUmAlQura(UmAlQuraYear, UmAlQuraMonth, UmAlQuraDay) - GetAbsoluteDateUmAlQura(UmAlQuraYear, 1, 1) + 1); 483 484 // Incorrect part value. 485 throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing); 486 } 487 488 // Returns the DateTime resulting from adding the given number of 489 // months to the specified DateTime. The result is computed by incrementing 490 // (or decrementing) the year and month parts of the specified DateTime by 491 // value months, and, if required, adjusting the day part of the 492 // resulting date downwards to the last day of the resulting month in the 493 // resulting year. The time-of-day part of the result is the same as the 494 // time-of-day part of the specified DateTime. 495 // 496 // In more precise terms, considering the specified DateTime to be of the 497 // form y / m / d + t, where y is the 498 // year, m is the month, d is the day, and t is the 499 // time-of-day, the result is y1 / m1 / d1 + t, 500 // where y1 and m1 are computed by adding value months 501 // to y and m, and d1 is the largest value less than 502 // or equal to d that denotes a valid day in month m1 of year 503 // y1. 504 // 505 506 AddMonths(DateTime time, int months)507 public override DateTime AddMonths(DateTime time, int months) 508 { 509 if (months < -120000 || months > 120000) 510 { 511 throw new ArgumentOutOfRangeException( 512 nameof(months), 513 String.Format( 514 CultureInfo.CurrentCulture, 515 SR.ArgumentOutOfRange_Range, 516 -120000, 517 120000)); 518 } 519 // Get the date in UmAlQura calendar. 520 int y = GetDatePart(time, DatePartYear); 521 int m = GetDatePart(time, DatePartMonth); 522 int d = GetDatePart(time, DatePartDay); 523 int i = m - 1 + months; 524 525 if (i >= 0) 526 { 527 m = i % 12 + 1; 528 y = y + i / 12; 529 } 530 else 531 { 532 m = 12 + (i + 1) % 12; 533 y = y + (i - 11) / 12; 534 } 535 536 if (d > 29) 537 { 538 int days = GetDaysInMonth(y, m); 539 if (d > days) 540 { 541 d = days; 542 } 543 } 544 CheckYearRange(y, UmAlQuraEra); 545 DateTime dt = new DateTime(GetAbsoluteDateUmAlQura(y, m, d) * TicksPerDay + time.Ticks % TicksPerDay); 546 Calendar.CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime); 547 return (dt); 548 } 549 550 // Returns the DateTime resulting from adding the given number of 551 // years to the specified DateTime. The result is computed by incrementing 552 // (or decrementing) the year part of the specified DateTime by value 553 // years. If the month and day of the specified DateTime is 2/29, and if the 554 // resulting year is not a leap year, the month and day of the resulting 555 // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day 556 // parts of the result are the same as those of the specified DateTime. 557 // 558 559 AddYears(DateTime time, int years)560 public override DateTime AddYears(DateTime time, int years) 561 { 562 return (AddMonths(time, years * 12)); 563 } 564 565 // Returns the day-of-month part of the specified DateTime. The returned 566 // value is an integer between 1 and 31. 567 // 568 569 GetDayOfMonth(DateTime time)570 public override int GetDayOfMonth(DateTime time) 571 { 572 return (GetDatePart(time, DatePartDay)); 573 } 574 575 // Returns the day-of-week part of the specified DateTime. The returned value 576 // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates 577 // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates 578 // Thursday, 5 indicates Friday, and 6 indicates Saturday. 579 // 580 581 GetDayOfWeek(DateTime time)582 public override DayOfWeek GetDayOfWeek(DateTime time) 583 { 584 return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7)); 585 } 586 587 // Returns the day-of-year part of the specified DateTime. The returned value 588 // is an integer between 1 and 354 or 355. 589 // 590 591 GetDayOfYear(DateTime time)592 public override int GetDayOfYear(DateTime time) 593 { 594 return (GetDatePart(time, DatePartDayOfYear)); 595 } 596 597 /* 598 internal bool CouldBeLeapYear(int year) 599 { 600 return ((((year * 11) + 14) % 30) < 11); 601 } 602 */ 603 604 // Returns the number of days in the month given by the year and 605 // month arguments. 606 // 607 608 GetDaysInMonth(int year, int month, int era)609 public override int GetDaysInMonth(int year, int month, int era) 610 { 611 CheckYearMonthRange(year, month, era); 612 613 if ((s_hijriYearInfo[year - MinCalendarYear].HijriMonthsLengthFlags & (1 << month - 1)) == 0) 614 return 29; 615 else 616 return 30; 617 } 618 RealGetDaysInYear(int year)619 internal static int RealGetDaysInYear(int year) 620 { 621 int days = 0, b; 622 623 Debug.Assert((year >= MinCalendarYear) && (year <= MaxCalendarYear), "Hijri year is out of range."); 624 625 b = s_hijriYearInfo[year - MinCalendarYear].HijriMonthsLengthFlags; 626 627 for (int m = 1; m <= 12; m++) 628 { 629 days = days + 29 + (b & 1); /* Add the months lengths before mh */ 630 b = b >> 1; 631 } 632 Debug.Assert((days == 354) || (days == 355), "Hijri year has to be 354 or 355 days."); 633 return days; 634 } 635 636 // Returns the number of days in the year given by the year argument for the current era. 637 // 638 639 GetDaysInYear(int year, int era)640 public override int GetDaysInYear(int year, int era) 641 { 642 CheckYearRange(year, era); 643 return (RealGetDaysInYear(year)); 644 } 645 646 // Returns the era for the specified DateTime value. 647 648 GetEra(DateTime time)649 public override int GetEra(DateTime time) 650 { 651 CheckTicksRange(time.Ticks); 652 return (UmAlQuraEra); 653 } 654 655 656 657 public override int[] Eras 658 { 659 get 660 { 661 return (new int[] { UmAlQuraEra }); 662 } 663 } 664 665 // Returns the month part of the specified DateTime. The returned value is an 666 // integer between 1 and 12. 667 // 668 669 GetMonth(DateTime time)670 public override int GetMonth(DateTime time) 671 { 672 return (GetDatePart(time, DatePartMonth)); 673 } 674 675 // Returns the number of months in the specified year and era. 676 677 GetMonthsInYear(int year, int era)678 public override int GetMonthsInYear(int year, int era) 679 { 680 CheckYearRange(year, era); 681 return (12); 682 } 683 684 // Returns the year part of the specified DateTime. The returned value is an 685 // integer between MinCalendarYear and MaxCalendarYear. 686 // 687 688 GetYear(DateTime time)689 public override int GetYear(DateTime time) 690 { 691 return (GetDatePart(time, DatePartYear)); 692 } 693 694 // Checks whether a given day in the specified era is a leap day. This method returns true if 695 // the date is a leap day, or false if not. 696 // 697 698 IsLeapDay(int year, int month, int day, int era)699 public override bool IsLeapDay(int year, int month, int day, int era) 700 { 701 if (day >= 1 && day <= 29) 702 { 703 CheckYearMonthRange(year, month, era); 704 return (false); 705 } 706 707 // The year/month/era value checking is done in GetDaysInMonth(). 708 int daysInMonth = GetDaysInMonth(year, month, era); 709 if (day < 1 || day > daysInMonth) 710 { 711 throw new ArgumentOutOfRangeException( 712 nameof(day), 713 String.Format( 714 CultureInfo.CurrentCulture, 715 SR.ArgumentOutOfRange_Day, 716 daysInMonth, 717 month)); 718 } 719 return (false); 720 } 721 722 // Returns the leap month in a calendar year of the specified era. This method returns 0 723 // if this calendar does not have leap month, or this year is not a leap year. 724 // 725 726 GetLeapMonth(int year, int era)727 public override int GetLeapMonth(int year, int era) 728 { 729 CheckYearRange(year, era); 730 return (0); 731 } 732 733 // Checks whether a given month in the specified era is a leap month. This method returns true if 734 // month is a leap month, or false if not. 735 // 736 737 IsLeapMonth(int year, int month, int era)738 public override bool IsLeapMonth(int year, int month, int era) 739 { 740 CheckYearMonthRange(year, month, era); 741 return (false); 742 } 743 744 // Checks whether a given year in the specified era is a leap year. This method returns true if 745 // year is a leap year, or false if not. 746 // 747 748 IsLeapYear(int year, int era)749 public override bool IsLeapYear(int year, int era) 750 { 751 CheckYearRange(year, era); 752 if (RealGetDaysInYear(year) == 355) 753 return true; 754 else 755 return false; 756 } 757 758 // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid. 759 // 760 761 ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)762 public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) 763 { 764 if (day >= 1 && day <= 29) 765 { 766 CheckYearMonthRange(year, month, era); 767 goto DayInRang; 768 } 769 770 // The year/month/era value checking is done in GetDaysInMonth(). 771 int daysInMonth = GetDaysInMonth(year, month, era); 772 773 if (day < 1 || day > daysInMonth) 774 { 775 throw new ArgumentOutOfRangeException( 776 nameof(day), 777 String.Format( 778 CultureInfo.CurrentCulture, 779 SR.ArgumentOutOfRange_Day, 780 daysInMonth, 781 month)); 782 } 783 DayInRang: 784 long lDate = GetAbsoluteDateUmAlQura(year, month, day); 785 786 if (lDate >= 0) 787 { 788 return (new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond))); 789 } 790 else 791 { 792 throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); 793 } 794 } 795 796 private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 1451; 797 798 799 800 public override int TwoDigitYearMax 801 { 802 get 803 { 804 if (twoDigitYearMax == -1) 805 { 806 twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX); 807 } 808 return (twoDigitYearMax); 809 } 810 811 set 812 { 813 if (value != 99 && (value < MinCalendarYear || value > MaxCalendarYear)) 814 { 815 throw new ArgumentOutOfRangeException( 816 nameof(value), 817 String.Format( 818 CultureInfo.CurrentCulture, 819 SR.ArgumentOutOfRange_Range, 820 MinCalendarYear, 821 MaxCalendarYear)); 822 } 823 VerifyWritable(); 824 // We allow year 99 to be set so that one can make ToFourDigitYearMax a no-op by setting TwoDigitYearMax to 99. 825 twoDigitYearMax = value; 826 } 827 } 828 829 830 ToFourDigitYear(int year)831 public override int ToFourDigitYear(int year) 832 { 833 if (year < 0) 834 { 835 throw new ArgumentOutOfRangeException(nameof(year), 836 SR.ArgumentOutOfRange_NeedNonNegNum); 837 } 838 839 if (year < 100) 840 { 841 return (base.ToFourDigitYear(year)); 842 } 843 844 if ((year < MinCalendarYear) || (year > MaxCalendarYear)) 845 { 846 throw new ArgumentOutOfRangeException( 847 nameof(year), 848 String.Format( 849 CultureInfo.CurrentCulture, 850 SR.ArgumentOutOfRange_Range, 851 MinCalendarYear, 852 MaxCalendarYear)); 853 } 854 return (year); 855 } 856 } 857 } 858 859