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