2 *******************************************************************************
\r
3 * Copyright (C) 1996-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
8 package com.ibm.icu.util;
\r
10 import java.util.Date;
\r
11 import java.util.Locale;
\r
14 * <code>IndianCalendar</code> is a subclass of <code>GregorianCalendar</code>
\r
15 * that numbers years since the birth of the Buddha. This is the civil calendar
\r
16 * which is accepted by government of India as Indian National Calendar.
\r
17 * The two calendars most widely used in India today are the Vikrama calendar
\r
18 * followed in North India and the Shalivahana or Saka calendar which is followed
\r
19 * in South India and Maharashtra.
\r
21 * A variant of the Shalivahana Calendar was reformed and standardized as the
\r
22 * Indian National calendar in 1957.
\r
24 * Some details of Indian National Calendar (to be implemented) :
\r
26 * Month Length Start date (Gregorian)
\r
27 * =================================================
\r
28 * 1 Chaitra 30/31 March 22*
\r
29 * 2 Vaisakha 31 April 21
\r
30 * 3 Jyaistha 31 May 22
\r
31 * 4 Asadha 31 June 22
\r
32 * 5 Sravana 31 July 23
\r
33 * 6 Bhadra 31 August 23
\r
34 * 7 Asvina 30 September 23
\r
35 * 8 Kartika 30 October 23
\r
36 * 9 Agrahayana 30 November 22
\r
37 * 10 Pausa 30 December 22
\r
38 * 11 Magha 30 January 21
\r
39 * 12 Phalguna 30 February 20
\r
41 * In leap years, Chaitra has 31 days and starts on March 21 instead.
\r
42 * The leap years of Gregorian calendar and Indian National Calendar are in synchornization.
\r
43 * So When its a leap year in Gregorian calendar then Chaitra has 31 days.
\r
46 * Years are counted in the Saka Era, which starts its year 0 in 78AD (by gregorian calendar).
\r
47 * So for eg. 9th June 2006 by Gregorian Calendar, is same as 19th of Jyaistha in 1928 of Saka
\r
48 * era by Indian National Calendar.
\r
50 * The Indian Calendar has only one allowable era: <code>Saka Era</code>. If the
\r
51 * calendar is not in lenient mode (see <code>setLenient</code>), dates before
\r
52 * 1/1/1 Saka Era are rejected with an <code>IllegalArgumentException</code>.
\r
54 * This class should not be subclassed.</p>
\r
56 * IndianCalendar usually should be instantiated using
\r
57 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
\r
58 * with the tag <code>"@calendar=Indian"</code>.</p>
\r
60 * @see com.ibm.icu.util.Calendar
\r
61 * @see com.ibm.icu.util.GregorianCalendar
\r
65 public class IndianCalendar extends Calendar {
\r
66 // jdk1.4.2 serialver
\r
67 private static final long serialVersionUID = 3617859668165014834L;
\r
70 * Constant for Chaitra, the 1st month of the Indian year.
\r
73 public static final int CHAITRA = 0;
\r
76 * Constant for Vaisakha, the 2nd month of the Indian year.
\r
79 public static final int VAISAKHA = 1;
\r
82 * Constant for Jyaistha, the 3rd month of the Indian year.
\r
85 public static final int JYAISTHA = 2;
\r
88 * Constant for Asadha, the 4th month of the Indian year.
\r
91 public static final int ASADHA = 3;
\r
94 * Constant for Sravana, the 5th month of the Indian year.
\r
97 public static final int SRAVANA = 4 ;
\r
100 * Constant for Bhadra, the 6th month of the Indian year.
\r
103 public static final int BHADRA = 5 ;
\r
106 * Constant for Asvina, the 7th month of the Indian year.
\r
109 public static final int ASVINA = 6 ;
\r
112 * Constant for Kartika, the 8th month of the Indian year.
\r
115 public static final int KARTIKA = 7 ;
\r
118 * Constant for Agrahayana, the 9th month of the Indian year.
\r
121 public static final int AGRAHAYANA = 8 ;
\r
124 * Constant for Pausa, the 10th month of the Indian year.
\r
127 public static final int PAUSA = 9 ;
\r
130 * Constant for Magha, the 11th month of the Indian year.
\r
133 public static final int MAGHA = 10;
\r
136 * Constant for Phalguna, the 12th month of the Indian year.
\r
139 public static final int PHALGUNA = 11;
\r
141 //-------------------------------------------------------------------------
\r
143 //-------------------------------------------------------------------------
\r
146 * Constant for the Indian Era. This is the only allowable <code>ERA</code>
\r
147 * value for the Indian calendar.
\r
149 * @see com.ibm.icu.util.Calendar#ERA
\r
152 public static final int IE = 0;
\r
155 * Constructs a <code>IndianCalendar</code> using the current time
\r
156 * in the default time zone with the default locale.
\r
159 public IndianCalendar() {
\r
160 this(TimeZone.getDefault(), ULocale.getDefault());
\r
164 * Constructs a <code>IndianCalendar</code> based on the current time
\r
165 * in the given time zone with the default locale.
\r
167 * @param zone the given time zone.
\r
170 public IndianCalendar(TimeZone zone) {
\r
171 this(zone, ULocale.getDefault());
\r
175 * Constructs a <code>IndianCalendar</code> based on the current time
\r
176 * in the default time zone with the given locale.
\r
178 * @param aLocale the given locale.
\r
181 public IndianCalendar(Locale aLocale) {
\r
182 this(TimeZone.getDefault(), aLocale);
\r
186 * Constructs a <code>IndianCalendar</code> based on the current time
\r
187 * in the default time zone with the given locale.
\r
189 * @param locale the given ulocale.
\r
192 public IndianCalendar(ULocale locale) {
\r
193 this(TimeZone.getDefault(), locale);
\r
197 * Constructs a <code>IndianCalendar</code> based on the current time
\r
198 * in the given time zone with the given locale.
\r
200 * @param zone the given time zone.
\r
202 * @param aLocale the given locale.
\r
205 public IndianCalendar(TimeZone zone, Locale aLocale) {
\r
206 super(zone, aLocale);
\r
207 setTimeInMillis(System.currentTimeMillis());
\r
211 * Constructs a <code>IndianCalendar</code> based on the current time
\r
212 * in the given time zone with the given locale.
\r
214 * @param zone the given time zone.
\r
216 * @param locale the given ulocale.
\r
219 public IndianCalendar(TimeZone zone, ULocale locale) {
\r
220 super(zone, locale);
\r
221 setTimeInMillis(System.currentTimeMillis());
\r
225 * Constructs a <code>IndianCalendar</code> with the given date set
\r
226 * in the default time zone with the default locale.
\r
228 * @param date The date to which the new calendar is set.
\r
231 public IndianCalendar(Date date) {
\r
232 super(TimeZone.getDefault(), ULocale.getDefault());
\r
233 this.setTime(date);
\r
237 * Constructs a <code>IndianCalendar</code> with the given date set
\r
238 * in the default time zone with the default locale.
\r
240 * @param year The value used to set the calendar's {@link #YEAR YEAR} time field.
\r
242 * @param month The value used to set the calendar's {@link #MONTH MONTH} time field.
\r
243 * The value is 0-based. e.g., 0 for January.
\r
245 * @param date The value used to set the calendar's {@link #DATE DATE} time field.
\r
248 public IndianCalendar(int year, int month, int date) {
\r
249 super(TimeZone.getDefault(), ULocale.getDefault());
\r
250 this.set(Calendar.YEAR, year);
\r
251 this.set(Calendar.MONTH, month);
\r
252 this.set(Calendar.DATE, date);
\r
257 * Constructs a IndianCalendar with the given date
\r
258 * and time set for the default time zone with the default locale.
\r
260 * @param year The value used to set the calendar's {@link #YEAR YEAR} time field.
\r
262 * @param month The value used to set the calendar's {@link #MONTH MONTH} time field.
\r
263 * The value is 0-based. e.g., 0 for January.
\r
265 * @param date The value used to set the calendar's {@link #DATE DATE} time field.
\r
267 * @param hour The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field.
\r
269 * @param minute The value used to set the calendar's {@link #MINUTE MINUTE} time field.
\r
271 * @param second The value used to set the calendar's {@link #SECOND SECOND} time field.
\r
274 public IndianCalendar(int year, int month, int date, int hour,
\r
275 int minute, int second)
\r
277 super(TimeZone.getDefault(), ULocale.getDefault());
\r
278 this.set(Calendar.YEAR, year);
\r
279 this.set(Calendar.MONTH, month);
\r
280 this.set(Calendar.DATE, date);
\r
281 this.set(Calendar.HOUR_OF_DAY, hour);
\r
282 this.set(Calendar.MINUTE, minute);
\r
283 this.set(Calendar.SECOND, second);
\r
287 //-------------------------------------------------------------------------
\r
288 // The only practical difference from a Gregorian calendar is that years
\r
289 // are numbered since the Saka Era. A couple of overrides will
\r
290 // take care of that....
\r
291 //-------------------------------------------------------------------------
\r
293 // Starts in 78 AD,
\r
294 private static final int INDIAN_ERA_START = 78;
\r
296 // The Indian year starts 80 days later than the Gregorian year.
\r
297 private static final int INDIAN_YEAR_START = 80;
\r
303 protected int handleGetExtendedYear() {
\r
306 if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {
\r
307 year = internalGet(EXTENDED_YEAR, 1);
\r
309 // Ignore the era, as there is only one
\r
310 year = internalGet(YEAR, 1);
\r
320 protected int handleGetYearLength(int extendedYear) {
\r
321 return super.handleGetYearLength(extendedYear);
\r
328 protected int handleGetMonthLength(int extendedYear, int month) {
\r
329 if (month < 0 || month > 11) {
\r
330 int[] remainder = new int[1];
\r
331 extendedYear += floorDivide(month, 12, remainder);
\r
332 month = remainder[0];
\r
335 if(isGregorianLeap(extendedYear + INDIAN_ERA_START) && month == 0) {
\r
339 if(month >= 1 && month <=5) {
\r
350 protected void handleComputeFields(int julianDay){
\r
351 double jdAtStartOfGregYear;
\r
352 int leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
\r
353 int[] gregorianDay; // Stores gregorian date corresponding to Julian day;
\r
355 gregorianDay = jdToGregorian(julianDay); // Gregorian date for Julian day
\r
356 IndianYear = gregorianDay[0] - INDIAN_ERA_START; // Year in Saka era
\r
357 jdAtStartOfGregYear = gregorianToJD(gregorianDay[0], 1, 1); // JD at start of Gregorian year
\r
358 yday = (int)(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0)
\r
360 if (yday < INDIAN_YEAR_START) {
\r
361 // Day is at the end of the preceding Saka year
\r
363 leapMonth = isGregorianLeap(gregorianDay[0] - 1) ? 31 : 30; // Days in leapMonth this year, previous Gregorian year
\r
364 yday += leapMonth + (31 * 5) + (30 * 3) + 10;
\r
366 leapMonth = isGregorianLeap(gregorianDay[0]) ? 31 : 30; // Days in leapMonth this year
\r
367 yday -= INDIAN_YEAR_START;
\r
370 if (yday < leapMonth) {
\r
372 IndianDayOfMonth = yday + 1;
\r
374 mday = yday - leapMonth;
\r
375 if (mday < (31 * 5)) {
\r
376 IndianMonth = (int)Math.floor(mday / 31) + 1;
\r
377 IndianDayOfMonth = (mday % 31) + 1;
\r
380 IndianMonth = (int)Math.floor(mday / 30) + 6;
\r
381 IndianDayOfMonth = (mday % 30) + 1;
\r
385 internalSet(ERA, 0);
\r
386 internalSet(EXTENDED_YEAR, IndianYear);
\r
387 internalSet(YEAR, IndianYear);
\r
388 internalSet(MONTH, IndianMonth);
\r
389 internalSet(DAY_OF_MONTH, IndianDayOfMonth );
\r
390 internalSet(DAY_OF_YEAR, yday + 1); // yday is 0-based
\r
393 private static final int LIMITS[][] = {
\r
394 // Minimum Greatest Least Maximum
\r
396 { 0, 0, 0, 0}, // ERA
\r
397 { -5000000, -5000000, 5000000, 5000000}, // YEAR
\r
398 { 0, 0, 11, 11}, // MONTH
\r
399 { 1, 1, 52, 53}, // WEEK_OF_YEAR
\r
400 {/* */}, // WEEK_OF_MONTH
\r
401 { 1, 1, 30, 31}, // DAY_OF_MONTH
\r
402 { 1, 1, 365, 366}, // DAY_OF_YEAR
\r
403 {/* */}, // DAY_OF_WEEK
\r
404 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
\r
407 {/* */}, // HOUR_OF_DAY
\r
410 {/* */}, // MILLISECOND
\r
411 {/* */}, // ZONE_OFFSET
\r
412 {/* */}, // DST_OFFSET
\r
413 { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY
\r
414 {/* */}, // DOW_LOCAL
\r
415 { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR
\r
416 {/* */}, // JULIAN_DAY
\r
417 {/* */}, // MILLISECONDS_IN_DAY
\r
425 protected int handleGetLimit(int field, int limitType) {
\r
426 return LIMITS[field][limitType];
\r
433 protected int handleComputeMonthStart(int year, int month, boolean useMonth) {
\r
435 //month is 0 based; converting it to 1-based
\r
441 imonth = month +1;
\r
444 double jd = IndianToJD(year ,imonth, 1);
\r
452 * This routine converts an Indian date to the corresponding Julian date"
\r
453 * @param year The year in Saka Era according to Indian calendar.
\r
454 * @param month The month according to Indian calendar (between 1 to 12)
\r
455 * @param date The date in month
\r
457 private static double IndianToJD(int year, int month, int date) {
\r
458 int leapMonth, gyear, m;
\r
461 gyear = year + INDIAN_ERA_START;
\r
464 if(isGregorianLeap(gyear)) {
\r
466 start = gregorianToJD(gyear, 3, 21);
\r
469 start = gregorianToJD(gyear, 3, 22);
\r
473 jd = start + (date - 1);
\r
475 jd = start + leapMonth;
\r
477 m = Math.min(m, 5);
\r
490 * The following function is not needed for basic calendar functioning.
\r
491 * This routine converts a gregorian date to the corresponding Julian date"
\r
492 * @param year The year in standard Gregorian calendar (AD/BC) .
\r
493 * @param month The month according to Gregorian calendar (between 0 to 11)
\r
494 * @param date The date in month
\r
496 private static double gregorianToJD(int year, int month, int date) {
\r
497 double JULIAN_EPOCH = 1721425.5;
\r
498 double jd = (JULIAN_EPOCH - 1) +
\r
499 (365 * (year - 1)) +
\r
500 Math.floor((year - 1) / 4) +
\r
501 (-Math.floor((year - 1) / 100)) +
\r
502 Math.floor((year - 1) / 400) +
\r
503 Math.floor((((367 * month) - 362) / 12) +
\r
504 ((month <= 2) ? 0 :
\r
505 (isGregorianLeap(year) ? -1 : -2)
\r
513 * The following function is not needed for basic calendar functioning.
\r
514 * This routine converts a julian day (jd) to the corresponding date in Gregorian calendar"
\r
515 * @param jd The Julian date in Julian Calendar which is to be converted to Indian date"
\r
517 private static int[] jdToGregorian(double jd) {
\r
518 double JULIAN_EPOCH = 1721425.5;
\r
519 double wjd, depoch, quadricent, dqc, cent, dcent, quad, dquad, yindex, yearday, leapadj;
\r
520 int year, month, day;
\r
522 wjd = Math.floor(jd - 0.5) + 0.5;
\r
523 depoch = wjd - JULIAN_EPOCH;
\r
524 quadricent = Math.floor(depoch / 146097);
\r
525 dqc = depoch % 146097;
\r
526 cent = Math.floor(dqc / 36524);
\r
527 dcent = dqc % 36524;
\r
528 quad = Math.floor(dcent / 1461);
\r
529 dquad = dcent % 1461;
\r
530 yindex = Math.floor(dquad / 365);
\r
531 year = (int)((quadricent * 400) + (cent * 100) + (quad * 4) + yindex);
\r
533 if (!((cent == 4) || (yindex == 4))) {
\r
537 yearday = wjd - gregorianToJD(year, 1, 1);
\r
538 leapadj = ((wjd < gregorianToJD(year, 3, 1)) ? 0
\r
540 (isGregorianLeap(year) ? 1 : 2)
\r
543 month = (int)Math.floor((((yearday + leapadj) * 12) + 373) / 367);
\r
544 day = (int)(wjd - gregorianToJD(year, month, 1)) + 1;
\r
546 int[] julianDate = new int[3];
\r
548 julianDate[0] = year;
\r
549 julianDate[1] = month;
\r
550 julianDate[2] = day;
\r
556 * The following function is not needed for basic calendar functioning.
\r
557 * This routine checks if the Gregorian year is a leap year"
\r
558 * @param year The year in Gregorian Calendar
\r
560 private static boolean isGregorianLeap(int year)
\r
562 return ((year % 4) == 0) &&
\r
563 (!(((year % 100) == 0) && ((year % 400) != 0)));
\r
571 public String getType() {
\r