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