Home | History | Annotate | Download | only in i18n
      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 static UBool calendar_islamic_cleanup(void) {
     63     if (gMonthCache) {
     64         delete gMonthCache;
     65         gMonthCache = NULL;
     66     }
     67     if (gIslamicCalendarAstro) {
     68         delete gIslamicCalendarAstro;
     69         gIslamicCalendarAstro = NULL;
     70     }
     71     return TRUE;
     72 }
     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 int32_t getUmalqura_MonthLength(int32_t y, int32_t m) {
    197     int32_t mask = (int32_t) (0x01 << (11 - m));    // set mask for bit corresponding to month
    198     if((UMALQURA_MONTHLENGTH[y] & mask) == 0 )
    199         return 29;
    200     else
    201         return 30;
    202 
    203 }
    204 
    205 //-------------------------------------------------------------------------
    206 // Constructors...
    207 //-------------------------------------------------------------------------
    208 
    209 const char *IslamicCalendar::getType() const {
    210     const char *sType = NULL;
    211 
    212     switch (cType) {
    213     case CIVIL:
    214         sType = "islamic-civil";
    215         break;
    216     case ASTRONOMICAL:
    217         sType = "islamic";
    218         break;
    219     case TBLA:
    220         sType = "islamic-tbla";
    221         break;
    222     case UMALQURA:
    223         sType = "islamic-umalqura";
    224         break;
    225     default:
    226         U_ASSERT(false); // out of range
    227         sType = "islamic";  // "islamic" is used as the generic type
    228         break;
    229     }
    230     return sType;
    231 }
    232 
    233 Calendar* IslamicCalendar::clone() const {
    234     return new IslamicCalendar(*this);
    235 }
    236 
    237 IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECalculationType type)
    238 :   Calendar(TimeZone::createDefault(), aLocale, success),
    239 cType(type)
    240 {
    241     setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
    242 }
    243 
    244 IslamicCalendar::IslamicCalendar(const IslamicCalendar& other) : Calendar(other), cType(other.cType) {
    245 }
    246 
    247 IslamicCalendar::~IslamicCalendar()
    248 {
    249 }
    250 
    251 void IslamicCalendar::setCalculationType(ECalculationType type, UErrorCode &status)
    252 {
    253     if (cType != type) {
    254         // The fields of the calendar will become invalid, because the calendar
    255         // rules are different
    256         UDate m = getTimeInMillis(status);
    257         cType = type;
    258         clear();
    259         setTimeInMillis(m, status);
    260     }
    261 }
    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 UBool IslamicCalendar::isCivil() {
    270     return (cType == CIVIL);
    271 }
    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 int32_t IslamicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
    316     return LIMITS[field][limitType];
    317 }
    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 {
    363     return (14 + 11 * year) % 30 < 11;
    364 }
    365 
    366 /**
    367 * Return the day # on which the given year starts.  Days are counted
    368 * from the Hijri epoch, origin 0.
    369 */
    370 int32_t IslamicCalendar::yearStart(int32_t year) const{
    371     if (cType == CIVIL || cType == TBLA ||
    372         (cType == UMALQURA && (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END)))
    373     {
    374         return (year-1)*354 + ClockMath::floorDivide((3+11*year),30);
    375     } else if(cType==ASTRONOMICAL){
    376         return trueMonthStart(12*(year-1));
    377     } else {
    378         year -= UMALQURA_YEAR_START;
    379         // rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
    380         int32_t yrStartLinearEstimate = (int32_t)((354.36720 * (double)year) + 460322.05 + 0.5);
    381         // need a slight correction to some
    382         return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
    383     }
    384 }
    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 int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const {
    394     if (cType == CIVIL || cType == TBLA) {
    395         // This does not handle months out of the range 0..11
    396         return (int32_t)uprv_ceil(29.5*month)
    397             + (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*year),30);
    398     } else if(cType==ASTRONOMICAL){
    399         return trueMonthStart(12*(year-1) + month);
    400     } else {
    401         int32_t ms = yearStart(year);
    402         for(int i=0; i< month; i++){
    403             ms+= handleGetMonthLength(year, i);
    404         }
    405         return ms;
    406     }
    407 }
    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 {
    419     UErrorCode status = U_ZERO_ERROR;
    420     int32_t start = CalendarCache::get(&gMonthCache, month, status);
    421 
    422     if (start==0) {
    423         // Make a guess at when the month started, using the average length
    424         UDate origin = HIJRA_MILLIS
    425             + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH) * kOneDay;
    426 
    427         // moonAge will fail due to memory allocation error
    428         double age = moonAge(origin, status);
    429         if (U_FAILURE(status)) {
    430             goto trueMonthStartEnd;
    431         }
    432 
    433         if (age >= 0) {
    434             // The month has already started
    435             do {
    436                 origin -= kOneDay;
    437                 age = moonAge(origin, status);
    438                 if (U_FAILURE(status)) {
    439                     goto trueMonthStartEnd;
    440                 }
    441             } while (age >= 0);
    442         }
    443         else {
    444             // Preceding month has not ended yet.
    445             do {
    446                 origin += kOneDay;
    447                 age = moonAge(origin, status);
    448                 if (U_FAILURE(status)) {
    449                     goto trueMonthStartEnd;
    450                 }
    451             } while (age < 0);
    452         }
    453         start = (int32_t)ClockMath::floorDivide((origin - HIJRA_MILLIS), (double)kOneDay) + 1;
    454         CalendarCache::put(&gMonthCache, month, start, status);
    455     }
    456 trueMonthStartEnd :
    457     if(U_FAILURE(status)) {
    458         start = 0;
    459     }
    460     return start;
    461 }
    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 {
    474     double age = 0;
    475 
    476     umtx_lock(&astroLock);
    477     if(gIslamicCalendarAstro == NULL) {
    478         gIslamicCalendarAstro = new CalendarAstronomer();
    479         if (gIslamicCalendarAstro == NULL) {
    480             status = U_MEMORY_ALLOCATION_ERROR;
    481             return age;
    482         }
    483         ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup);
    484     }
    485     gIslamicCalendarAstro->setTime(time);
    486     age = gIslamicCalendarAstro->getMoonAge();
    487     umtx_unlock(&astroLock);
    488 
    489     // Convert to degrees and normalize...
    490     age = age * 180 / CalendarAstronomer::PI;
    491     if (age > 180) {
    492         age = age - 360;
    493     }
    494 
    495     return age;
    496 }
    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 int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
    510 
    511     int32_t length = 0;
    512 
    513     if (cType == CIVIL || cType == TBLA ||
    514         (cType == UMALQURA && (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END)) ) {
    515         length = 29 + (month+1) % 2;
    516         if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
    517             length++;
    518         }
    519     } else if(cType == ASTRONOMICAL){
    520         month = 12*(extendedYear-1) + month;
    521         length =  trueMonthStart(month+1) - trueMonthStart(month) ;
    522     } else {
    523         length = getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month);
    524     }
    525     return length;
    526 }
    527 
    528 /**
    529 * Return the number of days in the given Islamic year
    530 * @draft ICU 2.4
    531 */
    532 int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
    533     if (cType == CIVIL || cType == TBLA ||
    534         (cType == UMALQURA && (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END)) ) {
    535         return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
    536     } else if(cType == ASTRONOMICAL){
    537         int32_t month = 12*(extendedYear-1);
    538         return (trueMonthStart(month + 12) - trueMonthStart(month));
    539     } else {
    540         int len = 0;
    541         for(int i=0; i<12; i++) {
    542             len += handleGetMonthLength(extendedYear, i);
    543         }
    544         return len;
    545     }
    546 }
    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 int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /* useMonth */) const {
    561     // This may be called by Calendar::handleComputeJulianDay with months out of the range
    562     // 0..11. Need to handle that here since monthStart requires months in the range 0.11.
    563     if (month > 11) {
    564         eyear += (month / 12);
    565         month %= 12;
    566     } else if (month < 0) {
    567         month++;
    568         eyear += (month / 12) - 1;
    569         month = (month % 12) + 11;
    570     }
    571     return monthStart(eyear, month) + ((cType == TBLA)? ASTRONOMICAL_EPOC: CIVIL_EPOC) - 1;
    572 }
    573 
    574 //-------------------------------------------------------------------------
    575 // Functions for converting from milliseconds to field values
    576 //-------------------------------------------------------------------------
    577 
    578 /**
    579 * @draft ICU 2.4
    580 */
    581 int32_t IslamicCalendar::handleGetExtendedYear() {
    582     int32_t year;
    583     if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
    584         year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
    585     } else {
    586         year = internalGet(UCAL_YEAR, 1); // Default to year 1
    587     }
    588     return year;
    589 }
    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 void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
    608     int32_t year, month, dayOfMonth, dayOfYear;
    609     int32_t startDate;
    610     int32_t days = julianDay - CIVIL_EPOC;
    611 
    612     if (cType == CIVIL || cType == TBLA) {
    613         if(cType == TBLA) {
    614             days = julianDay - ASTRONOMICAL_EPOC;
    615         }
    616         // Use the civil calendar approximation, which is just arithmetic
    617         year  = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 );
    618         month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
    619         month = month<11?month:11;
    620         startDate = monthStart(year, month);
    621     } else if(cType == ASTRONOMICAL){
    622         // Guess at the number of elapsed full months since the epoch
    623         int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
    624 
    625         startDate = (int32_t)uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH);
    626 
    627         double age = moonAge(internalGetTime(), status);
    628         if (U_FAILURE(status)) {
    629             status = U_MEMORY_ALLOCATION_ERROR;
    630             return;
    631         }
    632         if ( days - startDate >= 25 && age > 0) {
    633             // If we're near the end of the month, assume next month and search backwards
    634             months++;
    635         }
    636 
    637         // Find out the last time that the new moon was actually visible at this longitude
    638         // This returns midnight the night that the moon was visible at sunset.
    639         while ((startDate = trueMonthStart(months)) > days) {
    640             // If it was after the date in question, back up a month and try again
    641             months--;
    642         }
    643 
    644         year = months / 12 + 1;
    645         month = months % 12;
    646     } else if(cType == UMALQURA) {
    647         int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
    648         if( days < umalquraStartdays){
    649                 //Use Civil calculation
    650                 year  = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 );
    651                 month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
    652                 month = month<11?month:11;
    653                 startDate = monthStart(year, month);
    654             }else{
    655                 int y =UMALQURA_YEAR_START-1, m =0;
    656                 long d = 1;
    657                 while(d > 0){
    658                     y++;
    659                     d = days - yearStart(y) +1;
    660                     if(d == handleGetYearLength(y)){
    661                         m=11;
    662                         break;
    663                     }else if(d < handleGetYearLength(y) ){
    664                         int monthLen = handleGetMonthLength(y, m);
    665                         m=0;
    666                         while(d > monthLen){
    667                             d -= monthLen;
    668                             m++;
    669                             monthLen = handleGetMonthLength(y, m);
    670                         }
    671                         break;
    672                     }
    673                 }
    674                 year = y;
    675                 month = m;
    676             }
    677     } else { // invalid 'civil'
    678       U_ASSERT(false); // should not get here, out of range
    679       year=month=0;
    680     }
    681 
    682     dayOfMonth = (days - monthStart(year, month)) + 1;
    683 
    684     // Now figure out the day of the year.
    685     dayOfYear = (days - monthStart(year, 0)) + 1;
    686 
    687 
    688     internalSet(UCAL_ERA, 0);
    689     internalSet(UCAL_YEAR, year);
    690     internalSet(UCAL_EXTENDED_YEAR, year);
    691     internalSet(UCAL_MONTH, month);
    692     internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
    693     internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
    694 }
    695 
    696 UBool
    697 IslamicCalendar::inDaylightTime(UErrorCode& status) const
    698 {
    699     // copied from GregorianCalendar
    700     if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
    701         return FALSE;
    702 
    703     // Force an update of the state of the Calendar.
    704     ((IslamicCalendar*)this)->complete(status); // cast away const
    705 
    706     return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
    707 }
    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 {
    721     return TRUE;
    722 }
    723 
    724 UDate IslamicCalendar::defaultCenturyStart() const
    725 {
    726     // lazy-evaluate systemDefaultCenturyStart
    727     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
    728     return gSystemDefaultCenturyStart;
    729 }
    730 
    731 int32_t IslamicCalendar::defaultCenturyStartYear() const
    732 {
    733     // lazy-evaluate systemDefaultCenturyStartYear
    734     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
    735     return gSystemDefaultCenturyStartYear;
    736 }
    737 
    738 
    739 U_CFUNC void U_CALLCONV
    740 IslamicCalendar::initializeSystemDefaultCentury()
    741 {
    742     // initialize systemDefaultCentury and systemDefaultCenturyYear based
    743     // on the current time.  They'll be set to 80 years before
    744     // the current time.
    745     UErrorCode status = U_ZERO_ERROR;
    746     IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status);
    747     if (U_SUCCESS(status)) {
    748         calendar.setTime(Calendar::getNow(), status);
    749         calendar.add(UCAL_YEAR, -80, status);
    750 
    751         gSystemDefaultCenturyStart = calendar.getTime(status);
    752         gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
    753     }
    754     // We have no recourse upon failure unless we want to propagate the failure
    755     // out.
    756 }
    757 
    758 
    759 
    760 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)
    761 
    762 U_NAMESPACE_END
    763 
    764 #endif
    765 
    766