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