]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/util/IndianCalendar.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / util / IndianCalendar.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 1996-2010, 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 java.util.Date;\r
11 import java.util.Locale;\r
12 \r
13 /**\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
20 \r
21  * A variant of the Shalivahana Calendar was reformed and standardized as the \r
22  * Indian National calendar in 1957.\r
23  * <p>\r
24  * Some details of Indian National Calendar (to be implemented) :\r
25  * The Months\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
40 \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
44  *\r
45  * The Years\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
49  * <p>\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
53  * <p>\r
54  * This class should not be subclassed.</p>\r
55  * <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
59  * \r
60  * @see com.ibm.icu.util.Calendar\r
61  * @see com.ibm.icu.util.GregorianCalendar\r
62  *\r
63  * @stable ICU 3.8\r
64  */\r
65 public class IndianCalendar extends Calendar {\r
66     // jdk1.4.2 serialver\r
67     private static final long serialVersionUID = 3617859668165014834L;\r
68 \r
69     /** \r
70      * Constant for Chaitra, the 1st month of the Indian year. \r
71      * @stable ICU 3.8\r
72      */\r
73     public static final int CHAITRA = 0;\r
74 \r
75     /** \r
76      * Constant for Vaisakha, the 2nd month of the Indian year. \r
77      * @stable ICU 3.8\r
78      */\r
79     public static final int VAISAKHA = 1;\r
80 \r
81     /** \r
82      * Constant for Jyaistha, the 3rd month of the Indian year. \r
83      * @stable ICU 3.8\r
84      */\r
85     public static final int JYAISTHA = 2;\r
86 \r
87     /** \r
88      * Constant for Asadha, the 4th month of the Indian year. \r
89      * @stable ICU 3.8\r
90      */\r
91     public static final int ASADHA = 3; \r
92 \r
93     /** \r
94      * Constant for Sravana, the 5th month of the Indian year. \r
95      * @stable ICU 3.8\r
96      */\r
97     public static final int SRAVANA = 4 ;\r
98 \r
99     /** \r
100      * Constant for Bhadra, the 6th month of the Indian year. \r
101      * @stable ICU 3.8\r
102      */\r
103     public static final int BHADRA = 5 ;\r
104 \r
105     /** \r
106      * Constant for Asvina, the 7th month of the Indian year. \r
107      * @stable ICU 3.8\r
108      */\r
109     public static final int ASVINA = 6 ;\r
110 \r
111     /** \r
112      * Constant for Kartika, the 8th month of the Indian year. \r
113      * @stable ICU 3.8\r
114      */\r
115     public static final int KARTIKA = 7 ;\r
116 \r
117     /** \r
118      * Constant for Agrahayana, the 9th month of the Indian year. \r
119      * @stable ICU 3.8\r
120      */\r
121     public static final int AGRAHAYANA = 8 ;\r
122 \r
123     /** \r
124      * Constant for Pausa, the 10th month of the Indian year. \r
125      * @stable ICU 3.8\r
126      */\r
127     public static final int PAUSA = 9 ;\r
128 \r
129     /** \r
130      * Constant for Magha, the 11th month of the Indian year. \r
131      * @stable ICU 3.8\r
132      */\r
133     public static final int MAGHA = 10;\r
134 \r
135     /** \r
136      * Constant for Phalguna, the 12th month of the Indian year. \r
137      * @stable ICU 3.8\r
138      */\r
139     public static final int PHALGUNA = 11;\r
140     \r
141     //-------------------------------------------------------------------------\r
142     // Constructors...\r
143     //-------------------------------------------------------------------------\r
144 \r
145     /**\r
146      * Constant for the Indian Era.  This is the only allowable <code>ERA</code>\r
147      * value for the Indian calendar.\r
148      *\r
149      * @see com.ibm.icu.util.Calendar#ERA\r
150      * @stable ICU 3.8\r
151      */\r
152     public static final int IE = 0;\r
153     \r
154     /**\r
155      * Constructs a <code>IndianCalendar</code> using the current time\r
156      * in the default time zone with the default locale.\r
157      * @stable ICU 3.8\r
158      */\r
159     public IndianCalendar() {\r
160        this(TimeZone.getDefault(), ULocale.getDefault());\r
161     }\r
162 \r
163     /**\r
164      * Constructs a <code>IndianCalendar</code> based on the current time\r
165      * in the given time zone with the default locale.\r
166      *\r
167      * @param zone the given time zone.\r
168      * @stable ICU 3.8\r
169      */\r
170     public IndianCalendar(TimeZone zone) {\r
171        this(zone, ULocale.getDefault());\r
172     }\r
173 \r
174     /**\r
175      * Constructs a <code>IndianCalendar</code> based on the current time\r
176      * in the default time zone with the given locale.\r
177      *\r
178      * @param aLocale the given locale.\r
179      * @stable ICU 3.8\r
180      */\r
181     public IndianCalendar(Locale aLocale) {\r
182         this(TimeZone.getDefault(), aLocale);\r
183     }\r
184 \r
185     /**\r
186      * Constructs a <code>IndianCalendar</code> based on the current time\r
187      * in the default time zone with the given locale.\r
188      *\r
189      * @param locale the given ulocale.\r
190      * @stable ICU 3.8\r
191      */\r
192     public IndianCalendar(ULocale locale) {\r
193        this(TimeZone.getDefault(), locale);\r
194     }\r
195 \r
196     /**\r
197      * Constructs a <code>IndianCalendar</code> based on the current time\r
198      * in the given time zone with the given locale.\r
199      *\r
200      * @param zone the given time zone.\r
201      *\r
202      * @param aLocale the given locale.\r
203      * @stable ICU 3.8\r
204      */\r
205     public IndianCalendar(TimeZone zone, Locale aLocale) {\r
206         super(zone, aLocale);\r
207         setTimeInMillis(System.currentTimeMillis());\r
208     }\r
209 \r
210     /**\r
211      * Constructs a <code>IndianCalendar</code> based on the current time\r
212      * in the given time zone with the given locale.\r
213      *\r
214      * @param zone the given time zone.\r
215      *\r
216      * @param locale the given ulocale.\r
217      * @stable ICU 3.8\r
218      */\r
219     public IndianCalendar(TimeZone zone, ULocale locale) {\r
220         super(zone, locale);\r
221         setTimeInMillis(System.currentTimeMillis());\r
222     }\r
223 \r
224     /**\r
225      * Constructs a <code>IndianCalendar</code> with the given date set\r
226      * in the default time zone with the default locale.\r
227      *\r
228      * @param date      The date to which the new calendar is set.\r
229      * @stable ICU 3.8\r
230      */\r
231     public IndianCalendar(Date date) {\r
232         super(TimeZone.getDefault(), ULocale.getDefault());\r
233         this.setTime(date);\r
234     }\r
235 \r
236     /**\r
237      * Constructs a <code>IndianCalendar</code> with the given date set\r
238      * in the default time zone with the default locale.\r
239      *\r
240      * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.\r
241      *\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
244      *\r
245      * @param date      The value used to set the calendar's {@link #DATE DATE} time field.\r
246      * @stable ICU 3.8\r
247      */\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
253 \r
254     }\r
255 \r
256     /**\r
257      * Constructs a IndianCalendar with the given date\r
258      * and time set for the default time zone with the default locale.\r
259      *\r
260      * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.\r
261      *\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
264      *\r
265      * @param date      The value used to set the calendar's {@link #DATE DATE} time field.\r
266      *\r
267      * @param hour      The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field.\r
268      *\r
269      * @param minute    The value used to set the calendar's {@link #MINUTE MINUTE} time field.\r
270      *\r
271      * @param second    The value used to set the calendar's {@link #SECOND SECOND} time field.\r
272      * @stable ICU 3.8\r
273      */\r
274     public IndianCalendar(int year, int month, int date, int hour,\r
275                              int minute, int second)\r
276     {\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
284     }\r
285 \r
286 \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
292     \r
293     // Starts in 78 AD, \r
294     private static final int INDIAN_ERA_START = 78;\r
295     \r
296     // The Indian year starts 80 days later than the Gregorian year.\r
297     private static final int INDIAN_YEAR_START = 80;\r
298 \r
299     /**\r
300      * {@inheritDoc}\r
301      * @stable ICU 3.8\r
302      */\r
303     protected int handleGetExtendedYear() {\r
304         int year;\r
305         \r
306         if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {\r
307             year = internalGet(EXTENDED_YEAR, 1);\r
308         } else {\r
309             // Ignore the era, as there is only one\r
310             year = internalGet(YEAR, 1);\r
311         }\r
312         \r
313         return year;\r
314     }\r
315 \r
316     /**\r
317      * {@inheritDoc}\r
318      * @stable ICU 3.8\r
319      */\r
320     protected int handleGetYearLength(int extendedYear) {\r
321        return super.handleGetYearLength(extendedYear);\r
322     }\r
323 \r
324     /**\r
325      * {@inheritDoc}\r
326      * @stable ICU 3.8\r
327      */\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
333         }\r
334 \r
335         if(isGregorianLeap(extendedYear + INDIAN_ERA_START) && month == 0) {\r
336             return 31;\r
337         }\r
338 \r
339         if(month >= 1 && month <=5) {\r
340             return 31;\r
341         }\r
342 \r
343         return 30;\r
344     }\r
345 \r
346     /**\r
347      * {@inheritDoc}\r
348      * @stable ICU 3.8\r
349      */\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
354 \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
359 \r
360         if (yday < INDIAN_YEAR_START) {\r
361             //  Day is at the end of the preceding Saka year\r
362             IndianYear -= 1;\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
365         } else {\r
366             leapMonth = isGregorianLeap(gregorianDay[0]) ? 31 : 30; // Days in leapMonth this year\r
367             yday -= INDIAN_YEAR_START;\r
368         }\r
369 \r
370         if (yday < leapMonth) {\r
371             IndianMonth = 0;\r
372             IndianDayOfMonth = yday + 1;\r
373         } else {\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
378               } else {\r
379                  mday -= 31 * 5;\r
380                  IndianMonth = (int)Math.floor(mday / 30) + 6;\r
381                  IndianDayOfMonth = (mday % 30) + 1;\r
382               }\r
383         }\r
384 \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
391      }\r
392 \r
393     private static final int LIMITS[][] = {\r
394         // Minimum  Greatest     Least    Maximum\r
395         //           Minimum   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
405         {/*                                   */}, // AM_PM\r
406         {/*                                   */}, // HOUR\r
407         {/*                                   */}, // HOUR_OF_DAY\r
408         {/*                                   */}, // MINUTE\r
409         {/*                                   */}, // SECOND\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
418     };\r
419 \r
420 \r
421     /**\r
422      * {@inheritDoc}\r
423      * @stable ICU 3.8\r
424      */\r
425     protected int handleGetLimit(int field, int limitType) {\r
426        return LIMITS[field][limitType];\r
427     }\r
428 \r
429     /**\r
430      * {@inheritDoc}\r
431      * @stable ICU 3.8\r
432      */\r
433     protected int handleComputeMonthStart(int year, int month, boolean useMonth) {\r
434 \r
435        //month is 0 based; converting it to 1-based \r
436        int imonth;\r
437        \r
438        if(month == 12) {\r
439            imonth = 1;\r
440        } else {\r
441            imonth = month +1;  \r
442        }\r
443        \r
444        double jd = IndianToJD(year ,imonth, 1);\r
445        \r
446        return (int)jd;\r
447     }\r
448 \r
449 \r
450    \r
451     /*\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
456      */\r
457     private static double IndianToJD(int year, int month, int date) {\r
458        int leapMonth, gyear, m;\r
459        double start, jd;\r
460 \r
461        gyear = year + INDIAN_ERA_START;\r
462 \r
463 \r
464        if(isGregorianLeap(gyear)) {\r
465           leapMonth = 31;\r
466           start = gregorianToJD(gyear, 3, 21);\r
467        } else {\r
468           leapMonth = 30;\r
469           start = gregorianToJD(gyear, 3, 22);\r
470        }\r
471 \r
472        if (month == 1) {\r
473           jd = start + (date - 1);\r
474        } else {\r
475           jd = start + leapMonth;\r
476           m = month - 2;\r
477           m = Math.min(m, 5);\r
478           jd += m * 31;\r
479           if (month >= 8) {\r
480              m = month - 7;\r
481              jd += m * 30;\r
482           }\r
483           jd += date - 1;\r
484        }\r
485 \r
486        return jd;\r
487     }\r
488     \r
489     /*\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
495      */\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
506                 ) +\r
507                 date);\r
508        \r
509        return jd;\r
510     }\r
511     \r
512     /*\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
516      */\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
521        \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
532        \r
533        if (!((cent == 4) || (yindex == 4))) {\r
534           year++;\r
535        }\r
536        \r
537        yearday = wjd - gregorianToJD(year, 1, 1);\r
538        leapadj = ((wjd < gregorianToJD(year, 3, 1)) ? 0\r
539              :\r
540              (isGregorianLeap(year) ? 1 : 2)\r
541              );\r
542        \r
543        month = (int)Math.floor((((yearday + leapadj) * 12) + 373) / 367);\r
544        day = (int)(wjd - gregorianToJD(year, month, 1)) + 1;\r
545 \r
546        int[] julianDate = new int[3];\r
547        \r
548        julianDate[0] = year;\r
549        julianDate[1] = month;\r
550        julianDate[2] = day;\r
551        \r
552        return julianDate;\r
553     }\r
554     \r
555     /*\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
559      */\r
560     private static boolean isGregorianLeap(int year)\r
561     {\r
562        return ((year % 4) == 0) &&\r
563           (!(((year % 100) == 0) && ((year % 400) != 0)));\r
564     }\r
565 \r
566     \r
567     /**\r
568      * {@inheritDoc}\r
569      * @stable ICU 3.8\r
570      */\r
571     public String getType() {\r
572         return "indian";\r
573     }\r
574 }\r