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