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