• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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