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.
5 using System
.Diagnostics
;
7 namespace System
.Globalization
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
16 public partial class UmAlQuraCalendar
: Calendar
18 private const int MinCalendarYear
= 1318;
19 private const int MaxCalendarYear
= 1500;
21 private struct DateMapping
23 internal DateMapping(int MonthsLengthFlags
, int GYear
, int GMonth
, int GDay
)
25 HijriMonthsLengthFlags
= MonthsLengthFlags
;
26 GregorianDate
= new DateTime(GYear
, GMonth
, GDay
);
29 internal int HijriMonthsLengthFlags
;
30 internal DateTime GregorianDate
;
33 private static readonly DateMapping
[] s_hijriYearInfo
= InitDateMapping();
35 private static DateMapping
[] InitDateMapping()
37 short[] rawData
= new short[]
39 // These data are 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
226 // Direct inline initialization of DateMapping array would produce a lot of code bloat.
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
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]);
237 public const int UmAlQuraEra
= 1;
239 private const int DatePartYear
= 0;
240 private const int DatePartDayOfYear
= 1;
241 private const int DatePartMonth
= 2;
242 private const int DatePartDay
= 3;
244 private static readonly DateTime s_minDate
= new DateTime(1900, 4, 30);
245 private static readonly DateTime s_maxDate
= new DateTime((new DateTime(2077, 11, 16, 23, 59, 59, 999)).Ticks
+ 9999);
247 public override DateTime MinSupportedDateTime
=> s_minDate
;
249 public override DateTime MaxSupportedDateTime
=> s_maxDate
;
251 public override CalendarAlgorithmType AlgorithmType
=> CalendarAlgorithmType
.LunarCalendar
;
253 public UmAlQuraCalendar()
257 internal override CalendarId BaseCalendarID
=> CalendarId
.HIJRI
;
259 internal override CalendarId ID
=> CalendarId
.UMALQURA
;
261 protected override int DaysInYearBeforeMinSupportedYear
=>
262 // HijriCalendar has same number of days as UmAlQuraCalendar for any given year
263 // HijriCalendar says year 1317 has 355 days.
266 private static void ConvertHijriToGregorian(int HijriYear
, int HijriMonth
, int HijriDay
, out int yg
, out int mg
, out int dg
)
268 Debug
.Assert((HijriYear
>= MinCalendarYear
) && (HijriYear
<= MaxCalendarYear
), "Hijri year is out of range.");
269 Debug
.Assert(HijriMonth
>= 1, "Hijri month is out of range.");
270 Debug
.Assert(HijriDay
>= 1, "Hijri day is out of range.");
271 int nDays
= HijriDay
- 1;
273 int index
= HijriYear
- MinCalendarYear
;
274 DateTime dt
= s_hijriYearInfo
[index
].GregorianDate
;
275 int b
= s_hijriYearInfo
[index
].HijriMonthsLengthFlags
;
277 for (int m
= 1; m
< HijriMonth
; m
++)
279 // Add the months lengths before mh
280 nDays
= nDays
+ 29 + (b
& 1);
284 dt
= dt
.AddDays(nDays
);
285 dt
.GetDatePart(out yg
, out mg
, out dg
);
288 private static long GetAbsoluteDateUmAlQura(int year
, int month
, int day
)
290 ConvertHijriToGregorian(year
, month
, day
, out int yg
, out int mg
, out int dg
);
291 return GregorianCalendar
.GetAbsoluteDate(yg
, mg
, dg
);
294 internal static void CheckTicksRange(long ticks
)
296 if (ticks
< s_minDate
.Ticks
|| ticks
> s_maxDate
.Ticks
)
298 throw new ArgumentOutOfRangeException(
302 CultureInfo
.InvariantCulture
,
303 SR
.ArgumentOutOfRange_CalendarRange
,
309 internal static void CheckEraRange(int era
)
311 if (era
!= CurrentEra
&& era
!= UmAlQuraEra
)
313 throw new ArgumentOutOfRangeException(nameof(era
), era
, SR
.ArgumentOutOfRange_InvalidEraValue
);
317 internal static void CheckYearRange(int year
, int era
)
320 if (year
< MinCalendarYear
|| year
> MaxCalendarYear
)
322 throw new ArgumentOutOfRangeException(
325 SR
.Format(SR
.ArgumentOutOfRange_Range
, MinCalendarYear
, MaxCalendarYear
));
329 internal static void CheckYearMonthRange(int year
, int month
, int era
)
331 CheckYearRange(year
, era
);
332 if (month
< 1 || month
> 12)
334 throw new ArgumentOutOfRangeException(nameof(month
), month
, SR
.ArgumentOutOfRange_Month
);
338 private static void ConvertGregorianToHijri(DateTime time
, out int HijriYear
, out int HijriMonth
, out int HijriDay
)
340 Debug
.Assert((time
.Ticks
>= s_minDate
.Ticks
) && (time
.Ticks
<= s_maxDate
.Ticks
), "Gregorian date is out of range.");
342 // Find the index where we should start our search by quessing the Hijri year that we will be in HijriYearInfo.
343 // A Hijri year is 354 or 355 days. Use 355 days so that we will search from a lower index.
345 int index
= (int)((time
.Ticks
- s_minDate
.Ticks
) / Calendar
.TicksPerDay
) / 355;
348 } while (time
.CompareTo(s_hijriYearInfo
[++index
].GregorianDate
) > 0); // while greater
350 if (time
.CompareTo(s_hijriYearInfo
[index
].GregorianDate
) != 0)
355 TimeSpan ts
= time
.Subtract(s_hijriYearInfo
[index
].GregorianDate
);
356 int yh1
= index
+ MinCalendarYear
;
359 double nDays
= ts
.TotalDays
;
360 int b
= s_hijriYearInfo
[index
].HijriMonthsLengthFlags
;
361 int daysPerThisMonth
= 29 + (b
& 1);
363 while (nDays
>= daysPerThisMonth
)
365 nDays
-= daysPerThisMonth
;
367 daysPerThisMonth
= 29 + (b
& 1);
378 /// First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks.
379 /// Use the formula (((AbsoluteDate - 226894) * 33) / (33 * 365 + 8)) + 1, we can a rough value for the UmAlQura year.
380 /// In order to get the exact UmAlQura year, we compare the exact absolute date for UmAlQuraYear and (UmAlQuraYear + 1).
381 /// From here, we can get the correct UmAlQura year.
383 private int GetDatePart(DateTime time
, int part
)
385 long ticks
= time
.Ticks
;
386 CheckTicksRange(ticks
);
388 ConvertGregorianToHijri(time
, out int UmAlQuraYear
, out int UmAlQuraMonth
, out int UmAlQuraDay
);
390 if (part
== DatePartYear
)
394 if (part
== DatePartMonth
)
396 return UmAlQuraMonth
;
398 if (part
== DatePartDay
)
402 if (part
== DatePartDayOfYear
)
404 return (int)(GetAbsoluteDateUmAlQura(UmAlQuraYear
, UmAlQuraMonth
, UmAlQuraDay
) - GetAbsoluteDateUmAlQura(UmAlQuraYear
, 1, 1) + 1);
407 // Incorrect part value.
408 throw new InvalidOperationException(SR
.InvalidOperation_DateTimeParsing
);
411 public override DateTime
AddMonths(DateTime time
, int months
)
413 if (months
< -120000 || months
> 120000)
415 throw new ArgumentOutOfRangeException(
418 SR
.Format(SR
.ArgumentOutOfRange_Range
, -120000, 120000));
421 // Get the date in UmAlQura calendar.
422 int y
= GetDatePart(time
, DatePartYear
);
423 int m
= GetDatePart(time
, DatePartMonth
);
424 int d
= GetDatePart(time
, DatePartDay
);
425 int i
= m
- 1 + months
;
434 m
= 12 + (i
+ 1) % 12;
440 int days
= GetDaysInMonth(y
, m
);
447 CheckYearRange(y
, UmAlQuraEra
);
448 DateTime dt
= new DateTime(GetAbsoluteDateUmAlQura(y
, m
, d
) * TicksPerDay
+ time
.Ticks
% TicksPerDay
);
449 Calendar
.CheckAddResult(dt
.Ticks
, MinSupportedDateTime
, MaxSupportedDateTime
);
453 public override DateTime
AddYears(DateTime time
, int years
)
455 return AddMonths(time
, years
* 12);
458 public override int GetDayOfMonth(DateTime time
)
460 return GetDatePart(time
, DatePartDay
);
463 public override DayOfWeek
GetDayOfWeek(DateTime time
)
465 return (DayOfWeek
)((int)(time
.Ticks
/ TicksPerDay
+ 1) % 7);
468 public override int GetDayOfYear(DateTime time
)
470 return GetDatePart(time
, DatePartDayOfYear
);
473 public override int GetDaysInMonth(int year
, int month
, int era
)
475 CheckYearMonthRange(year
, month
, era
);
477 if ((s_hijriYearInfo
[year
- MinCalendarYear
].HijriMonthsLengthFlags
& (1 << month
- 1)) == 0)
487 internal static int RealGetDaysInYear(int year
)
491 Debug
.Assert((year
>= MinCalendarYear
) && (year
<= MaxCalendarYear
), "Hijri year is out of range.");
493 int b
= s_hijriYearInfo
[year
- MinCalendarYear
].HijriMonthsLengthFlags
;
495 for (int m
= 1; m
<= 12; m
++)
497 days
= days
+ 29 + (b
& 1); /* Add the months lengths before mh */
501 Debug
.Assert((days
== 354) || (days
== 355), "Hijri year has to be 354 or 355 days.");
505 public override int GetDaysInYear(int year
, int era
)
507 CheckYearRange(year
, era
);
508 return RealGetDaysInYear(year
);
511 public override int GetEra(DateTime time
)
513 CheckTicksRange(time
.Ticks
);
517 public override int[] Eras
=> new int[] { UmAlQuraEra }
;
519 public override int GetMonth(DateTime time
)
521 return GetDatePart(time
, DatePartMonth
);
524 public override int GetMonthsInYear(int year
, int era
)
526 CheckYearRange(year
, era
);
530 public override int GetYear(DateTime time
)
532 return GetDatePart(time
, DatePartYear
);
535 public override bool IsLeapDay(int year
, int month
, int day
, int era
)
537 if (day
>= 1 && day
<= 29)
539 CheckYearMonthRange(year
, month
, era
);
543 // The year/month/era value checking is done in GetDaysInMonth().
544 int daysInMonth
= GetDaysInMonth(year
, month
, era
);
545 if (day
< 1 || day
> daysInMonth
)
547 throw new ArgumentOutOfRangeException(
550 SR
.Format(SR
.ArgumentOutOfRange_Day
, daysInMonth
, month
));
555 public override int GetLeapMonth(int year
, int era
)
557 CheckYearRange(year
, era
);
561 public override bool IsLeapMonth(int year
, int month
, int era
)
563 CheckYearMonthRange(year
, month
, era
);
567 public override bool IsLeapYear(int year
, int era
)
569 CheckYearRange(year
, era
);
570 return RealGetDaysInYear(year
) == 355;
573 public override DateTime
ToDateTime(int year
, int month
, int day
, int hour
, int minute
, int second
, int millisecond
, int era
)
575 if (day
>= 1 && day
<= 29)
577 CheckYearMonthRange(year
, month
, era
);
581 // The year/month/era value checking is done in GetDaysInMonth().
582 int daysInMonth
= GetDaysInMonth(year
, month
, era
);
584 if (day
< 1 || day
> daysInMonth
)
586 throw new ArgumentOutOfRangeException(
589 SR
.Format(SR
.ArgumentOutOfRange_Day
, daysInMonth
, month
));
592 long lDate
= GetAbsoluteDateUmAlQura(year
, month
, day
);
595 throw new ArgumentOutOfRangeException(null, SR
.ArgumentOutOfRange_BadYearMonthDay
);
598 return new DateTime(lDate
* GregorianCalendar
.TicksPerDay
+ TimeToTicks(hour
, minute
, second
, millisecond
));
601 private const int DefaultTwoDigitYearMax
= 1451;
603 public override int TwoDigitYearMax
607 if (_twoDigitYearMax
== -1)
609 _twoDigitYearMax
= GetSystemTwoDigitYearSetting(ID
, DefaultTwoDigitYearMax
);
612 return _twoDigitYearMax
;
616 if (value != 99 && (value < MinCalendarYear
|| value > MaxCalendarYear
))
618 throw new ArgumentOutOfRangeException(
621 SR
.Format(SR
.ArgumentOutOfRange_Range
, MinCalendarYear
, MaxCalendarYear
));
625 // We allow year 99 to be set so that one can make ToFourDigitYearMax a no-op by setting TwoDigitYearMax to 99.
626 _twoDigitYearMax
= value;
630 public override int ToFourDigitYear(int year
)
634 throw new ArgumentOutOfRangeException(nameof(year
), year
, SR
.ArgumentOutOfRange_NeedNonNegNum
);
639 return base.ToFourDigitYear(year
);
642 if (year
< MinCalendarYear
|| year
> MaxCalendarYear
)
644 throw new ArgumentOutOfRangeException(
647 SR
.Format(SR
.ArgumentOutOfRange_Range
, MinCalendarYear
, MaxCalendarYear
));