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