1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5 *******************************************************************************
6 * Copyright (C) 1996-2016, International Business Machines Corporation and    *
7 * others. All Rights Reserved.                                                *
8 *******************************************************************************
9 */
10package android.icu.util;
11import java.io.IOException;
12import java.io.ObjectInputStream;
13import java.util.Date;
14import java.util.Locale;
15
16import android.icu.impl.CalendarAstronomer;
17import android.icu.impl.CalendarCache;
18import android.icu.impl.CalendarUtil;
19import android.icu.util.ULocale.Category;
20
21/**
22 * <code>IslamicCalendar</code> is a subclass of <code>Calendar</code>
23 * that that implements the Islamic civil and religious calendars.  It
24 * is used as the civil calendar in most of the Arab world and the
25 * liturgical calendar of the Islamic faith worldwide.  This calendar
26 * is also known as the "Hijri" calendar, since it starts at the time
27 * of Mohammed's emigration (or "hijra") to Medinah on Thursday,
28 * July 15, 622 AD (Julian).
29 * <p>
30 * The Islamic calendar is strictly lunar, and thus an Islamic year of twelve
31 * lunar months does not correspond to the solar year used by most other
32 * calendar systems, including the Gregorian.  An Islamic year is, on average,
33 * about 354 days long, so each successive Islamic year starts about 11 days
34 * earlier in the corresponding Gregorian year.
35 * <p>
36 * Each month of the calendar starts when the new moon's crescent is visible
37 * at sunset.  However, in order to keep the time fields in this class
38 * synchronized with those of the other calendars and with local clock time,
39 * we treat days and months as beginning at midnight,
40 * roughly 6 hours after the corresponding sunset.
41 * <p>
42 * There are three main variants of the Islamic calendar in existence.  The first
43 * is the <em>civil</em> calendar, which uses a fixed cycle of alternating 29-
44 * and 30-day months, with a leap day added to the last month of 11 out of
45 * every 30 years.  This calendar is easily calculated and thus predictable in
46 * advance, so it is used as the civil calendar in a number of Arab countries.
47 * This is the default behavior of a newly-created <code>IslamicCalendar</code>
48 * object.
49 * <p>
50 * The Islamic <em>religious</em> calendar and Saudi Arabia's <em>Umm al-Qura</em>
51 * calendar, however, are based on the <em>observation</em> of the crescent moon.
52 * It is thus affected by the position at which the
53 * observations are made, seasonal variations in the time of sunset, the
54 * eccentricities of the moon's orbit, and even the weather at the observation
55 * site.  This makes it impossible to calculate in advance, and it causes the
56 * start of a month in the religious calendar to differ from the civil calendar
57 * by up to three days.
58 * <p>
59 * Using astronomical calculations for the position of the sun and moon, the
60 * moon's illumination, and other factors, it is possible to determine the start
61 * of a lunar month with a fairly high degree of certainty.  However, these
62 * calculations are extremely complicated and thus slow, so most algorithms,
63 * including the one used here, are only approximations of the true astronomical
64 * calculations.  At present, the approximations used in this class are fairly
65 * simplistic; they will be improved in later versions of the code.
66 * <p>
67 * Like the Islamic religious calendar, <em>Umm al-Qura</em> is also based
68 * on the sighting method of the crescent moon but is standardized by Saudi Arabia.
69 * <p>
70 * The fixed-cycle <em>civil</em> calendar is used.
71 * <p>
72 * This class should not be subclassed.</p>
73 * <p>
74 * IslamicCalendar usually should be instantiated using
75 * {@link android.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
76 * with the tag <code>"@calendar=islamic"</code> or <code>"@calendar=islamic-civil"</code>
77 * or <code>"@calendar=islamic-umalqura"</code>.</p>
78 *
79 * @see android.icu.util.GregorianCalendar
80 * @see android.icu.util.Calendar
81 *
82 * @author Laura Werner
83 * @author Alan Liu
84 */
85public class IslamicCalendar extends Calendar {
86    // jdk1.4.2 serialver
87    private static final long serialVersionUID = -6253365474073869325L;
88
89    //-------------------------------------------------------------------------
90    // Constants...
91    //-------------------------------------------------------------------------
92
93    /**
94     * Constant for Muharram, the 1st month of the Islamic year.
95     */
96    public static final int MUHARRAM = 0;
97
98    /**
99     * Constant for Safar, the 2nd month of the Islamic year.
100     */
101    public static final int SAFAR = 1;
102
103    /**
104     * Constant for Rabi' al-awwal (or Rabi' I), the 3rd month of the Islamic year.
105     */
106    public static final int RABI_1 = 2;
107
108    /**
109     * Constant for Rabi' al-thani or (Rabi' II), the 4th month of the Islamic year.
110     */
111    public static final int RABI_2 = 3;
112
113    /**
114     * Constant for Jumada al-awwal or (Jumada I), the 5th month of the Islamic year.
115     */
116    public static final int JUMADA_1 = 4;
117
118    /**
119     * Constant for Jumada al-thani or (Jumada II), the 6th month of the Islamic year.
120     */
121    public static final int JUMADA_2 = 5;
122
123    /**
124     * Constant for Rajab, the 7th month of the Islamic year.
125     */
126    public static final int RAJAB = 6;
127
128    /**
129     * Constant for Sha'ban, the 8th month of the Islamic year.
130     */
131    public static final int SHABAN = 7;
132
133    /**
134     * Constant for Ramadan, the 9th month of the Islamic year.
135     */
136    public static final int RAMADAN = 8;
137
138    /**
139     * Constant for Shawwal, the 10th month of the Islamic year.
140     */
141    public static final int SHAWWAL = 9;
142
143    /**
144     * Constant for Dhu al-Qi'dah, the 11th month of the Islamic year.
145     */
146    public static final int DHU_AL_QIDAH = 10;
147
148    /**
149     * Constant for Dhu al-Hijjah, the 12th month of the Islamic year.
150     */
151    public static final int DHU_AL_HIJJAH = 11;
152
153
154    private static final long HIJRA_MILLIS = -42521587200000L;    // 7/16/622 AD 00:00
155
156    /**
157     * Friday EPOC
158     */
159    private static final long CIVIL_EPOC = 1948440; // CE 622 July 16 Friday (Julian calendar) / CE 622 July 19 (Gregorian calendar)
160    /**
161     * Thursday EPOC
162     */
163    private static final long ASTRONOMICAL_EPOC = 1948439; // CE 622 July 15 Thursday (Julian calendar)
164
165    //-------------------------------------------------------------------------
166    // Constructors...
167    //-------------------------------------------------------------------------
168
169    /**
170     * Constructs a default <code>IslamicCalendar</code> using the current time
171     * in the default time zone with the default <code>FORMAT</code> locale.
172     * @see Category#FORMAT
173     */
174    public IslamicCalendar()
175    {
176        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
177    }
178
179    /**
180     * Constructs an <code>IslamicCalendar</code> based on the current time
181     * in the given time zone with the default <code>FORMAT</code> locale.
182     * @param zone the given time zone.
183     * @see Category#FORMAT
184     */
185    public IslamicCalendar(TimeZone zone)
186    {
187        this(zone, ULocale.getDefault(Category.FORMAT));
188    }
189
190    /**
191     * Constructs an <code>IslamicCalendar</code> based on the current time
192     * in the default time zone with the given locale.
193     *
194     * @param aLocale the given locale.
195     */
196    public IslamicCalendar(Locale aLocale)
197    {
198        this(TimeZone.getDefault(), aLocale);
199    }
200
201    /**
202     * Constructs an <code>IslamicCalendar</code> based on the current time
203     * in the default time zone with the given locale.
204     *
205     * @param locale the given ulocale.
206     */
207    public IslamicCalendar(ULocale locale)
208    {
209        this(TimeZone.getDefault(), locale);
210    }
211
212    /**
213     * Constructs an <code>IslamicCalendar</code> based on the current time
214     * in the given time zone with the given locale.
215     *
216     * @param zone the given time zone.
217     * @param aLocale the given locale.
218     */
219    public IslamicCalendar(TimeZone zone, Locale aLocale)
220    {
221        this(zone, ULocale.forLocale(aLocale));
222    }
223
224    /**
225     * Constructs an <code>IslamicCalendar</code> based on the current time
226     * in the given time zone with the given locale.
227     *
228     * @param zone the given time zone.
229     * @param locale the given ulocale.
230     */
231    public IslamicCalendar(TimeZone zone, ULocale locale)
232    {
233        super(zone, locale);
234        setCalcTypeForLocale(locale);
235        setTimeInMillis(System.currentTimeMillis());
236    }
237
238    /**
239     * Constructs an <code>IslamicCalendar</code> with the given date set
240     * in the default time zone with the default <code>FORMAT</code> locale.
241     *
242     * @param date      The date to which the new calendar is set.
243     * @see Category#FORMAT
244     */
245    public IslamicCalendar(Date date) {
246        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
247        this.setTime(date);
248    }
249
250    /**
251     * Constructs an <code>IslamicCalendar</code> with the given date set
252     * in the default time zone with the default <code>FORMAT</code> locale.
253     *
254     * @param year the value used to set the {@link #YEAR YEAR} time field in the calendar.
255     * @param month the value used to set the {@link #MONTH MONTH} time field in the calendar.
256     *              Note that the month value is 0-based. e.g., 0 for Muharram.
257     * @param date the value used to set the {@link #DATE DATE} time field in the calendar.
258     * @see Category#FORMAT
259     */
260    public IslamicCalendar(int year, int month, int date)
261    {
262        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
263        this.set(Calendar.YEAR, year);
264        this.set(Calendar.MONTH, month);
265        this.set(Calendar.DATE, date);
266    }
267
268    /**
269     * Constructs an <code>IslamicCalendar</code> with the given date
270     * and time set for the default time zone with the default <code>FORMAT</code> locale.
271     *
272     * @param year  the value used to set the {@link #YEAR YEAR} time field in the calendar.
273     * @param month the value used to set the {@link #MONTH MONTH} time field in the calendar.
274     *              Note that the month value is 0-based. e.g., 0 for Muharram.
275     * @param date  the value used to set the {@link #DATE DATE} time field in the calendar.
276     * @param hour  the value used to set the {@link #HOUR_OF_DAY HOUR_OF_DAY} time field
277     *              in the calendar.
278     * @param minute the value used to set the {@link #MINUTE MINUTE} time field
279     *              in the calendar.
280     * @param second the value used to set the {@link #SECOND SECOND} time field
281     *              in the calendar.
282     * @see Category#FORMAT
283     */
284    public IslamicCalendar(int year, int month, int date, int hour,
285                             int minute, int second)
286    {
287        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
288        this.set(Calendar.YEAR, year);
289        this.set(Calendar.MONTH, month);
290        this.set(Calendar.DATE, date);
291        this.set(Calendar.HOUR_OF_DAY, hour);
292        this.set(Calendar.MINUTE, minute);
293        this.set(Calendar.SECOND, second);
294    }
295
296    /**
297     * Determines whether this object uses the fixed-cycle Islamic civil calendar
298     * or an approximation of the religious, astronomical calendar.
299     *
300     * @param beCivil   <code>true</code> to use the civil calendar,
301     *                  <code>false</code> to use the astronomical calendar.
302     * @apiNote <strong>Discouraged:</strong> ICU 57 use setCalculationType(CalculationType) instead
303     * @hide unsupported on Android
304     */
305    public void setCivil(boolean beCivil)
306    {
307        civil = beCivil;
308
309        if (beCivil && cType != CalculationType.ISLAMIC_CIVIL) {
310            // The fields of the calendar will become invalid, because the calendar
311            // rules are different
312            long m = getTimeInMillis();
313            cType = CalculationType.ISLAMIC_CIVIL;
314            clear();
315            setTimeInMillis(m);
316        } else if(!beCivil && cType != CalculationType.ISLAMIC) {
317            // The fields of the calendar will become invalid, because the calendar
318            // rules are different
319            long m = getTimeInMillis();
320            cType = CalculationType.ISLAMIC;
321            clear();
322            setTimeInMillis(m);
323        }
324    }
325
326    /**
327     * Returns <code>true</code> if this object is using the fixed-cycle civil
328     * calendar, or <code>false</code> if using the religious, astronomical
329     * calendar.
330     * @apiNote <strong>Discouraged:</strong> ICU 57 use getCalculationType() instead
331     * @hide unsupported on Android
332     */
333    public boolean isCivil() {
334        if(cType == CalculationType.ISLAMIC_CIVIL) {
335            return true;
336        }
337        return false;
338    }
339
340    //-------------------------------------------------------------------------
341    // Minimum / Maximum access functions
342    //-------------------------------------------------------------------------
343
344    // Note: Current IslamicCalendar implementation does not work
345    // well with negative years.
346
347    private static final int LIMITS[][] = {
348        // Minimum  Greatest     Least   Maximum
349        //           Minimum   Maximum
350        {        0,        0,        0,        0}, // ERA
351        {        1,        1,  5000000,  5000000}, // YEAR
352        {        0,        0,       11,       11}, // MONTH
353        {        1,        1,       50,       51}, // WEEK_OF_YEAR
354        {/*                                   */}, // WEEK_OF_MONTH
355        {        1,        1,       29,       30}, // DAY_OF_MONTH
356        {        1,        1,      354,      355}, // DAY_OF_YEAR
357        {/*                                   */}, // DAY_OF_WEEK
358        {       -1,       -1,        5,        5}, // DAY_OF_WEEK_IN_MONTH
359        {/*                                   */}, // AM_PM
360        {/*                                   */}, // HOUR
361        {/*                                   */}, // HOUR_OF_DAY
362        {/*                                   */}, // MINUTE
363        {/*                                   */}, // SECOND
364        {/*                                   */}, // MILLISECOND
365        {/*                                   */}, // ZONE_OFFSET
366        {/*                                   */}, // DST_OFFSET
367        {        1,        1,  5000000,  5000000}, // YEAR_WOY
368        {/*                                   */}, // DOW_LOCAL
369        {        1,        1,  5000000,  5000000}, // EXTENDED_YEAR
370        {/*                                   */}, // JULIAN_DAY
371        {/*                                   */}, // MILLISECONDS_IN_DAY
372    };
373
374    /*
375     * bit map array where a bit turned on represents a month with 30 days.
376     */
377    private static final int[] UMALQURA_MONTHLENGTH = {
378    //* 1300 -1302 */ "1010 1010 1010", "1101 0101 0100", "1110 1100 1001",
379                            0x0AAA,           0x0D54,           0x0EC9,
380    //* 1303 -1307 */ "0110 1101 0100", "0110 1110 1010", "0011 0110 1100", "1010 1010 1101", "0101 0101 0101",
381                            0x06D4,           0x06EA,           0x036C,           0x0AAD,           0x0555,
382    //* 1308 -1312 */ "0110 1010 1001", "0111 1001 0010", "1011 1010 1001", "0101 1101 0100", "1010 1101 1010",
383                            0x06A9,           0x0792,           0x0BA9,           0x05D4,           0x0ADA,
384    //* 1313 -1317 */ "0101 0101 1100", "1101 0010 1101", "0110 1001 0101", "0111 0100 1010", "1011 0101 0100",
385                            0x055C,           0x0D2D,           0x0695,           0x074A,           0x0B54,
386    //* 1318 -1322 */ "1011 0110 1010", "0101 1010 1101", "0100 1010 1110", "1010 0100 1111", "0101 0001 0111",
387                            0x0B6A,           0x05AD,           0x04AE,           0x0A4F,           0x0517,
388    //* 1323 -1327 */ "0110 1000 1011", "0110 1010 0101", "1010 1101 0101", "0010 1101 0110", "1001 0101 1011",
389                            0x068B,           0x06A5,           0x0AD5,           0x02D6,           0x095B,
390    //* 1328 -1332 */ "0100 1001 1101", "1010 0100 1101", "1101 0010 0110", "1101 1001 0101", "0101 1010 1100",
391                            0x049D,           0x0A4D,           0x0D26,           0x0D95,           0x05AC,
392    //* 1333 -1337 */ "1001 1011 0110", "0010 1011 1010", "1010 0101 1011", "0101 0010 1011", "1010 1001 0101",
393                            0x09B6,           0x02BA,           0x0A5B,           0x052B,           0x0A95,
394    //* 1338 -1342 */ "0110 1100 1010", "1010 1110 1001", "0010 1111 0100", "1001 0111 0110", "0010 1011 0110",
395                            0x06CA,           0x0AE9,           0x02F4,           0x0976,           0x02B6,
396    //* 1343 -1347 */ "1001 0101 0110", "1010 1100 1010", "1011 1010 0100", "1011 1101 0010", "0101 1101 1001",
397                            0x0956,           0x0ACA,           0x0BA4,           0x0BD2,           0x05D9,
398    //* 1348 -1352 */ "0010 1101 1100", "1001 0110 1101", "0101 0100 1101", "1010 1010 0101", "1011 0101 0010",
399                            0x02DC,           0x096D,           0x054D,           0x0AA5,           0x0B52,
400    //* 1353 -1357 */ "1011 1010 0101", "0101 1011 0100", "1001 1011 0110", "0101 0101 0111", "0010 1001 0111",
401                            0x0BA5,           0x05B4,           0x09B6,           0x0557,           0x0297,
402    //* 1358 -1362 */ "0101 0100 1011", "0110 1010 0011", "0111 0101 0010", "1011 0110 0101", "0101 0110 1010",
403                            0x054B,           0x06A3,           0x0752,           0x0B65,           0x056A,
404    //* 1363 -1367 */ "1010 1010 1011", "0101 0010 1011", "1100 1001 0101", "1101 0100 1010", "1101 1010 0101",
405                            0x0AAB,           0x052B,           0x0C95,           0x0D4A,           0x0DA5,
406    //* 1368 -1372 */ "0101 1100 1010", "1010 1101 0110", "1001 0101 0111", "0100 1010 1011", "1001 0100 1011",
407                            0x05CA,           0x0AD6,           0x0957,           0x04AB,           0x094B,
408    //* 1373 -1377 */ "1010 1010 0101", "1011 0101 0010", "1011 0110 1010", "0101 0111 0101", "0010 0111 0110",
409                            0x0AA5,           0x0B52,           0x0B6A,           0x0575,           0x0276,
410    //* 1378 -1382 */ "1000 1011 0111", "0100 0101 1011", "0101 0101 0101", "0101 1010 1001", "0101 1011 0100",
411                            0x08B7,           0x045B,           0x0555,           0x05A9,           0x05B4,
412    //* 1383 -1387 */ "1001 1101 1010", "0100 1101 1101", "0010 0110 1110", "1001 0011 0110", "1010 1010 1010",
413                            0x09DA,           0x04DD,           0x026E,           0x0936,           0x0AAA,
414    //* 1388 -1392 */ "1101 0101 0100", "1101 1011 0010", "0101 1101 0101", "0010 1101 1010", "1001 0101 1011",
415                            0x0D54,           0x0DB2,           0x05D5,           0x02DA,           0x095B,
416    //* 1393 -1397 */ "0100 1010 1011", "1010 0101 0101", "1011 0100 1001", "1011 0110 0100", "1011 0111 0001",
417                            0x04AB,           0x0A55,           0x0B49,           0x0B64,           0x0B71,
418    //* 1398 -1402 */ "0101 1011 0100", "1010 1011 0101", "1010 0101 0101", "1101 0010 0101", "1110 1001 0010",
419                            0x05B4,           0x0AB5,           0x0A55,           0x0D25,           0x0E92,
420    //* 1403 -1407 */ "1110 1100 1001", "0110 1101 0100", "1010 1110 1001", "1001 0110 1011", "0100 1010 1011",
421                            0x0EC9,           0x06D4,           0x0AE9,           0x096B,           0x04AB,
422    //* 1408 -1412 */ "1010 1001 0011", "1101 0100 1001", "1101 1010 0100", "1101 1011 0010", "1010 1011 1001",
423                            0x0A93,           0x0D49,         0x0DA4,           0x0DB2,           0x0AB9,
424    //* 1413 -1417 */ "0100 1011 1010", "1010 0101 1011", "0101 0010 1011", "1010 1001 0101", "1011 0010 1010",
425                            0x04BA,           0x0A5B,           0x052B,           0x0A95,           0x0B2A,
426    //* 1418 -1422 */ "1011 0101 0101", "0101 0101 1100", "0100 1011 1101", "0010 0011 1101", "1001 0001 1101",
427                            0x0B55,           0x055C,           0x04BD,           0x023D,           0x091D,
428    //* 1423 -1427 */ "1010 1001 0101", "1011 0100 1010", "1011 0101 1010", "0101 0110 1101", "0010 1011 0110",
429                            0x0A95,           0x0B4A,           0x0B5A,           0x056D,           0x02B6,
430    //* 1428 -1432 */ "1001 0011 1011", "0100 1001 1011", "0110 0101 0101", "0110 1010 1001", "0111 0101 0100",
431                            0x093B,           0x049B,           0x0655,           0x06A9,           0x0754,
432    //* 1433 -1437 */ "1011 0110 1010", "0101 0110 1100", "1010 1010 1101", "0101 0101 0101", "1011 0010 1001",
433                            0x0B6A,           0x056C,           0x0AAD,           0x0555,           0x0B29,
434    //* 1438 -1442 */ "1011 1001 0010", "1011 1010 1001", "0101 1101 0100", "1010 1101 1010", "0101 0101 1010",
435                            0x0B92,           0x0BA9,           0x05D4,           0x0ADA,           0x055A,
436    //* 1443 -1447 */ "1010 1010 1011", "0101 1001 0101", "0111 0100 1001", "0111 0110 0100", "1011 1010 1010",
437                            0x0AAB,           0x0595,           0x0749,           0x0764,           0x0BAA,
438    //* 1448 -1452 */ "0101 1011 0101", "0010 1011 0110", "1010 0101 0110", "1110 0100 1101", "1011 0010 0101",
439                            0x05B5,           0x02B6,           0x0A56,           0x0E4D,           0x0B25,
440    //* 1453 -1457 */ "1011 0101 0010", "1011 0110 1010", "0101 1010 1101", "0010 1010 1110", "1001 0010 1111",
441                            0x0B52,           0x0B6A,           0x05AD,           0x02AE,           0x092F,
442    //* 1458 -1462 */ "0100 1001 0111", "0110 0100 1011", "0110 1010 0101", "0110 1010 1100", "1010 1101 0110",
443                            0x0497,           0x064B,           0x06A5,           0x06AC,           0x0AD6,
444    //* 1463 -1467 */ "0101 0101 1101", "0100 1001 1101", "1010 0100 1101", "1101 0001 0110", "1101 1001 0101",
445                            0x055D,           0x049D,           0x0A4D,           0x0D16,           0x0D95,
446    //* 1468 -1472 */ "0101 1010 1010", "0101 1011 0101", "0010 1101 1010", "1001 0101 1011", "0100 1010 1101",
447                            0x05AA,           0x05B5,           0x02DA,           0x095B,           0x04AD,
448    //* 1473 -1477 */ "0101 1001 0101", "0110 1100 1010", "0110 1110 0100", "1010 1110 1010", "0100 1111 0101",
449                            0x0595,           0x06CA,           0x06E4,           0x0AEA,           0x04F5,
450    //* 1478 -1482 */ "0010 1011 0110", "1001 0101 0110", "1010 1010 1010", "1011 0101 0100", "1011 1101 0010",
451                            0x02B6,           0x0956,           0x0AAA,           0x0B54,           0x0BD2,
452    //* 1483 -1487 */ "0101 1101 1001", "0010 1110 1010", "1001 0110 1101", "0100 1010 1101", "1010 1001 0101",
453                            0x05D9,           0x02EA,           0x096D,           0x04AD,           0x0A95,
454    //* 1488 -1492 */ "1011 0100 1010", "1011 1010 0101", "0101 1011 0010", "1001 1011 0101", "0100 1101 0110",
455                            0x0B4A,           0x0BA5,           0x05B2,           0x09B5,           0x04D6,
456    //* 1493 -1497 */ "1010 1001 0111", "0101 0100 0111", "0110 1001 0011", "0111 0100 1001", "1011 0101 0101",
457                            0x0A97,           0x0547,           0x0693,           0x0749,           0x0B55,
458    //* 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",
459                            0x056A,           0x0A6B,           0x052B,           0x0A8B,           0x0D46,           0x0DA3,           0x05CA,           0x0AD6,           0x04DB,           0x026B,           0x094B,
460    //* 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",
461                            0x0AA5,           0x0B52,           0x0B69,           0x0575,           0x0176,           0x08B7,           0x025B,           0x052B,           0x0565,           0x05B4,           0x09DA,
462    //* 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",
463                            0x04ED,           0x016D,           0x08B6,           0x0AA6,           0x0D52,           0x0DA9,           0x05D4,           0x0ADA,           0x095B,           0x04AB,           0x0653,
464    //* 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",
465                            0x0729,           0x0762,           0x0BA9,           0x05B2,           0x0AB5,           0x0555,           0x0B25,           0x0D92,           0x0EC9,           0x06D2,           0x0AE9,
466    //* 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",
467                            0x056B,           0x04AB,           0x0A55,           0x0D29,           0x0D54,           0x0DAA,           0x09B5,           0x04BA,           0x0A3B,           0x049B,           0x0A4D,
468    //* 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",
469                            0x0AAA,           0x0AD5,           0x02DA,           0x095D,           0x045E,           0x0A2E,           0x0C9A,           0x0D55,           0x06B2,           0x06B9,           0x04BA,
470    //* 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",
471                            0x0A5D,           0x052D,           0x0A95,           0x0B52,           0x0BA8,           0x0BB4,           0x05B9,           0x02DA,           0x095A,           0x0B4A,           0x0DA4,
472    //* 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",
473                            0x0ED1,           0x06E8,           0x0B6A,           0x056D,           0x0535,           0x0695,           0x0D4A,           0x0DA8,           0x0DD4,           0x06DA,           0x055B,
474    //* 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",
475                            0x029D,           0x062B,           0x0B15,           0x0B4A,           0x0B95,           0x05AA,           0x0AAE,           0x092E,           0x0C8F,           0x0527,           0x0695,
476    //* 1597 -1600 */ "0110 1010 1010", "1010 1101 0110", "0101 0101 1101", "0010 1001 1101", };
477                            0x06AA,           0x0AD6,           0x055D,           0x029D
478    };
479
480    private static final int UMALQURA_YEAR_START = 1300;
481    private static final int UMALQURA_YEAR_END = 1600;
482
483
484    /**
485     */
486    @Override
487    protected int handleGetLimit(int field, int limitType) {
488        return LIMITS[field][limitType];
489    }
490
491    //-------------------------------------------------------------------------
492    // Assorted calculation utilities
493    //
494
495	// we could compress this down more if we need to
496	private static final byte[] UMALQURA_YEAR_START_ESTIMATE_FIX = {
497		 0,  0, -1,  0, -1,  0,  0,  0,  0,  0, // 1300..
498		-1,  0,  0,  0,  0,  0,  0,  0, -1,  0, // 1310..
499		 1,  0,  1,  1,  0,  0,  0,  0,  1,  0, // 1320..
500		 0,  0,  0,  0,  0,  0,  1,  0,  0,  0, // 1330..
501		 0,  0,  1,  0,  0, -1, -1,  0,  0,  0, // 1340..
502		 1,  0,  0, -1,  0,  0,  0,  1,  1,  0, // 1350..
503		 0,  0,  0,  0,  0,  0,  0, -1,  0,  0, // 1360..
504		 0,  1,  1,  0,  0, -1,  0,  1,  0,  1, // 1370..
505		 1,  0,  0, -1,  0,  1,  0,  0,  0, -1, // 1380..
506		 0,  1,  0,  1,  0,  0,  0, -1,  0,  0, // 1390..
507		 0,  0, -1, -1,  0, -1,  0,  1,  0,  0, // 1400..
508		 0, -1,  0,  0,  0,  1,  0,  0,  0,  0, // 1410..
509		 0,  1,  0,  0, -1, -1,  0,  0,  0,  1, // 1420..
510		 0,  0, -1, -1,  0, -1,  0,  0, -1, -1, // 1430..
511		 0, -1,  0, -1,  0,  0, -1, -1,  0,  0, // 1440..
512		 0,  0,  0,  0, -1,  0,  1,  0,  1,  1, // 1450..
513		 0,  0, -1,  0,  1,  0,  0,  0,  0,  0, // 1460..
514		 1,  0,  1,  0,  0,  0, -1,  0,  1,  0, // 1470..
515		 0, -1, -1,  0,  0,  0,  1,  0,  0,  0, // 1480..
516		 0,  0,  0,  0,  1,  0,  0,  0,  0,  0, // 1490..
517		 1,  0,  0, -1,  0,  0,  0,  1,  1,  0, // 1500..
518		 0, -1,  0,  1,  0,  1,  1,  0,  0,  0, // 1510..
519		 0,  1,  0,  0,  0, -1,  0,  0,  0,  1, // 1520..
520		 0,  0,  0, -1,  0,  0,  0,  0,  0, -1, // 1530..
521		 0, -1,  0,  1,  0,  0,  0, -1,  0,  1, // 1540..
522		 0,  1,  0,  0,  0,  0,  0,  1,  0,  0, // 1550..
523		-1,  0,  0,  0,  0,  1,  0,  0,  0, -1, // 1560..
524		 0,  0,  0,  0, -1, -1,  0, -1,  0,  1, // 1570..
525		 0,  0, -1, -1,  0,  0,  1,  1,  0,  0, // 1580..
526		-1,  0,  0,  0,  0,  1,  0,  0,  0,  0, // 1590..
527		 1 // 1600
528	};
529
530// Unused code - Alan 2003-05
531//    /**
532//     * Find the day of the week for a given day
533//     *
534//     * @param day   The # of days since the start of the Islamic calendar.
535//     */
536//    // private and uncalled, perhaps not used yet?
537//    private static final int absoluteDayToDayOfWeek(long day)
538//    {
539//        // Calculate the day of the week.
540//        // This relies on the fact that the epoch was a Thursday.
541//        int dayOfWeek = (int)(day + THURSDAY) % 7 + SUNDAY;
542//        if (dayOfWeek < 0) {
543//            dayOfWeek += 7;
544//        }
545//        return dayOfWeek;
546//    }
547
548    /**
549     * Determine whether a year is a leap year in the Islamic civil calendar
550     */
551    private final static boolean civilLeapYear(int year)
552    {
553        return (14 + 11 * year) % 30 < 11;
554    }
555
556    /**
557     * Return the day # on which the given year starts.  Days are counted
558     * from the Hijri epoch, origin 0.
559     */
560    private long yearStart(int year) {
561        long ys = 0;
562        if (cType == CalculationType.ISLAMIC_CIVIL
563                || cType == CalculationType.ISLAMIC_TBLA
564                || (cType == CalculationType.ISLAMIC_UMALQURA && (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END))) {
565            ys = (year-1)*354 + (long)Math.floor((3+11*year)/30.0);
566        } else if(cType == CalculationType.ISLAMIC) {
567            ys = trueMonthStart(12*(year-1));
568        } else if(cType == CalculationType.ISLAMIC_UMALQURA){
569            year -= UMALQURA_YEAR_START;
570            // rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
571            int yrStartLinearEstimate = (int)((354.36720 * year) + 460322.05 + 0.5);
572            // need a slight correction to some
573            ys = yrStartLinearEstimate + UMALQURA_YEAR_START_ESTIMATE_FIX[year];
574        }
575        return ys;
576    }
577
578    /**
579     * Return the day # on which the given month starts.  Days are counted
580     * from the Hijri epoch, origin 0.
581     *
582     * @param year  The hijri year
583     * @param month  The hijri month, 0-based
584     */
585    private long monthStart(int year, int month) {
586        // Normalize year/month in case month is outside the normal bounds, which may occur
587        // in the case of an add operation
588        int realYear = year + month / 12;
589        int realMonth = month % 12;
590        long ms = 0;
591        if (cType == CalculationType.ISLAMIC_CIVIL
592                || cType == CalculationType.ISLAMIC_TBLA
593                || (cType == CalculationType.ISLAMIC_UMALQURA && year < UMALQURA_YEAR_START )) {
594            ms = (long)Math.ceil(29.5*realMonth)
595                    + (realYear-1)*354 + (long)Math.floor((3+11*realYear)/30.0);
596        } else if(cType == CalculationType.ISLAMIC) {
597            ms = trueMonthStart(12*(realYear-1) + realMonth);
598        } else if(cType == CalculationType.ISLAMIC_UMALQURA) {
599            ms = yearStart(year);
600            for(int i=0; i< month; i++) {
601                ms+= handleGetMonthLength(year, i);
602            }
603        }
604
605        return ms;
606    }
607
608    /**
609     * Find the day number on which a particular month of the true/lunar
610     * Islamic calendar starts.
611     *
612     * @param month The month in question, origin 0 from the Hijri epoch
613     *
614     * @return The day number on which the given month starts.
615     */
616    private static final long trueMonthStart(long month)
617    {
618        long start = cache.get(month);
619
620        if (start == CalendarCache.EMPTY)
621        {
622            // Make a guess at when the month started, using the average length
623            long origin = HIJRA_MILLIS
624                        + (long)Math.floor(month * CalendarAstronomer.SYNODIC_MONTH) * ONE_DAY;
625
626            double age = moonAge(origin);
627
628            if (moonAge(origin) >= 0) {
629                // The month has already started
630                do {
631                    origin -= ONE_DAY;
632                    age = moonAge(origin);
633                } while (age >= 0);
634            }
635            else {
636                // Preceding month has not ended yet.
637                do {
638                    origin += ONE_DAY;
639                    age = moonAge(origin);
640                } while (age < 0);
641            }
642
643            start = (origin - HIJRA_MILLIS) / ONE_DAY + 1;
644
645            cache.put(month, start);
646        }
647        return start;
648    }
649
650    /**
651     * Return the "age" of the moon at the given time; this is the difference
652     * in ecliptic latitude between the moon and the sun.  This method simply
653     * calls CalendarAstronomer.moonAge, converts to degrees,
654     * and adjusts the resultto be in the range [-180, 180].
655     *
656     * @param time  The time at which the moon's age is desired,
657     *              in millis since 1/1/1970.
658     */
659    static final double moonAge(long time)
660    {
661        double age = 0;
662
663        synchronized(astro) {
664            astro.setTime(time);
665            age = astro.getMoonAge();
666        }
667        // Convert to degrees and normalize...
668        age = age * 180 / Math.PI;
669        if (age > 180) {
670            age = age - 360;
671        }
672
673        return age;
674    }
675
676    //-------------------------------------------------------------------------
677    // Internal data....
678    //
679
680    // And an Astronomer object for the moon age calculations
681    private static CalendarAstronomer astro = new CalendarAstronomer();
682
683    private static CalendarCache cache = new CalendarCache();
684
685    /**
686     * <code>true</code> if this object uses the fixed-cycle Islamic civil calendar,
687     * and <code>false</code> if it approximates the true religious calendar using
688     * astronomical calculations for the time of the new moon.
689     *
690     * @serial
691     */
692    private boolean civil = true;
693
694    /**
695     * determines the type of calculation to use for this instance
696     *
697     * @serial
698     */
699    private CalculationType cType = CalculationType.ISLAMIC_CIVIL;
700
701    //----------------------------------------------------------------------
702    // Calendar framework
703    //----------------------------------------------------------------------
704
705    /**
706     * Return the length (in days) of the given month.
707     *
708     * @param extendedYear  The hijri year
709     * @param month The hijri month, 0-based
710     */
711    @Override
712    protected int handleGetMonthLength(int extendedYear, int month) {
713
714        int length;
715
716        if (cType == CalculationType.ISLAMIC_CIVIL
717                || cType == CalculationType.ISLAMIC_TBLA
718                || (cType == CalculationType.ISLAMIC_UMALQURA && (extendedYear < UMALQURA_YEAR_START  || extendedYear > UMALQURA_YEAR_END) )) {
719            length = 29 + (month+1) % 2;
720            if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
721                length++;
722            }
723        }
724        else if (cType == CalculationType.ISLAMIC) {
725            month = 12*(extendedYear-1) + month;
726            length = (int)( trueMonthStart(month+1) - trueMonthStart(month) );
727        }
728        else { // cType == CalculationType.ISLAMIC_UMALQURA should be true at this point and not null.
729            int idx = (extendedYear - UMALQURA_YEAR_START);     // calculate year offset into bit map array
730            int mask = (0x01 << (11 - month));                  // set mask for bit corresponding to month
731            if((UMALQURA_MONTHLENGTH[idx] & mask) == 0 ) {
732                length = 29;
733            }
734            else {
735                length = 30;
736            }
737        }
738        return length;
739    }
740
741    /**
742     * Return the number of days in the given Islamic year
743     */
744    @Override
745    protected int handleGetYearLength(int extendedYear) {
746        int length =0;
747        if (cType == CalculationType.ISLAMIC_CIVIL
748                || cType == CalculationType.ISLAMIC_TBLA
749                || (cType == CalculationType.ISLAMIC_UMALQURA && (extendedYear < UMALQURA_YEAR_START  || extendedYear > UMALQURA_YEAR_END) )) {
750            length =  354 + (civilLeapYear(extendedYear) ? 1 : 0);
751        } else if (cType == CalculationType.ISLAMIC) {
752            int month = 12*(extendedYear-1);
753            length =  (int)(trueMonthStart(month + 12) - trueMonthStart(month));
754        } else if (cType == CalculationType.ISLAMIC_UMALQURA) {
755            for(int i=0; i<12; i++)
756                length += handleGetMonthLength(extendedYear, i);
757        }
758
759        return length;
760    }
761
762    //-------------------------------------------------------------------------
763    // Functions for converting from field values to milliseconds....
764    //-------------------------------------------------------------------------
765
766    // Return JD of start of given month/year
767    // Calendar says:
768    // Get the Julian day of the day BEFORE the start of this year.
769    // If useMonth is true, get the day before the start of the month.
770    // Hence the -1
771    /**
772     */
773    @Override
774    protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {
775        return (int)(monthStart(eyear, month) + ((cType ==  CalculationType.ISLAMIC_TBLA)? ASTRONOMICAL_EPOC: CIVIL_EPOC) - 1);
776    }
777
778    //-------------------------------------------------------------------------
779    // Functions for converting from milliseconds to field values
780    //-------------------------------------------------------------------------
781
782    /**
783     */
784    @Override
785    protected int handleGetExtendedYear() {
786        int year;
787        if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {
788            year = internalGet(EXTENDED_YEAR, 1); // Default to year 1
789        } else {
790            year = internalGet(YEAR, 1); // Default to year 1
791        }
792        return year;
793    }
794
795    /**
796     * Override Calendar to compute several fields specific to the Islamic
797     * calendar system.  These are:
798     *
799     * <ul><li>ERA
800     * <li>YEAR
801     * <li>MONTH
802     * <li>DAY_OF_MONTH
803     * <li>DAY_OF_YEAR
804     * <li>EXTENDED_YEAR</ul>
805     *
806     * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
807     * method is called. The getGregorianXxx() methods return Gregorian
808     * calendar equivalents for the given Julian day.
809     */
810    @Override
811    protected void handleComputeFields(int julianDay) {
812        int year =0, month=0, dayOfMonth=0, dayOfYear=0;
813        long monthStart;
814        long days = julianDay - CIVIL_EPOC;
815
816        if (cType == CalculationType.ISLAMIC_CIVIL || cType == CalculationType.ISLAMIC_TBLA) {
817            if (cType == CalculationType.ISLAMIC_TBLA) {
818                days = julianDay - ASTRONOMICAL_EPOC;
819            }
820            // Use the civil calendar approximation, which is just arithmetic
821            year  = (int)Math.floor( (30 * days + 10646) / 10631.0 );
822            month = (int)Math.ceil((days - 29 - yearStart(year)) / 29.5 );
823            month = Math.min(month, 11);
824        } else if (cType == CalculationType.ISLAMIC){
825            // Guess at the number of elapsed full months since the epoch
826            int months = (int)Math.floor(days / CalendarAstronomer.SYNODIC_MONTH);
827
828            monthStart = (long)Math.floor(months * CalendarAstronomer.SYNODIC_MONTH - 1);
829
830            if ( days - monthStart >= 25 && moonAge(internalGetTimeInMillis()) > 0) {
831                // If we're near the end of the month, assume next month and search backwards
832                months++;
833            }
834
835            // Find out the last time that the new moon was actually visible at this longitude
836            // This returns midnight the night that the moon was visible at sunset.
837            while ((monthStart = trueMonthStart(months)) > days) {
838                // If it was after the date in question, back up a month and try again
839                months--;
840            }
841
842            year = months / 12 + 1;
843            month = months % 12;
844        } else if (cType == CalculationType.ISLAMIC_UMALQURA) {
845            long umalquraStartdays = yearStart(UMALQURA_YEAR_START);
846            if( days < umalquraStartdays) {
847                // Use Civil calculation
848                year  = (int)Math.floor( (30 * days + 10646) / 10631.0 );
849                month = (int)Math.ceil((days - 29 - yearStart(year)) / 29.5 );
850                month = Math.min(month, 11);
851            } else {
852                int y =UMALQURA_YEAR_START-1, m =0;
853                long d = 1;
854                while(d > 0) {
855                    y++;
856                    d = days - yearStart(y) +1;
857                    if(d == handleGetYearLength(y)) {
858                        m=11;
859                        break;
860                    } else if(d < handleGetYearLength(y) ) {
861                        int monthLen = handleGetMonthLength(y, m);
862                        m=0;
863                        while(d > monthLen) {
864                            d -= monthLen;
865                            m++;
866                            monthLen = handleGetMonthLength(y, m);
867                        }
868                        break;
869                    }
870                }
871                year = y;
872                month = m;
873            }
874        }
875
876
877        dayOfMonth = (int)(days - monthStart(year, month)) + 1;
878
879        // Now figure out the day of the year.
880        dayOfYear = (int)(days - monthStart(year, 0) + 1);
881
882
883        internalSet(ERA, 0);
884        internalSet(YEAR, year);
885        internalSet(EXTENDED_YEAR, year);
886        internalSet(MONTH, month);
887        internalSet(DAY_OF_MONTH, dayOfMonth);
888        internalSet(DAY_OF_YEAR, dayOfYear);
889    }
890
891    /**
892     *  enumeration of available calendar calculation types
893     */
894    public enum CalculationType {
895        /**
896         * Religious calendar (atronomical simulation)
897         */
898        ISLAMIC             ("islamic"),
899        /**
900         * Tabular (intercalary years [2,5,7,10,13,16,18,21,24,26,29]) algorithm
901         * with civil (Friday) epoch.
902         */
903        ISLAMIC_CIVIL       ("islamic-civil"),
904        /**
905         * Umm al-Qura calendar
906         */
907        ISLAMIC_UMALQURA    ("islamic-umalqura"),
908        /**
909         * Tabular (intercalary years [2,5,7,10,13,16,18,21,24,26,29]) algorithm
910         * with astronomical (Thursday) epoch.
911         */
912        ISLAMIC_TBLA        ("islamic-tbla");
913
914        private String bcpType;
915
916        CalculationType(String bcpType) {
917            this.bcpType = bcpType;
918        }
919
920        String bcpType() {
921            return bcpType;
922        }
923    };
924
925    /**
926     * sets the calculation type for this calendar.
927     */
928    public void setCalculationType(CalculationType type) {
929        cType = type;
930
931        // ensure civil property is up-to-date
932        if(cType == CalculationType.ISLAMIC_CIVIL)
933            civil = true;
934        else
935            civil = false;
936    }
937
938    /**
939     * gets the calculation type for this calendar.
940     */
941    public CalculationType getCalculationType() {
942        return cType;
943    }
944
945    /**
946     * set type based on locale
947     */
948    private void setCalcTypeForLocale(ULocale locale) {
949        String localeCalType = CalendarUtil.getCalendarType(locale);
950        if("islamic-civil".equals(localeCalType))
951            setCalculationType(CalculationType.ISLAMIC_CIVIL);
952        else if("islamic-umalqura".equals(localeCalType))
953            setCalculationType(CalculationType.ISLAMIC_UMALQURA);
954        else if("islamic-tbla".equals(localeCalType))
955            setCalculationType(CalculationType.ISLAMIC_TBLA);
956        else if(localeCalType.startsWith("islamic"))
957            setCalculationType(CalculationType.ISLAMIC);       // needs to be last so it's always the default if it's islamic-something-unhandled
958        else
959            setCalculationType(CalculationType.ISLAMIC_CIVIL); // default for any non-islamic calendar locale
960    }
961
962
963    /**
964     * {@inheritDoc}
965     */
966    @Override
967    public String getType() {
968        if (cType == null) {
969            // TODO: getType() is called during Islamic calendar
970            // construction and might be null at that point. We should
971            // check the initialization sequence. See ticket#10425.
972            return "islamic";
973        }
974        return cType.bcpType();
975    }
976
977    private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {
978        in.defaultReadObject();
979
980        if (cType == null) {
981            // The serialized data was created by an ICU version before CalculationType
982            // was introduced.
983            cType = civil ? CalculationType.ISLAMIC_CIVIL : CalculationType.ISLAMIC;
984        } else {
985            // Make sure 'civil' is consistent with CalculationType
986            civil = (cType == CalculationType.ISLAMIC_CIVIL);
987        }
988    }
989
990    /*
991    private static CalendarFactory factory;
992    public static CalendarFactory factory() {
993        if (factory == null) {
994            factory = new CalendarFactory() {
995                public Calendar create(TimeZone tz, ULocale loc) {
996                    return new IslamicCalendar(tz, loc);
997                }
998
999                public String factoryName() {
1000                    return "Islamic";
1001                }
1002            };
1003        }
1004        return factory;
1005    }
1006    */
1007}
1008