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