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