Coverage Report

Created: 2018-09-25 14:53

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