1/* 2 ******************************************************************************* 3 * Copyright (C) 1996-2011, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 8package com.ibm.icu.util; 9 10import java.util.Date; 11import java.util.Locale; 12 13import com.ibm.icu.util.ULocale.Category; 14 15/** 16 * <code>IndianCalendar</code> is a subclass of <code>GregorianCalendar</code> 17 * that numbers years since the birth of the Buddha. This is the civil calendar 18 * which is accepted by government of India as Indian National Calendar. 19 * The two calendars most widely used in India today are the Vikrama calendar 20 * followed in North India and the Shalivahana or Saka calendar which is followed 21 * in South India and Maharashtra. 22 23 * A variant of the Shalivahana Calendar was reformed and standardized as the 24 * Indian National calendar in 1957. 25 * <p> 26 * Some details of Indian National Calendar (to be implemented) : 27 * The Months 28 * Month Length Start date (Gregorian) 29 * ================================================= 30 * 1 Chaitra 30/31 March 22* 31 * 2 Vaisakha 31 April 21 32 * 3 Jyaistha 31 May 22 33 * 4 Asadha 31 June 22 34 * 5 Sravana 31 July 23 35 * 6 Bhadra 31 August 23 36 * 7 Asvina 30 September 23 37 * 8 Kartika 30 October 23 38 * 9 Agrahayana 30 November 22 39 * 10 Pausa 30 December 22 40 * 11 Magha 30 January 21 41 * 12 Phalguna 30 February 20 42 43 * In leap years, Chaitra has 31 days and starts on March 21 instead. 44 * The leap years of Gregorian calendar and Indian National Calendar are in synchornization. 45 * So When its a leap year in Gregorian calendar then Chaitra has 31 days. 46 * 47 * The Years 48 * Years are counted in the Saka Era, which starts its year 0 in 78AD (by gregorian calendar). 49 * So for eg. 9th June 2006 by Gregorian Calendar, is same as 19th of Jyaistha in 1928 of Saka 50 * era by Indian National Calendar. 51 * <p> 52 * The Indian Calendar has only one allowable era: <code>Saka Era</code>. If the 53 * calendar is not in lenient mode (see <code>setLenient</code>), dates before 54 * 1/1/1 Saka Era are rejected with an <code>IllegalArgumentException</code>. 55 * <p> 56 * This class should not be subclassed.</p> 57 * <p> 58 * IndianCalendar usually should be instantiated using 59 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code> 60 * with the tag <code>"@calendar=Indian"</code>.</p> 61 * 62 * @see com.ibm.icu.util.Calendar 63 * @see com.ibm.icu.util.GregorianCalendar 64 * 65 * @stable ICU 3.8 66 */ 67public class IndianCalendar extends Calendar { 68 // jdk1.4.2 serialver 69 private static final long serialVersionUID = 3617859668165014834L; 70 71 /** 72 * Constant for Chaitra, the 1st month of the Indian year. 73 * @stable ICU 3.8 74 */ 75 public static final int CHAITRA = 0; 76 77 /** 78 * Constant for Vaisakha, the 2nd month of the Indian year. 79 * @stable ICU 3.8 80 */ 81 public static final int VAISAKHA = 1; 82 83 /** 84 * Constant for Jyaistha, the 3rd month of the Indian year. 85 * @stable ICU 3.8 86 */ 87 public static final int JYAISTHA = 2; 88 89 /** 90 * Constant for Asadha, the 4th month of the Indian year. 91 * @stable ICU 3.8 92 */ 93 public static final int ASADHA = 3; 94 95 /** 96 * Constant for Sravana, the 5th month of the Indian year. 97 * @stable ICU 3.8 98 */ 99 public static final int SRAVANA = 4 ; 100 101 /** 102 * Constant for Bhadra, the 6th month of the Indian year. 103 * @stable ICU 3.8 104 */ 105 public static final int BHADRA = 5 ; 106 107 /** 108 * Constant for Asvina, the 7th month of the Indian year. 109 * @stable ICU 3.8 110 */ 111 public static final int ASVINA = 6 ; 112 113 /** 114 * Constant for Kartika, the 8th month of the Indian year. 115 * @stable ICU 3.8 116 */ 117 public static final int KARTIKA = 7 ; 118 119 /** 120 * Constant for Agrahayana, the 9th month of the Indian year. 121 * @stable ICU 3.8 122 */ 123 public static final int AGRAHAYANA = 8 ; 124 125 /** 126 * Constant for Pausa, the 10th month of the Indian year. 127 * @stable ICU 3.8 128 */ 129 public static final int PAUSA = 9 ; 130 131 /** 132 * Constant for Magha, the 11th month of the Indian year. 133 * @stable ICU 3.8 134 */ 135 public static final int MAGHA = 10; 136 137 /** 138 * Constant for Phalguna, the 12th month of the Indian year. 139 * @stable ICU 3.8 140 */ 141 public static final int PHALGUNA = 11; 142 143 //------------------------------------------------------------------------- 144 // Constructors... 145 //------------------------------------------------------------------------- 146 147 /** 148 * Constant for the Indian Era. This is the only allowable <code>ERA</code> 149 * value for the Indian calendar. 150 * 151 * @see com.ibm.icu.util.Calendar#ERA 152 * @stable ICU 3.8 153 */ 154 public static final int IE = 0; 155 156 /** 157 * Constructs a <code>IndianCalendar</code> using the current time 158 * in the default time zone with the default <code>FORMAT</code> locale. 159 * @see Category#FORMAT 160 * @stable ICU 3.8 161 */ 162 public IndianCalendar() { 163 this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); 164 } 165 166 /** 167 * Constructs a <code>IndianCalendar</code> based on the current time 168 * in the given time zone with the default <code>FORMAT</code> locale. 169 * 170 * @param zone the given time zone. 171 * @see Category#FORMAT 172 * @stable ICU 3.8 173 */ 174 public IndianCalendar(TimeZone zone) { 175 this(zone, ULocale.getDefault(Category.FORMAT)); 176 } 177 178 /** 179 * Constructs a <code>IndianCalendar</code> based on the current time 180 * in the default time zone with the given locale. 181 * 182 * @param aLocale the given locale. 183 * @stable ICU 3.8 184 */ 185 public IndianCalendar(Locale aLocale) { 186 this(TimeZone.getDefault(), aLocale); 187 } 188 189 /** 190 * Constructs a <code>IndianCalendar</code> based on the current time 191 * in the default time zone with the given locale. 192 * 193 * @param locale the given ulocale. 194 * @stable ICU 3.8 195 */ 196 public IndianCalendar(ULocale locale) { 197 this(TimeZone.getDefault(), locale); 198 } 199 200 /** 201 * Constructs a <code>IndianCalendar</code> based on the current time 202 * in the given time zone with the given locale. 203 * 204 * @param zone the given time zone. 205 * 206 * @param aLocale the given locale. 207 * @stable ICU 3.8 208 */ 209 public IndianCalendar(TimeZone zone, Locale aLocale) { 210 super(zone, aLocale); 211 setTimeInMillis(System.currentTimeMillis()); 212 } 213 214 /** 215 * Constructs a <code>IndianCalendar</code> based on the current time 216 * in the given time zone with the given locale. 217 * 218 * @param zone the given time zone. 219 * 220 * @param locale the given ulocale. 221 * @stable ICU 3.8 222 */ 223 public IndianCalendar(TimeZone zone, ULocale locale) { 224 super(zone, locale); 225 setTimeInMillis(System.currentTimeMillis()); 226 } 227 228 /** 229 * Constructs a <code>IndianCalendar</code> with the given date set 230 * in the default time zone with the default <code>FORMAT</code> locale. 231 * 232 * @param date The date to which the new calendar is set. 233 * @see Category#FORMAT 234 * @stable ICU 3.8 235 */ 236 public IndianCalendar(Date date) { 237 super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); 238 this.setTime(date); 239 } 240 241 /** 242 * Constructs a <code>IndianCalendar</code> with the given date set 243 * in the default time zone with the default <code>FORMAT</code> locale. 244 * 245 * @param year The value used to set the calendar's {@link #YEAR YEAR} time field. 246 * 247 * @param month The value used to set the calendar's {@link #MONTH MONTH} time field. 248 * The value is 0-based. e.g., 0 for January. 249 * 250 * @param date The value used to set the calendar's {@link #DATE DATE} time field. 251 * @see Category#FORMAT 252 * @stable ICU 3.8 253 */ 254 public IndianCalendar(int year, int month, int date) { 255 super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); 256 this.set(Calendar.YEAR, year); 257 this.set(Calendar.MONTH, month); 258 this.set(Calendar.DATE, date); 259 260 } 261 262 /** 263 * Constructs a IndianCalendar with the given date 264 * and time set for the default time zone with the default <code>FORMAT</code> locale. 265 * 266 * @param year The value used to set the calendar's {@link #YEAR YEAR} time field. 267 * 268 * @param month The value used to set the calendar's {@link #MONTH MONTH} time field. 269 * The value is 0-based. e.g., 0 for January. 270 * 271 * @param date The value used to set the calendar's {@link #DATE DATE} time field. 272 * 273 * @param hour The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field. 274 * 275 * @param minute The value used to set the calendar's {@link #MINUTE MINUTE} time field. 276 * 277 * @param second The value used to set the calendar's {@link #SECOND SECOND} time field. 278 * @see Category#FORMAT 279 * @stable ICU 3.8 280 */ 281 public IndianCalendar(int year, int month, int date, int hour, 282 int minute, int second) 283 { 284 super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); 285 this.set(Calendar.YEAR, year); 286 this.set(Calendar.MONTH, month); 287 this.set(Calendar.DATE, date); 288 this.set(Calendar.HOUR_OF_DAY, hour); 289 this.set(Calendar.MINUTE, minute); 290 this.set(Calendar.SECOND, second); 291 } 292 293 294 //------------------------------------------------------------------------- 295 // The only practical difference from a Gregorian calendar is that years 296 // are numbered since the Saka Era. A couple of overrides will 297 // take care of that.... 298 //------------------------------------------------------------------------- 299 300 // Starts in 78 AD, 301 private static final int INDIAN_ERA_START = 78; 302 303 // The Indian year starts 80 days later than the Gregorian year. 304 private static final int INDIAN_YEAR_START = 80; 305 306 /** 307 * {@inheritDoc} 308 * @stable ICU 3.8 309 */ 310 protected int handleGetExtendedYear() { 311 int year; 312 313 if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) { 314 year = internalGet(EXTENDED_YEAR, 1); 315 } else { 316 // Ignore the era, as there is only one 317 year = internalGet(YEAR, 1); 318 } 319 320 return year; 321 } 322 323 /** 324 * {@inheritDoc} 325 * @stable ICU 3.8 326 */ 327 protected int handleGetYearLength(int extendedYear) { 328 return super.handleGetYearLength(extendedYear); 329 } 330 331 /** 332 * {@inheritDoc} 333 * @stable ICU 3.8 334 */ 335 protected int handleGetMonthLength(int extendedYear, int month) { 336 if (month < 0 || month > 11) { 337 int[] remainder = new int[1]; 338 extendedYear += floorDivide(month, 12, remainder); 339 month = remainder[0]; 340 } 341 342 if(isGregorianLeap(extendedYear + INDIAN_ERA_START) && month == 0) { 343 return 31; 344 } 345 346 if(month >= 1 && month <=5) { 347 return 31; 348 } 349 350 return 30; 351 } 352 353 /** 354 * {@inheritDoc} 355 * @stable ICU 3.8 356 */ 357 protected void handleComputeFields(int julianDay){ 358 double jdAtStartOfGregYear; 359 int leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday; 360 int[] gregorianDay; // Stores gregorian date corresponding to Julian day; 361 362 gregorianDay = jdToGregorian(julianDay); // Gregorian date for Julian day 363 IndianYear = gregorianDay[0] - INDIAN_ERA_START; // Year in Saka era 364 jdAtStartOfGregYear = gregorianToJD(gregorianDay[0], 1, 1); // JD at start of Gregorian year 365 yday = (int)(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0) 366 367 if (yday < INDIAN_YEAR_START) { 368 // Day is at the end of the preceding Saka year 369 IndianYear -= 1; 370 leapMonth = isGregorianLeap(gregorianDay[0] - 1) ? 31 : 30; // Days in leapMonth this year, previous Gregorian year 371 yday += leapMonth + (31 * 5) + (30 * 3) + 10; 372 } else { 373 leapMonth = isGregorianLeap(gregorianDay[0]) ? 31 : 30; // Days in leapMonth this year 374 yday -= INDIAN_YEAR_START; 375 } 376 377 if (yday < leapMonth) { 378 IndianMonth = 0; 379 IndianDayOfMonth = yday + 1; 380 } else { 381 mday = yday - leapMonth; 382 if (mday < (31 * 5)) { 383 IndianMonth = mday / 31 + 1; 384 IndianDayOfMonth = (mday % 31) + 1; 385 } else { 386 mday -= 31 * 5; 387 IndianMonth = mday / 30 + 6; 388 IndianDayOfMonth = (mday % 30) + 1; 389 } 390 } 391 392 internalSet(ERA, 0); 393 internalSet(EXTENDED_YEAR, IndianYear); 394 internalSet(YEAR, IndianYear); 395 internalSet(MONTH, IndianMonth); 396 internalSet(DAY_OF_MONTH, IndianDayOfMonth ); 397 internalSet(DAY_OF_YEAR, yday + 1); // yday is 0-based 398 } 399 400 private static final int LIMITS[][] = { 401 // Minimum Greatest Least Maximum 402 // Minimum Maximum 403 { 0, 0, 0, 0}, // ERA 404 { -5000000, -5000000, 5000000, 5000000}, // YEAR 405 { 0, 0, 11, 11}, // MONTH 406 { 1, 1, 52, 53}, // WEEK_OF_YEAR 407 {/* */}, // WEEK_OF_MONTH 408 { 1, 1, 30, 31}, // DAY_OF_MONTH 409 { 1, 1, 365, 366}, // DAY_OF_YEAR 410 {/* */}, // DAY_OF_WEEK 411 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH 412 {/* */}, // AM_PM 413 {/* */}, // HOUR 414 {/* */}, // HOUR_OF_DAY 415 {/* */}, // MINUTE 416 {/* */}, // SECOND 417 {/* */}, // MILLISECOND 418 {/* */}, // ZONE_OFFSET 419 {/* */}, // DST_OFFSET 420 { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY 421 {/* */}, // DOW_LOCAL 422 { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR 423 {/* */}, // JULIAN_DAY 424 {/* */}, // MILLISECONDS_IN_DAY 425 }; 426 427 428 /** 429 * {@inheritDoc} 430 * @stable ICU 3.8 431 */ 432 protected int handleGetLimit(int field, int limitType) { 433 return LIMITS[field][limitType]; 434 } 435 436 /** 437 * {@inheritDoc} 438 * @stable ICU 3.8 439 */ 440 protected int handleComputeMonthStart(int year, int month, boolean useMonth) { 441 442 //month is 0 based; converting it to 1-based 443 int imonth; 444 445 // If the month is out of range, adjust it into range, and adjust the extended year accordingly 446 if (month < 0 || month > 11) { 447 year += month / 12; 448 month %= 12; 449 } 450 451 if(month == 12) { 452 imonth = 1; 453 } else { 454 imonth = month +1; 455 } 456 457 double jd = IndianToJD(year ,imonth, 1); 458 459 return (int)jd; 460 } 461 462 463 464 /* 465 * This routine converts an Indian date to the corresponding Julian date" 466 * @param year The year in Saka Era according to Indian calendar. 467 * @param month The month according to Indian calendar (between 1 to 12) 468 * @param date The date in month 469 */ 470 private static double IndianToJD(int year, int month, int date) { 471 int leapMonth, gyear, m; 472 double start, jd; 473 474 gyear = year + INDIAN_ERA_START; 475 476 477 if(isGregorianLeap(gyear)) { 478 leapMonth = 31; 479 start = gregorianToJD(gyear, 3, 21); 480 } else { 481 leapMonth = 30; 482 start = gregorianToJD(gyear, 3, 22); 483 } 484 485 if (month == 1) { 486 jd = start + (date - 1); 487 } else { 488 jd = start + leapMonth; 489 m = month - 2; 490 m = Math.min(m, 5); 491 jd += m * 31; 492 if (month >= 8) { 493 m = month - 7; 494 jd += m * 30; 495 } 496 jd += date - 1; 497 } 498 499 return jd; 500 } 501 502 /* 503 * The following function is not needed for basic calendar functioning. 504 * This routine converts a gregorian date to the corresponding Julian date" 505 * @param year The year in standard Gregorian calendar (AD/BC) . 506 * @param month The month according to Gregorian calendar (between 0 to 11) 507 * @param date The date in month 508 */ 509 private static double gregorianToJD(int year, int month, int date) { 510 double JULIAN_EPOCH = 1721425.5; 511 int y = year - 1; 512 int result = (365 * y) 513 + (y / 4) 514 - (y / 100) 515 + (y / 400) 516 + (((367 * month) - 362) / 12) 517 + ((month <= 2) ? 0 : (isGregorianLeap(year) ? -1 : -2)) 518 + date; 519 return result - 1 + JULIAN_EPOCH; 520 } 521 522 /* 523 * The following function is not needed for basic calendar functioning. 524 * This routine converts a julian day (jd) to the corresponding date in Gregorian calendar" 525 * @param jd The Julian date in Julian Calendar which is to be converted to Indian date" 526 */ 527 private static int[] jdToGregorian(double jd) { 528 double JULIAN_EPOCH = 1721425.5; 529 double wjd, depoch, quadricent, dqc, cent, dcent, quad, dquad, yindex, yearday, leapadj; 530 int year, month, day; 531 532 wjd = Math.floor(jd - 0.5) + 0.5; 533 depoch = wjd - JULIAN_EPOCH; 534 quadricent = Math.floor(depoch / 146097); 535 dqc = depoch % 146097; 536 cent = Math.floor(dqc / 36524); 537 dcent = dqc % 36524; 538 quad = Math.floor(dcent / 1461); 539 dquad = dcent % 1461; 540 yindex = Math.floor(dquad / 365); 541 year = (int)((quadricent * 400) + (cent * 100) + (quad * 4) + yindex); 542 543 if (!((cent == 4) || (yindex == 4))) { 544 year++; 545 } 546 547 yearday = wjd - gregorianToJD(year, 1, 1); 548 leapadj = ((wjd < gregorianToJD(year, 3, 1)) ? 0 549 : 550 (isGregorianLeap(year) ? 1 : 2) 551 ); 552 553 month = (int)Math.floor((((yearday + leapadj) * 12) + 373) / 367); 554 day = (int)(wjd - gregorianToJD(year, month, 1)) + 1; 555 556 int[] julianDate = new int[3]; 557 558 julianDate[0] = year; 559 julianDate[1] = month; 560 julianDate[2] = day; 561 562 return julianDate; 563 } 564 565 /* 566 * The following function is not needed for basic calendar functioning. 567 * This routine checks if the Gregorian year is a leap year" 568 * @param year The year in Gregorian Calendar 569 */ 570 private static boolean isGregorianLeap(int year) 571 { 572 return ((year % 4) == 0) && 573 (!(((year % 100) == 0) && ((year % 400) != 0))); 574 } 575 576 577 /** 578 * {@inheritDoc} 579 * @stable ICU 3.8 580 */ 581 public String getType() { 582 return "indian"; 583 } 584} 585