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