1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 * Copyright (C) 2003-2015, International Business Machines Corporation
6 * and others. All Rights Reserved.
7 ******************************************************************************
8 *
9 * File ISLAMCAL.H
10 *
11 * Modification History:
12 *
13 * Date Name Description
14 * 10/14/2003 srl ported from java IslamicCalendar
15 *****************************************************************************
16 */
17
18 #include "islamcal.h"
19
20 #if !UCONFIG_NO_FORMATTING
21
22 #include "umutex.h"
23 #include <float.h>
24 #include "gregoimp.h" // Math
25 #include "astro.h" // CalendarAstronomer
26 #include "uhash.h"
27 #include "ucln_in.h"
28 #include "uassert.h"
29
30 static const UDate HIJRA_MILLIS = -42521587200000.0; // 7/16/622 AD 00:00
31
32 // Debugging
33 #ifdef U_DEBUG_ISLAMCAL
34 # include <stdio.h>
35 # include <stdarg.h>
debug_islamcal_loc(const char * f,int32_t l)36 static void debug_islamcal_loc(const char *f, int32_t l)
37 {
38 fprintf(stderr, "%s:%d: ", f, l);
39 }
40
debug_islamcal_msg(const char * pat,...)41 static void debug_islamcal_msg(const char *pat, ...)
42 {
43 va_list ap;
44 va_start(ap, pat);
45 vfprintf(stderr, pat, ap);
46 fflush(stderr);
47 }
48 // must use double parens, i.e.: U_DEBUG_ISLAMCAL_MSG(("four is: %d",4));
49 #define U_DEBUG_ISLAMCAL_MSG(x) {debug_islamcal_loc(__FILE__,__LINE__);debug_islamcal_msg x;}
50 #else
51 #define U_DEBUG_ISLAMCAL_MSG(x)
52 #endif
53
54
55 // --- The cache --
56 // cache of months
57 static icu::CalendarCache *gMonthCache = nullptr;
58 static icu::CalendarAstronomer *gIslamicCalendarAstro = nullptr;
59
60 U_CDECL_BEGIN
calendar_islamic_cleanup()61 static UBool calendar_islamic_cleanup() {
62 if (gMonthCache) {
63 delete gMonthCache;
64 gMonthCache = nullptr;
65 }
66 if (gIslamicCalendarAstro) {
67 delete gIslamicCalendarAstro;
68 gIslamicCalendarAstro = nullptr;
69 }
70 return true;
71 }
72 U_CDECL_END
73
74 U_NAMESPACE_BEGIN
75
76 // Implementation of the IslamicCalendar class
77
78 /**
79 * Friday EPOC
80 */
81 static const int32_t CIVIL_EPOC = 1948440; // CE 622 July 16 Friday (Julian calendar) / CE 622 July 19 (Gregorian calendar)
82
83 /**
84 * Thursday EPOC
85 */
86 static const int32_t ASTRONOMICAL_EPOC = 1948439; // CE 622 July 15 Thursday (Julian calendar)
87
88
89 static const int32_t UMALQURA_YEAR_START = 1300;
90 static const int32_t UMALQURA_YEAR_END = 1600;
91
92 static const int UMALQURA_MONTHLENGTH[] = {
93 //* 1300 -1302 */ "1010 1010 1010", "1101 0101 0100", "1110 1100 1001",
94 0x0AAA, 0x0D54, 0x0EC9,
95 //* 1303 -1307 */ "0110 1101 0100", "0110 1110 1010", "0011 0110 1100", "1010 1010 1101", "0101 0101 0101",
96 0x06D4, 0x06EA, 0x036C, 0x0AAD, 0x0555,
97 //* 1308 -1312 */ "0110 1010 1001", "0111 1001 0010", "1011 1010 1001", "0101 1101 0100", "1010 1101 1010",
98 0x06A9, 0x0792, 0x0BA9, 0x05D4, 0x0ADA,
99 //* 1313 -1317 */ "0101 0101 1100", "1101 0010 1101", "0110 1001 0101", "0111 0100 1010", "1011 0101 0100",
100 0x055C, 0x0D2D, 0x0695, 0x074A, 0x0B54,
101 //* 1318 -1322 */ "1011 0110 1010", "0101 1010 1101", "0100 1010 1110", "1010 0100 1111", "0101 0001 0111",
102 0x0B6A, 0x05AD, 0x04AE, 0x0A4F, 0x0517,
103 //* 1323 -1327 */ "0110 1000 1011", "0110 1010 0101", "1010 1101 0101", "0010 1101 0110", "1001 0101 1011",
104 0x068B, 0x06A5, 0x0AD5, 0x02D6, 0x095B,
105 //* 1328 -1332 */ "0100 1001 1101", "1010 0100 1101", "1101 0010 0110", "1101 1001 0101", "0101 1010 1100",
106 0x049D, 0x0A4D, 0x0D26, 0x0D95, 0x05AC,
107 //* 1333 -1337 */ "1001 1011 0110", "0010 1011 1010", "1010 0101 1011", "0101 0010 1011", "1010 1001 0101",
108 0x09B6, 0x02BA, 0x0A5B, 0x052B, 0x0A95,
109 //* 1338 -1342 */ "0110 1100 1010", "1010 1110 1001", "0010 1111 0100", "1001 0111 0110", "0010 1011 0110",
110 0x06CA, 0x0AE9, 0x02F4, 0x0976, 0x02B6,
111 //* 1343 -1347 */ "1001 0101 0110", "1010 1100 1010", "1011 1010 0100", "1011 1101 0010", "0101 1101 1001",
112 0x0956, 0x0ACA, 0x0BA4, 0x0BD2, 0x05D9,
113 //* 1348 -1352 */ "0010 1101 1100", "1001 0110 1101", "0101 0100 1101", "1010 1010 0101", "1011 0101 0010",
114 0x02DC, 0x096D, 0x054D, 0x0AA5, 0x0B52,
115 //* 1353 -1357 */ "1011 1010 0101", "0101 1011 0100", "1001 1011 0110", "0101 0101 0111", "0010 1001 0111",
116 0x0BA5, 0x05B4, 0x09B6, 0x0557, 0x0297,
117 //* 1358 -1362 */ "0101 0100 1011", "0110 1010 0011", "0111 0101 0010", "1011 0110 0101", "0101 0110 1010",
118 0x054B, 0x06A3, 0x0752, 0x0B65, 0x056A,
119 //* 1363 -1367 */ "1010 1010 1011", "0101 0010 1011", "1100 1001 0101", "1101 0100 1010", "1101 1010 0101",
120 0x0AAB, 0x052B, 0x0C95, 0x0D4A, 0x0DA5,
121 //* 1368 -1372 */ "0101 1100 1010", "1010 1101 0110", "1001 0101 0111", "0100 1010 1011", "1001 0100 1011",
122 0x05CA, 0x0AD6, 0x0957, 0x04AB, 0x094B,
123 //* 1373 -1377 */ "1010 1010 0101", "1011 0101 0010", "1011 0110 1010", "0101 0111 0101", "0010 0111 0110",
124 0x0AA5, 0x0B52, 0x0B6A, 0x0575, 0x0276,
125 //* 1378 -1382 */ "1000 1011 0111", "0100 0101 1011", "0101 0101 0101", "0101 1010 1001", "0101 1011 0100",
126 0x08B7, 0x045B, 0x0555, 0x05A9, 0x05B4,
127 //* 1383 -1387 */ "1001 1101 1010", "0100 1101 1101", "0010 0110 1110", "1001 0011 0110", "1010 1010 1010",
128 0x09DA, 0x04DD, 0x026E, 0x0936, 0x0AAA,
129 //* 1388 -1392 */ "1101 0101 0100", "1101 1011 0010", "0101 1101 0101", "0010 1101 1010", "1001 0101 1011",
130 0x0D54, 0x0DB2, 0x05D5, 0x02DA, 0x095B,
131 //* 1393 -1397 */ "0100 1010 1011", "1010 0101 0101", "1011 0100 1001", "1011 0110 0100", "1011 0111 0001",
132 0x04AB, 0x0A55, 0x0B49, 0x0B64, 0x0B71,
133 //* 1398 -1402 */ "0101 1011 0100", "1010 1011 0101", "1010 0101 0101", "1101 0010 0101", "1110 1001 0010",
134 0x05B4, 0x0AB5, 0x0A55, 0x0D25, 0x0E92,
135 //* 1403 -1407 */ "1110 1100 1001", "0110 1101 0100", "1010 1110 1001", "1001 0110 1011", "0100 1010 1011",
136 0x0EC9, 0x06D4, 0x0AE9, 0x096B, 0x04AB,
137 //* 1408 -1412 */ "1010 1001 0011", "1101 0100 1001", "1101 1010 0100", "1101 1011 0010", "1010 1011 1001",
138 0x0A93, 0x0D49, 0x0DA4, 0x0DB2, 0x0AB9,
139 //* 1413 -1417 */ "0100 1011 1010", "1010 0101 1011", "0101 0010 1011", "1010 1001 0101", "1011 0010 1010",
140 0x04BA, 0x0A5B, 0x052B, 0x0A95, 0x0B2A,
141 //* 1418 -1422 */ "1011 0101 0101", "0101 0101 1100", "0100 1011 1101", "0010 0011 1101", "1001 0001 1101",
142 0x0B55, 0x055C, 0x04BD, 0x023D, 0x091D,
143 //* 1423 -1427 */ "1010 1001 0101", "1011 0100 1010", "1011 0101 1010", "0101 0110 1101", "0010 1011 0110",
144 0x0A95, 0x0B4A, 0x0B5A, 0x056D, 0x02B6,
145 //* 1428 -1432 */ "1001 0011 1011", "0100 1001 1011", "0110 0101 0101", "0110 1010 1001", "0111 0101 0100",
146 0x093B, 0x049B, 0x0655, 0x06A9, 0x0754,
147 //* 1433 -1437 */ "1011 0110 1010", "0101 0110 1100", "1010 1010 1101", "0101 0101 0101", "1011 0010 1001",
148 0x0B6A, 0x056C, 0x0AAD, 0x0555, 0x0B29,
149 //* 1438 -1442 */ "1011 1001 0010", "1011 1010 1001", "0101 1101 0100", "1010 1101 1010", "0101 0101 1010",
150 0x0B92, 0x0BA9, 0x05D4, 0x0ADA, 0x055A,
151 //* 1443 -1447 */ "1010 1010 1011", "0101 1001 0101", "0111 0100 1001", "0111 0110 0100", "1011 1010 1010",
152 0x0AAB, 0x0595, 0x0749, 0x0764, 0x0BAA,
153 //* 1448 -1452 */ "0101 1011 0101", "0010 1011 0110", "1010 0101 0110", "1110 0100 1101", "1011 0010 0101",
154 0x05B5, 0x02B6, 0x0A56, 0x0E4D, 0x0B25,
155 //* 1453 -1457 */ "1011 0101 0010", "1011 0110 1010", "0101 1010 1101", "0010 1010 1110", "1001 0010 1111",
156 0x0B52, 0x0B6A, 0x05AD, 0x02AE, 0x092F,
157 //* 1458 -1462 */ "0100 1001 0111", "0110 0100 1011", "0110 1010 0101", "0110 1010 1100", "1010 1101 0110",
158 0x0497, 0x064B, 0x06A5, 0x06AC, 0x0AD6,
159 //* 1463 -1467 */ "0101 0101 1101", "0100 1001 1101", "1010 0100 1101", "1101 0001 0110", "1101 1001 0101",
160 0x055D, 0x049D, 0x0A4D, 0x0D16, 0x0D95,
161 //* 1468 -1472 */ "0101 1010 1010", "0101 1011 0101", "0010 1101 1010", "1001 0101 1011", "0100 1010 1101",
162 0x05AA, 0x05B5, 0x02DA, 0x095B, 0x04AD,
163 //* 1473 -1477 */ "0101 1001 0101", "0110 1100 1010", "0110 1110 0100", "1010 1110 1010", "0100 1111 0101",
164 0x0595, 0x06CA, 0x06E4, 0x0AEA, 0x04F5,
165 //* 1478 -1482 */ "0010 1011 0110", "1001 0101 0110", "1010 1010 1010", "1011 0101 0100", "1011 1101 0010",
166 0x02B6, 0x0956, 0x0AAA, 0x0B54, 0x0BD2,
167 //* 1483 -1487 */ "0101 1101 1001", "0010 1110 1010", "1001 0110 1101", "0100 1010 1101", "1010 1001 0101",
168 0x05D9, 0x02EA, 0x096D, 0x04AD, 0x0A95,
169 //* 1488 -1492 */ "1011 0100 1010", "1011 1010 0101", "0101 1011 0010", "1001 1011 0101", "0100 1101 0110",
170 0x0B4A, 0x0BA5, 0x05B2, 0x09B5, 0x04D6,
171 //* 1493 -1497 */ "1010 1001 0111", "0101 0100 0111", "0110 1001 0011", "0111 0100 1001", "1011 0101 0101",
172 0x0A97, 0x0547, 0x0693, 0x0749, 0x0B55,
173 //* 1498 -1508 */ "0101 0110 1010", "1010 0110 1011", "0101 0010 1011", "1010 1000 1011", "1101 0100 0110", "1101 1010 0011", "0101 1100 1010", "1010 1101 0110", "0100 1101 1011", "0010 0110 1011", "1001 0100 1011",
174 0x056A, 0x0A6B, 0x052B, 0x0A8B, 0x0D46, 0x0DA3, 0x05CA, 0x0AD6, 0x04DB, 0x026B, 0x094B,
175 //* 1509 -1519 */ "1010 1010 0101", "1011 0101 0010", "1011 0110 1001", "0101 0111 0101", "0001 0111 0110", "1000 1011 0111", "0010 0101 1011", "0101 0010 1011", "0101 0110 0101", "0101 1011 0100", "1001 1101 1010",
176 0x0AA5, 0x0B52, 0x0B69, 0x0575, 0x0176, 0x08B7, 0x025B, 0x052B, 0x0565, 0x05B4, 0x09DA,
177 //* 1520 -1530 */ "0100 1110 1101", "0001 0110 1101", "1000 1011 0110", "1010 1010 0110", "1101 0101 0010", "1101 1010 1001", "0101 1101 0100", "1010 1101 1010", "1001 0101 1011", "0100 1010 1011", "0110 0101 0011",
178 0x04ED, 0x016D, 0x08B6, 0x0AA6, 0x0D52, 0x0DA9, 0x05D4, 0x0ADA, 0x095B, 0x04AB, 0x0653,
179 //* 1531 -1541 */ "0111 0010 1001", "0111 0110 0010", "1011 1010 1001", "0101 1011 0010", "1010 1011 0101", "0101 0101 0101", "1011 0010 0101", "1101 1001 0010", "1110 1100 1001", "0110 1101 0010", "1010 1110 1001",
180 0x0729, 0x0762, 0x0BA9, 0x05B2, 0x0AB5, 0x0555, 0x0B25, 0x0D92, 0x0EC9, 0x06D2, 0x0AE9,
181 //* 1542 -1552 */ "0101 0110 1011", "0100 1010 1011", "1010 0101 0101", "1101 0010 1001", "1101 0101 0100", "1101 1010 1010", "1001 1011 0101", "0100 1011 1010", "1010 0011 1011", "0100 1001 1011", "1010 0100 1101",
182 0x056B, 0x04AB, 0x0A55, 0x0D29, 0x0D54, 0x0DAA, 0x09B5, 0x04BA, 0x0A3B, 0x049B, 0x0A4D,
183 //* 1553 -1563 */ "1010 1010 1010", "1010 1101 0101", "0010 1101 1010", "1001 0101 1101", "0100 0101 1110", "1010 0010 1110", "1100 1001 1010", "1101 0101 0101", "0110 1011 0010", "0110 1011 1001", "0100 1011 1010",
184 0x0AAA, 0x0AD5, 0x02DA, 0x095D, 0x045E, 0x0A2E, 0x0C9A, 0x0D55, 0x06B2, 0x06B9, 0x04BA,
185 //* 1564 -1574 */ "1010 0101 1101", "0101 0010 1101", "1010 1001 0101", "1011 0101 0010", "1011 1010 1000", "1011 1011 0100", "0101 1011 1001", "0010 1101 1010", "1001 0101 1010", "1011 0100 1010", "1101 1010 0100",
186 0x0A5D, 0x052D, 0x0A95, 0x0B52, 0x0BA8, 0x0BB4, 0x05B9, 0x02DA, 0x095A, 0x0B4A, 0x0DA4,
187 //* 1575 -1585 */ "1110 1101 0001", "0110 1110 1000", "1011 0110 1010", "0101 0110 1101", "0101 0011 0101", "0110 1001 0101", "1101 0100 1010", "1101 1010 1000", "1101 1101 0100", "0110 1101 1010", "0101 0101 1011",
188 0x0ED1, 0x06E8, 0x0B6A, 0x056D, 0x0535, 0x0695, 0x0D4A, 0x0DA8, 0x0DD4, 0x06DA, 0x055B,
189 //* 1586 -1596 */ "0010 1001 1101", "0110 0010 1011", "1011 0001 0101", "1011 0100 1010", "1011 1001 0101", "0101 1010 1010", "1010 1010 1110", "1001 0010 1110", "1100 1000 1111", "0101 0010 0111", "0110 1001 0101",
190 0x029D, 0x062B, 0x0B15, 0x0B4A, 0x0B95, 0x05AA, 0x0AAE, 0x092E, 0x0C8F, 0x0527, 0x0695,
191 //* 1597 -1600 */ "0110 1010 1010", "1010 1101 0110", "0101 0101 1101", "0010 1001 1101", };
192 0x06AA, 0x0AD6, 0x055D, 0x029D
193 };
194
getUmalqura_MonthLength(int32_t y,int32_t m)195 int32_t getUmalqura_MonthLength(int32_t y, int32_t m) {
196 int32_t mask = (int32_t) (0x01 << (11 - m)); // set mask for bit corresponding to month
197 if((UMALQURA_MONTHLENGTH[y] & mask) == 0 )
198 return 29;
199 else
200 return 30;
201
202 }
203
204 //-------------------------------------------------------------------------
205 // Constructors...
206 //-------------------------------------------------------------------------
207
getType() const208 const char *IslamicCalendar::getType() const {
209 return "islamic";
210 }
211
clone() const212 IslamicCalendar* IslamicCalendar::clone() const {
213 return new IslamicCalendar(*this);
214 }
215
IslamicCalendar(const Locale & aLocale,UErrorCode & success)216 IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success)
217 : Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
218 {
219 setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
220 }
221
~IslamicCalendar()222 IslamicCalendar::~IslamicCalendar()
223 {
224 }
225 //-------------------------------------------------------------------------
226 // Minimum / Maximum access functions
227 //-------------------------------------------------------------------------
228
229 // Note: Current IslamicCalendar implementation does not work
230 // well with negative years.
231
232 // TODO: In some cases the current ICU Islamic calendar implementation shows
233 // a month as having 31 days. Since date parsing now uses range checks based
234 // on the table below, we need to change the range for last day of month to
235 // include 31 as a workaround until the implementation is fixed.
236 static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
237 // Minimum Greatest Least Maximum
238 // Minimum Maximum
239 { 0, 0, 0, 0}, // ERA
240 { 1, 1, 5000000, 5000000}, // YEAR
241 { 0, 0, 11, 11}, // MONTH
242 { 1, 1, 50, 51}, // WEEK_OF_YEAR
243 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
244 { 1, 1, 29, 31}, // DAY_OF_MONTH - 31 to workaround for cal implementation bug, should be 30
245 { 1, 1, 354, 355}, // DAY_OF_YEAR
246 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
247 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
248 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
249 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
250 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
251 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
252 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
253 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
254 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
255 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
256 { 1, 1, 5000000, 5000000}, // YEAR_WOY
257 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
258 { 1, 1, 5000000, 5000000}, // EXTENDED_YEAR
259 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
260 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
261 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
262 { 0, 0, 11, 11}, // ORDINAL_MONTH
263 };
264
265 /**
266 * @draft ICU 2.4
267 */
handleGetLimit(UCalendarDateFields field,ELimitType limitType) const268 int32_t IslamicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
269 return LIMITS[field][limitType];
270 }
271
272 //-------------------------------------------------------------------------
273 // Assorted calculation utilities
274 //
275
276 // we could compress this down more if we need to
277 static const int8_t umAlQuraYrStartEstimateFix[] = {
278 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, // 1300..
279 -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, // 1310..
280 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, // 1320..
281 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 1330..
282 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, // 1340..
283 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, // 1350..
284 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, // 1360..
285 0, 1, 1, 0, 0, -1, 0, 1, 0, 1, // 1370..
286 1, 0, 0, -1, 0, 1, 0, 0, 0, -1, // 1380..
287 0, 1, 0, 1, 0, 0, 0, -1, 0, 0, // 1390..
288 0, 0, -1, -1, 0, -1, 0, 1, 0, 0, // 1400..
289 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, // 1410..
290 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, // 1420..
291 0, 0, -1, -1, 0, -1, 0, 0, -1, -1, // 1430..
292 0, -1, 0, -1, 0, 0, -1, -1, 0, 0, // 1440..
293 0, 0, 0, 0, -1, 0, 1, 0, 1, 1, // 1450..
294 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, // 1460..
295 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, // 1470..
296 0, -1, -1, 0, 0, 0, 1, 0, 0, 0, // 1480..
297 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // 1490..
298 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, // 1500..
299 0, -1, 0, 1, 0, 1, 1, 0, 0, 0, // 1510..
300 0, 1, 0, 0, 0, -1, 0, 0, 0, 1, // 1520..
301 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, // 1530..
302 0, -1, 0, 1, 0, 0, 0, -1, 0, 1, // 1540..
303 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, // 1550..
304 -1, 0, 0, 0, 0, 1, 0, 0, 0, -1, // 1560..
305 0, 0, 0, 0, -1, -1, 0, -1, 0, 1, // 1570..
306 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, // 1580..
307 -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 1590..
308 1 // 1600
309 };
310
311 /**
312 * Determine whether a year is a leap year in the Islamic civil calendar
313 */
civilLeapYear(int32_t year)314 UBool IslamicCalendar::civilLeapYear(int32_t year)
315 {
316 return (14 + 11 * year) % 30 < 11;
317 }
318
319 /**
320 * Return the day # on which the given year starts. Days are counted
321 * from the Hijri epoch, origin 0.
322 */
yearStart(int32_t year) const323 int32_t IslamicCalendar::yearStart(int32_t year) const{
324 return trueMonthStart(12*(year-1));
325 }
326
327 /**
328 * Return the day # on which the given month starts. Days are counted
329 * from the Hijri epoch, origin 0.
330 *
331 * @param year The hijri year
332 * @param month The hijri month, 0-based (assumed to be in range 0..11)
333 */
monthStart(int32_t year,int32_t month) const334 int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const {
335 return trueMonthStart(12*(year-1) + month);
336 }
337
338 /**
339 * Find the day number on which a particular month of the true/lunar
340 * Islamic calendar starts.
341 *
342 * @param month The month in question, origin 0 from the Hijri epoch
343 *
344 * @return The day number on which the given month starts.
345 */
trueMonthStart(int32_t month) const346 int32_t IslamicCalendar::trueMonthStart(int32_t month) const
347 {
348 UErrorCode status = U_ZERO_ERROR;
349 int32_t start = CalendarCache::get(&gMonthCache, month, status);
350
351 if (start==0) {
352 // Make a guess at when the month started, using the average length
353 UDate origin = HIJRA_MILLIS
354 + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH) * kOneDay;
355
356 // moonAge will fail due to memory allocation error
357 double age = moonAge(origin, status);
358 if (U_FAILURE(status)) {
359 goto trueMonthStartEnd;
360 }
361
362 if (age >= 0) {
363 // The month has already started
364 do {
365 origin -= kOneDay;
366 age = moonAge(origin, status);
367 if (U_FAILURE(status)) {
368 goto trueMonthStartEnd;
369 }
370 } while (age >= 0);
371 }
372 else {
373 // Preceding month has not ended yet.
374 do {
375 origin += kOneDay;
376 age = moonAge(origin, status);
377 if (U_FAILURE(status)) {
378 goto trueMonthStartEnd;
379 }
380 } while (age < 0);
381 }
382 start = (int32_t)(ClockMath::floorDivide(
383 (int64_t)((int64_t)origin - HIJRA_MILLIS), (int64_t)kOneDay) + 1);
384 CalendarCache::put(&gMonthCache, month, start, status);
385 }
386 trueMonthStartEnd :
387 if(U_FAILURE(status)) {
388 start = 0;
389 }
390 return start;
391 }
392
393 /**
394 * Return the "age" of the moon at the given time; this is the difference
395 * in ecliptic latitude between the moon and the sun. This method simply
396 * calls CalendarAstronomer.moonAge, converts to degrees,
397 * and adjusts the result to be in the range [-180, 180].
398 *
399 * @param time The time at which the moon's age is desired,
400 * in millis since 1/1/1970.
401 */
moonAge(UDate time,UErrorCode & status)402 double IslamicCalendar::moonAge(UDate time, UErrorCode &status)
403 {
404 double age = 0;
405
406 static UMutex astroLock; // pod bay door lock
407 umtx_lock(&astroLock);
408 if(gIslamicCalendarAstro == nullptr) {
409 gIslamicCalendarAstro = new CalendarAstronomer();
410 if (gIslamicCalendarAstro == nullptr) {
411 status = U_MEMORY_ALLOCATION_ERROR;
412 return age;
413 }
414 ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup);
415 }
416 gIslamicCalendarAstro->setTime(time);
417 age = gIslamicCalendarAstro->getMoonAge();
418 umtx_unlock(&astroLock);
419
420 // Convert to degrees and normalize...
421 age = age * 180 / CalendarAstronomer::PI;
422 if (age > 180) {
423 age = age - 360;
424 }
425
426 return age;
427 }
428
429 //----------------------------------------------------------------------
430 // Calendar framework
431 //----------------------------------------------------------------------
432
433 /**
434 * Return the length (in days) of the given month.
435 *
436 * @param year The hijri year
437 * @param year The hijri month, 0-based
438 * @draft ICU 2.4
439 */
handleGetMonthLength(int32_t extendedYear,int32_t month) const440 int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
441 month = 12*(extendedYear-1) + month;
442 return trueMonthStart(month+1) - trueMonthStart(month) ;
443 }
444
445 /**
446 * Return the number of days in the given Islamic year
447 * @draft ICU 2.4
448 */
handleGetYearLength(int32_t extendedYear) const449 int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
450 int32_t month = 12*(extendedYear-1);
451 return (trueMonthStart(month + 12) - trueMonthStart(month));
452 }
453
454 //-------------------------------------------------------------------------
455 // Functions for converting from field values to milliseconds....
456 //-------------------------------------------------------------------------
457
458 // Return JD of start of given month/year
459 // Calendar says:
460 // Get the Julian day of the day BEFORE the start of this year.
461 // If useMonth is true, get the day before the start of the month.
462 // Hence the -1
463 /**
464 * @draft ICU 2.4
465 */
handleComputeMonthStart(int32_t eyear,int32_t month,UBool) const466 int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /* useMonth */) const {
467 // This may be called by Calendar::handleComputeJulianDay with months out of the range
468 // 0..11. Need to handle that here since monthStart requires months in the range 0.11.
469 if (month > 11) {
470 eyear += (month / 12);
471 month %= 12;
472 } else if (month < 0) {
473 month++;
474 eyear += (month / 12) - 1;
475 month = (month % 12) + 11;
476 }
477 return monthStart(eyear, month) + getEpoc() - 1;
478 }
479
480 //-------------------------------------------------------------------------
481 // Functions for converting from milliseconds to field values
482 //-------------------------------------------------------------------------
483
484 /**
485 * @draft ICU 2.4
486 */
handleGetExtendedYear()487 int32_t IslamicCalendar::handleGetExtendedYear() {
488 int32_t year;
489 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
490 year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
491 } else {
492 year = internalGet(UCAL_YEAR, 1); // Default to year 1
493 }
494 return year;
495 }
496
497 /**
498 * Override Calendar to compute several fields specific to the Islamic
499 * calendar system. These are:
500 *
501 * <ul><li>ERA
502 * <li>YEAR
503 * <li>MONTH
504 * <li>DAY_OF_MONTH
505 * <li>DAY_OF_YEAR
506 * <li>EXTENDED_YEAR</ul>
507 *
508 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
509 * method is called. The getGregorianXxx() methods return Gregorian
510 * calendar equivalents for the given Julian day.
511 * @draft ICU 2.4
512 */
handleComputeFields(int32_t julianDay,UErrorCode & status)513 void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
514 if (U_FAILURE(status)) return;
515 int32_t days = julianDay - getEpoc();
516
517 // Guess at the number of elapsed full months since the epoch
518 int32_t month = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
519
520 int32_t startDate = (int32_t)uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH);
521
522 double age = moonAge(internalGetTime(), status);
523 if (U_FAILURE(status)) {
524 status = U_MEMORY_ALLOCATION_ERROR;
525 return;
526 }
527 if ( days - startDate >= 25 && age > 0) {
528 // If we're near the end of the month, assume next month and search backwards
529 month++;
530 }
531
532 // Find out the last time that the new moon was actually visible at this longitude
533 // This returns midnight the night that the moon was visible at sunset.
534 while ((startDate = trueMonthStart(month)) > days) {
535 // If it was after the date in question, back up a month and try again
536 month--;
537 }
538
539 int32_t year = month >= 0 ? ((month / 12) + 1) : ((month + 1 ) / 12);
540 month = ((month % 12) + 12 ) % 12;
541 int32_t dayOfMonth = (days - monthStart(year, month)) + 1;
542
543 // Now figure out the day of the year.
544 int32_t dayOfYear = (days - monthStart(year, 0)) + 1;
545
546 internalSet(UCAL_ERA, 0);
547 internalSet(UCAL_YEAR, year);
548 internalSet(UCAL_EXTENDED_YEAR, year);
549 internalSet(UCAL_MONTH, month);
550 internalSet(UCAL_ORDINAL_MONTH, month);
551 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
552 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
553 }
554
getEpoc() const555 int32_t IslamicCalendar::getEpoc() const {
556 return CIVIL_EPOC;
557 }
558
gregoYearFromIslamicStart(int32_t year)559 static int32_t gregoYearFromIslamicStart(int32_t year) {
560 // ad hoc conversion, improve under #10752
561 // rough est for now, ok for grego 1846-2138,
562 // otherwise occasionally wrong (for 3% of years)
563 int cycle, offset, shift = 0;
564 if (year >= 1397) {
565 cycle = (year - 1397) / 67;
566 offset = (year - 1397) % 67;
567 shift = 2*cycle + ((offset >= 33)? 1: 0);
568 } else {
569 cycle = (year - 1396) / 67 - 1;
570 offset = -(year - 1396) % 67;
571 shift = 2*cycle + ((offset <= 33)? 1: 0);
572 }
573 return year + 579 - shift;
574 }
575
getRelatedYear(UErrorCode & status) const576 int32_t IslamicCalendar::getRelatedYear(UErrorCode &status) const
577 {
578 int32_t year = get(UCAL_EXTENDED_YEAR, status);
579 if (U_FAILURE(status)) {
580 return 0;
581 }
582 return gregoYearFromIslamicStart(year);
583 }
584
firstIslamicStartYearFromGrego(int32_t year)585 static int32_t firstIslamicStartYearFromGrego(int32_t year) {
586 // ad hoc conversion, improve under #10752
587 // rough est for now, ok for grego 1846-2138,
588 // otherwise occasionally wrong (for 3% of years)
589 int cycle, offset, shift = 0;
590 if (year >= 1977) {
591 cycle = (year - 1977) / 65;
592 offset = (year - 1977) % 65;
593 shift = 2*cycle + ((offset >= 32)? 1: 0);
594 } else {
595 cycle = (year - 1976) / 65 - 1;
596 offset = -(year - 1976) % 65;
597 shift = 2*cycle + ((offset <= 32)? 1: 0);
598 }
599 return year - 579 + shift;
600 }
601
setRelatedYear(int32_t year)602 void IslamicCalendar::setRelatedYear(int32_t year)
603 {
604 set(UCAL_EXTENDED_YEAR, firstIslamicStartYearFromGrego(year));
605 }
606
607 /**
608 * The system maintains a static default century start date and Year. They are
609 * initialized the first time they are used. Once the system default century date
610 * and year are set, they do not change.
611 */
612 static UDate gSystemDefaultCenturyStart = DBL_MIN;
613 static int32_t gSystemDefaultCenturyStartYear = -1;
614 static icu::UInitOnce gSystemDefaultCenturyInit {};
615
616
haveDefaultCentury() const617 UBool IslamicCalendar::haveDefaultCentury() const
618 {
619 return true;
620 }
621
defaultCenturyStart() const622 UDate IslamicCalendar::defaultCenturyStart() const
623 {
624 // lazy-evaluate systemDefaultCenturyStart
625 umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
626 return gSystemDefaultCenturyStart;
627 }
628
defaultCenturyStartYear() const629 int32_t IslamicCalendar::defaultCenturyStartYear() const
630 {
631 // lazy-evaluate systemDefaultCenturyStartYear
632 umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
633 return gSystemDefaultCenturyStartYear;
634 }
635
636 bool
inTemporalLeapYear(UErrorCode & status) const637 IslamicCalendar::inTemporalLeapYear(UErrorCode &status) const
638 {
639 int32_t days = getActualMaximum(UCAL_DAY_OF_YEAR, status);
640 if (U_FAILURE(status)) return false;
641 return days == 355;
642 }
643
644
645 U_CFUNC void U_CALLCONV
initializeSystemDefaultCentury()646 IslamicCalendar::initializeSystemDefaultCentury()
647 {
648 // initialize systemDefaultCentury and systemDefaultCenturyYear based
649 // on the current time. They'll be set to 80 years before
650 // the current time.
651 UErrorCode status = U_ZERO_ERROR;
652 IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status);
653 if (U_SUCCESS(status)) {
654 calendar.setTime(Calendar::getNow(), status);
655 calendar.add(UCAL_YEAR, -80, status);
656
657 gSystemDefaultCenturyStart = calendar.getTime(status);
658 gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
659 }
660 // We have no recourse upon failure unless we want to propagate the failure
661 // out.
662 }
663
664 /*****************************************************************************
665 * IslamicCivilCalendar
666 *****************************************************************************/
IslamicCivilCalendar(const Locale & aLocale,UErrorCode & success)667 IslamicCivilCalendar::IslamicCivilCalendar(const Locale& aLocale, UErrorCode& success)
668 : IslamicCalendar(aLocale, success)
669 {
670 }
671
~IslamicCivilCalendar()672 IslamicCivilCalendar::~IslamicCivilCalendar()
673 {
674 }
675
getType() const676 const char *IslamicCivilCalendar::getType() const {
677 return "islamic-civil";
678 }
679
clone() const680 IslamicCivilCalendar* IslamicCivilCalendar::clone() const {
681 return new IslamicCivilCalendar(*this);
682 }
683
684 /**
685 * Return the day # on which the given year starts. Days are counted
686 * from the Hijri epoch, origin 0.
687 */
yearStart(int32_t year) const688 int32_t IslamicCivilCalendar::yearStart(int32_t year) const{
689 return static_cast<int32_t>(
690 (year-1)*354 + ClockMath::floorDivide((3+11*static_cast<int64_t>(year)),
691 static_cast<int64_t>(30)));
692 }
693
694 /**
695 * Return the day # on which the given month starts. Days are counted
696 * from the Hijri epoch, origin 0.
697 *
698 * @param year The hijri year
699 * @param month The hijri month, 0-based (assumed to be in range 0..11)
700 */
monthStart(int32_t year,int32_t month) const701 int32_t IslamicCivilCalendar::monthStart(int32_t year, int32_t month) const {
702 // This does not handle months out of the range 0..11
703 return static_cast<int32_t>(
704 uprv_ceil(29.5*month) + (year-1)*354 +
705 static_cast<int32_t>(ClockMath::floorDivide(
706 3+11*static_cast<int64_t>(year),
707 static_cast<int64_t>(30))));
708 }
709
710 /**
711 * Return the length (in days) of the given month.
712 *
713 * @param year The hijri year
714 * @param year The hijri month, 0-based
715 * @draft ICU 2.4
716 */
handleGetMonthLength(int32_t extendedYear,int32_t month) const717 int32_t IslamicCivilCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
718 int32_t length = 29 + (month+1) % 2;
719 if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
720 length++;
721 }
722 return length;
723 }
724
725 /**
726 * Return the number of days in the given Islamic year
727 * @draft ICU 2.4
728 */
handleGetYearLength(int32_t extendedYear) const729 int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear) const {
730 return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
731 }
732
733 /**
734 * Override Calendar to compute several fields specific to the Islamic
735 * calendar system. These are:
736 *
737 * <ul><li>ERA
738 * <li>YEAR
739 * <li>MONTH
740 * <li>DAY_OF_MONTH
741 * <li>DAY_OF_YEAR
742 * <li>EXTENDED_YEAR</ul>
743 *
744 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
745 * method is called. The getGregorianXxx() methods return Gregorian
746 * calendar equivalents for the given Julian day.
747 * @draft ICU 2.4
748 */
handleComputeFields(int32_t julianDay,UErrorCode & status)749 void IslamicCivilCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
750 if (U_FAILURE(status)) return;
751 int32_t days = julianDay - getEpoc();
752
753 // Use the civil calendar approximation, which is just arithmetic
754 int32_t year = static_cast<int32_t>(
755 ClockMath::floorDivide(30 * static_cast<int64_t>(days) + 10646,
756 static_cast<int64_t>(10631)));
757 int32_t month = static_cast<int32_t>(
758 uprv_ceil((days - 29 - yearStart(year)) / 29.5 ));
759 month = month<11?month:11;
760
761 int32_t dayOfMonth = (days - monthStart(year, month)) + 1;
762
763 // Now figure out the day of the year.
764 int32_t dayOfYear = (days - monthStart(year, 0)) + 1;
765
766 internalSet(UCAL_ERA, 0);
767 internalSet(UCAL_YEAR, year);
768 internalSet(UCAL_EXTENDED_YEAR, year);
769 internalSet(UCAL_MONTH, month);
770 internalSet(UCAL_ORDINAL_MONTH, month);
771 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
772 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
773 }
774 /*****************************************************************************
775 * IslamicTBLACalendar
776 *****************************************************************************/
IslamicTBLACalendar(const Locale & aLocale,UErrorCode & success)777 IslamicTBLACalendar::IslamicTBLACalendar(const Locale& aLocale, UErrorCode& success)
778 : IslamicCivilCalendar(aLocale, success)
779 {
780 }
781
~IslamicTBLACalendar()782 IslamicTBLACalendar::~IslamicTBLACalendar()
783 {
784 }
785
getType() const786 const char *IslamicTBLACalendar::getType() const {
787 return "islamic-tbla";
788 }
789
clone() const790 IslamicTBLACalendar* IslamicTBLACalendar::clone() const {
791 return new IslamicTBLACalendar(*this);
792 }
793
getEpoc() const794 int32_t IslamicTBLACalendar::getEpoc() const {
795 return ASTRONOMICAL_EPOC;
796 }
797
798 /*****************************************************************************
799 * IslamicUmalquraCalendar
800 *****************************************************************************/
IslamicUmalquraCalendar(const Locale & aLocale,UErrorCode & success)801 IslamicUmalquraCalendar::IslamicUmalquraCalendar(const Locale& aLocale, UErrorCode& success)
802 : IslamicCalendar(aLocale, success)
803 {
804 }
805
~IslamicUmalquraCalendar()806 IslamicUmalquraCalendar::~IslamicUmalquraCalendar()
807 {
808 }
809
getType() const810 const char *IslamicUmalquraCalendar::getType() const {
811 return "islamic-umalqura";
812 }
813
clone() const814 IslamicUmalquraCalendar* IslamicUmalquraCalendar::clone() const {
815 return new IslamicUmalquraCalendar(*this);
816 }
817
818 /**
819 * Return the day # on which the given year starts. Days are counted
820 * from the Hijri epoch, origin 0.
821 */
yearStart(int32_t year) const822 int32_t IslamicUmalquraCalendar::yearStart(int32_t year) const {
823 if (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END) {
824 return static_cast<int32_t>(
825 (year-1)*354 + ClockMath::floorDivide((3+11*static_cast<int64_t>(year)),
826 static_cast<int64_t>(30)));
827 }
828 year -= UMALQURA_YEAR_START;
829 // rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
830 int32_t yrStartLinearEstimate = static_cast<int32_t>(
831 (354.36720 * (double)year) + 460322.05 + 0.5);
832 // need a slight correction to some
833 return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
834 }
835
836 /**
837 * Return the day # on which the given month starts. Days are counted
838 * from the Hijri epoch, origin 0.
839 *
840 * @param year The hijri year
841 * @param month The hijri month, 0-based (assumed to be in range 0..11)
842 */
monthStart(int32_t year,int32_t month) const843 int32_t IslamicUmalquraCalendar::monthStart(int32_t year, int32_t month) const {
844 int32_t ms = yearStart(year);
845 for(int i=0; i< month; i++){
846 ms+= handleGetMonthLength(year, i);
847 }
848 return ms;
849 }
850
851 /**
852 * Return the length (in days) of the given month.
853 *
854 * @param year The hijri year
855 * @param year The hijri month, 0-based
856 */
handleGetMonthLength(int32_t extendedYear,int32_t month) const857 int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
858 int32_t length = 0;
859 if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
860 length = 29 + (month+1) % 2;
861 if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
862 length++;
863 }
864 return length;
865 }
866 return getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month);
867 }
868
869 /**
870 * Return the number of days in the given Islamic year
871 * @draft ICU 2.4
872 */
handleGetYearLength(int32_t extendedYear) const873 int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear) const {
874 if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
875 return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
876 }
877 int len = 0;
878 for(int i=0; i<12; i++) {
879 len += handleGetMonthLength(extendedYear, i);
880 }
881 return len;
882 }
883
884 /**
885 * Override Calendar to compute several fields specific to the Islamic
886 * calendar system. These are:
887 *
888 * <ul><li>ERA
889 * <li>YEAR
890 * <li>MONTH
891 * <li>DAY_OF_MONTH
892 * <li>DAY_OF_YEAR
893 * <li>EXTENDED_YEAR</ul>
894 *
895 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
896 * method is called. The getGregorianXxx() methods return Gregorian
897 * calendar equivalents for the given Julian day.
898 * @draft ICU 2.4
899 */
handleComputeFields(int32_t julianDay,UErrorCode & status)900 void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
901 if (U_FAILURE(status)) return;
902 int32_t year, month, dayOfMonth, dayOfYear;
903 int32_t days = julianDay - getEpoc();
904
905 int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
906 if (days < umalquraStartdays) {
907 //Use Civil calculation
908 year = (int32_t)ClockMath::floorDivide(
909 (30 * (int64_t)days + 10646) , (int64_t)10631.0 );
910 month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
911 month = month < 11 ? month : 11;
912 } else {
913 int y =UMALQURA_YEAR_START-1, m =0;
914 long d = 1;
915 while (d > 0) {
916 y++;
917 d = days - yearStart(y) +1;
918 if (d == handleGetYearLength(y)) {
919 m=11;
920 break;
921 }
922 if (d < handleGetYearLength(y)){
923 int monthLen = handleGetMonthLength(y, m);
924 m=0;
925 while(d > monthLen){
926 d -= monthLen;
927 m++;
928 monthLen = handleGetMonthLength(y, m);
929 }
930 break;
931 }
932 }
933 year = y;
934 month = m;
935 }
936
937 dayOfMonth = (days - monthStart(year, month)) + 1;
938
939 // Now figure out the day of the year.
940 dayOfYear = (days - monthStart(year, 0)) + 1;
941
942 internalSet(UCAL_ERA, 0);
943 internalSet(UCAL_YEAR, year);
944 internalSet(UCAL_EXTENDED_YEAR, year);
945 internalSet(UCAL_MONTH, month);
946 internalSet(UCAL_ORDINAL_MONTH, month);
947 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
948 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
949 }
950 /*****************************************************************************
951 * IslamicRGSACalendar
952 *****************************************************************************/
IslamicRGSACalendar(const Locale & aLocale,UErrorCode & success)953 IslamicRGSACalendar::IslamicRGSACalendar(const Locale& aLocale, UErrorCode& success)
954 : IslamicCalendar(aLocale, success)
955 {
956 }
957
~IslamicRGSACalendar()958 IslamicRGSACalendar::~IslamicRGSACalendar()
959 {
960 }
961
getType() const962 const char *IslamicRGSACalendar::getType() const {
963 return "islamic-rgsa";
964 }
965
clone() const966 IslamicRGSACalendar* IslamicRGSACalendar::clone() const {
967 return new IslamicRGSACalendar(*this);
968 }
969
970 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)
971 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCivilCalendar)
972 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicUmalquraCalendar)
973 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicTBLACalendar)
974 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicRGSACalendar)
975
976 U_NAMESPACE_END
977
978 #endif
979
980