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