• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
4 /*
5  *******************************************************************************
6  * Copyright (C) 1996-2016, International Business Machines Corporation and    *
7  * others. All Rights Reserved.                                                *
8  *******************************************************************************
9  */
10 package android.icu.util;
11 import java.io.IOException;
12 import java.io.ObjectInputStream;
13 import java.util.Date;
14 import java.util.Locale;
15 
16 import android.icu.impl.CalendarAstronomer;
17 import android.icu.impl.CalendarCache;
18 import android.icu.impl.CalendarUtil;
19 import 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  */
85 public 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      */
IslamicCalendar()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      */
IslamicCalendar(TimeZone zone)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      */
IslamicCalendar(Locale aLocale)196     public IslamicCalendar(Locale aLocale)
197     {
198         this(TimeZone.forLocaleOrDefault(aLocale), 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      */
IslamicCalendar(ULocale locale)207     public IslamicCalendar(ULocale locale)
208     {
209         this(TimeZone.forULocaleOrDefault(locale), 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      */
IslamicCalendar(TimeZone zone, Locale aLocale)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      */
IslamicCalendar(TimeZone zone, ULocale locale)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      */
IslamicCalendar(Date date)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      */
IslamicCalendar(int year, int month, int date)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      */
IslamicCalendar(int year, int month, int date, int hour, int minute, int second)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      */
setCivil(boolean beCivil)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      */
isCivil()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
handleGetLimit(int field, int limitType)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      */
civilLeapYear(int year)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      */
yearStart(int year)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      */
monthStart(int year, int month)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      */
trueMonthStart(long month)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      */
moonAge(long time)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
handleGetMonthLength(int extendedYear, int month)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
handleGetYearLength(int extendedYear)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
handleComputeMonthStart(int eyear, int month, boolean useMonth)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
handleGetExtendedYear()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
handleComputeFields(int julianDay)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 >=  0 ? ((months / 12) + 1) : ((months + 1 ) / 12);
843             month = ((months % 12) + 12 ) % 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 
CalculationType(String bcpType)916         CalculationType(String bcpType) {
917             this.bcpType = bcpType;
918         }
919 
bcpType()920         String bcpType() {
921             return bcpType;
922         }
923     };
924 
925     /**
926      * sets the calculation type for this calendar.
927      */
setCalculationType(CalculationType type)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      */
getCalculationType()941     public CalculationType getCalculationType() {
942         return cType;
943     }
944 
945     /**
946      * set type based on locale
947      */
setCalcTypeForLocale(ULocale locale)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
getType()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 
readObject(ObjectInputStream in)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