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