| /* GENERATED SOURCE. DO NOT MODIFY. */ |
| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /* |
| ******************************************************************************* |
| * Copyright (C) 1996-2011, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| |
| package android.icu.util; |
| |
| import java.util.Date; |
| import java.util.Locale; |
| |
| import android.icu.util.ULocale.Category; |
| |
| /** |
| * <code>IndianCalendar</code> is a subclass of <code>GregorianCalendar</code> |
| * that numbers years since the birth of the Buddha. This is the civil calendar |
| * which is accepted by government of India as Indian National Calendar. |
| * The two calendars most widely used in India today are the Vikrama calendar |
| * followed in North India and the Shalivahana or Saka calendar which is followed |
| * in South India and Maharashtra. |
| |
| * A variant of the Shalivahana Calendar was reformed and standardized as the |
| * Indian National calendar in 1957. |
| * <p> |
| * Some details of Indian National Calendar (to be implemented) : |
| * The Months |
| * Month Length Start date (Gregorian) |
| * ================================================= |
| * 1 Chaitra 30/31 March 22* |
| * 2 Vaisakha 31 April 21 |
| * 3 Jyaistha 31 May 22 |
| * 4 Asadha 31 June 22 |
| * 5 Sravana 31 July 23 |
| * 6 Bhadra 31 August 23 |
| * 7 Asvina 30 September 23 |
| * 8 Kartika 30 October 23 |
| * 9 Agrahayana 30 November 22 |
| * 10 Pausa 30 December 22 |
| * 11 Magha 30 January 21 |
| * 12 Phalguna 30 February 20 |
| |
| * In leap years, Chaitra has 31 days and starts on March 21 instead. |
| * The leap years of Gregorian calendar and Indian National Calendar are in synchornization. |
| * So When its a leap year in Gregorian calendar then Chaitra has 31 days. |
| * |
| * The Years |
| * Years are counted in the Saka Era, which starts its year 0 in 78AD (by gregorian calendar). |
| * So for eg. 9th June 2006 by Gregorian Calendar, is same as 19th of Jyaistha in 1928 of Saka |
| * era by Indian National Calendar. |
| * <p> |
| * The Indian Calendar has only one allowable era: <code>Saka Era</code>. If the |
| * calendar is not in lenient mode (see <code>setLenient</code>), dates before |
| * 1/1/1 Saka Era are rejected with an <code>IllegalArgumentException</code>. |
| * <p> |
| * This class should not be subclassed.</p> |
| * <p> |
| * IndianCalendar usually should be instantiated using |
| * {@link android.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code> |
| * with the tag <code>"@calendar=Indian"</code>.</p> |
| * |
| * @see android.icu.util.Calendar |
| * @see android.icu.util.GregorianCalendar |
| */ |
| public class IndianCalendar extends Calendar { |
| // jdk1.4.2 serialver |
| private static final long serialVersionUID = 3617859668165014834L; |
| |
| /** |
| * Constant for Chaitra, the 1st month of the Indian year. |
| */ |
| public static final int CHAITRA = 0; |
| |
| /** |
| * Constant for Vaisakha, the 2nd month of the Indian year. |
| */ |
| public static final int VAISAKHA = 1; |
| |
| /** |
| * Constant for Jyaistha, the 3rd month of the Indian year. |
| */ |
| public static final int JYAISTHA = 2; |
| |
| /** |
| * Constant for Asadha, the 4th month of the Indian year. |
| */ |
| public static final int ASADHA = 3; |
| |
| /** |
| * Constant for Sravana, the 5th month of the Indian year. |
| */ |
| public static final int SRAVANA = 4 ; |
| |
| /** |
| * Constant for Bhadra, the 6th month of the Indian year. |
| */ |
| public static final int BHADRA = 5 ; |
| |
| /** |
| * Constant for Asvina, the 7th month of the Indian year. |
| */ |
| public static final int ASVINA = 6 ; |
| |
| /** |
| * Constant for Kartika, the 8th month of the Indian year. |
| */ |
| public static final int KARTIKA = 7 ; |
| |
| /** |
| * Constant for Agrahayana, the 9th month of the Indian year. |
| */ |
| public static final int AGRAHAYANA = 8 ; |
| |
| /** |
| * Constant for Pausa, the 10th month of the Indian year. |
| */ |
| public static final int PAUSA = 9 ; |
| |
| /** |
| * Constant for Magha, the 11th month of the Indian year. |
| */ |
| public static final int MAGHA = 10; |
| |
| /** |
| * Constant for Phalguna, the 12th month of the Indian year. |
| */ |
| public static final int PHALGUNA = 11; |
| |
| //------------------------------------------------------------------------- |
| // Constructors... |
| //------------------------------------------------------------------------- |
| |
| /** |
| * Constant for the Indian Era. This is the only allowable <code>ERA</code> |
| * value for the Indian calendar. |
| * |
| * @see android.icu.util.Calendar#ERA |
| */ |
| public static final int IE = 0; |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> using the current time |
| * in the default time zone with the default <code>FORMAT</code> locale. |
| * @see Category#FORMAT |
| */ |
| public IndianCalendar() { |
| this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> based on the current time |
| * in the given time zone with the default <code>FORMAT</code> locale. |
| * |
| * @param zone the given time zone. |
| * @see Category#FORMAT |
| */ |
| public IndianCalendar(TimeZone zone) { |
| this(zone, ULocale.getDefault(Category.FORMAT)); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> based on the current time |
| * in the default time zone with the given locale. |
| * |
| * @param aLocale the given locale. |
| */ |
| public IndianCalendar(Locale aLocale) { |
| this(TimeZone.forLocaleOrDefault(aLocale), aLocale); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> based on the current time |
| * in the default time zone with the given locale. |
| * |
| * @param locale the given ulocale. |
| */ |
| public IndianCalendar(ULocale locale) { |
| this(TimeZone.forULocaleOrDefault(locale), locale); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> based on the current time |
| * in the given time zone with the given locale. |
| * |
| * @param zone the given time zone. |
| * |
| * @param aLocale the given locale. |
| */ |
| public IndianCalendar(TimeZone zone, Locale aLocale) { |
| super(zone, aLocale); |
| setTimeInMillis(System.currentTimeMillis()); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> based on the current time |
| * in the given time zone with the given locale. |
| * |
| * @param zone the given time zone. |
| * |
| * @param locale the given ulocale. |
| */ |
| public IndianCalendar(TimeZone zone, ULocale locale) { |
| super(zone, locale); |
| setTimeInMillis(System.currentTimeMillis()); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> with the given date set |
| * in the default time zone with the default <code>FORMAT</code> locale. |
| * |
| * @param date The date to which the new calendar is set. |
| * @see Category#FORMAT |
| */ |
| public IndianCalendar(Date date) { |
| super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); |
| this.setTime(date); |
| } |
| |
| /** |
| * Constructs a <code>IndianCalendar</code> with the given date set |
| * in the default time zone with the default <code>FORMAT</code> locale. |
| * |
| * @param year The value used to set the calendar's {@link #YEAR YEAR} time field. |
| * |
| * @param month The value used to set the calendar's {@link #MONTH MONTH} time field. |
| * The value is 0-based. e.g., 0 for January. |
| * |
| * @param date The value used to set the calendar's {@link #DATE DATE} time field. |
| * @see Category#FORMAT |
| */ |
| public IndianCalendar(int year, int month, int date) { |
| super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); |
| this.set(Calendar.YEAR, year); |
| this.set(Calendar.MONTH, month); |
| this.set(Calendar.DATE, date); |
| |
| } |
| |
| /** |
| * Constructs a IndianCalendar with the given date |
| * and time set for the default time zone with the default <code>FORMAT</code> locale. |
| * |
| * @param year The value used to set the calendar's {@link #YEAR YEAR} time field. |
| * |
| * @param month The value used to set the calendar's {@link #MONTH MONTH} time field. |
| * The value is 0-based. e.g., 0 for January. |
| * |
| * @param date The value used to set the calendar's {@link #DATE DATE} time field. |
| * |
| * @param hour The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field. |
| * |
| * @param minute The value used to set the calendar's {@link #MINUTE MINUTE} time field. |
| * |
| * @param second The value used to set the calendar's {@link #SECOND SECOND} time field. |
| * @see Category#FORMAT |
| */ |
| public IndianCalendar(int year, int month, int date, int hour, |
| int minute, int second) |
| { |
| super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT)); |
| this.set(Calendar.YEAR, year); |
| this.set(Calendar.MONTH, month); |
| this.set(Calendar.DATE, date); |
| this.set(Calendar.HOUR_OF_DAY, hour); |
| this.set(Calendar.MINUTE, minute); |
| this.set(Calendar.SECOND, second); |
| } |
| |
| |
| //------------------------------------------------------------------------- |
| // The only practical difference from a Gregorian calendar is that years |
| // are numbered since the Saka Era. A couple of overrides will |
| // take care of that.... |
| //------------------------------------------------------------------------- |
| |
| // Starts in 78 AD, |
| private static final int INDIAN_ERA_START = 78; |
| |
| // The Indian year starts 80 days later than the Gregorian year. |
| private static final int INDIAN_YEAR_START = 80; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| protected int handleGetExtendedYear() { |
| int year; |
| |
| if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) { |
| year = internalGet(EXTENDED_YEAR, 1); |
| } else { |
| // Ignore the era, as there is only one |
| year = internalGet(YEAR, 1); |
| } |
| |
| return year; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| protected int handleGetYearLength(int extendedYear) { |
| return super.handleGetYearLength(extendedYear); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| protected int handleGetMonthLength(int extendedYear, int month) { |
| if (month < 0 || month > 11) { |
| int[] remainder = new int[1]; |
| extendedYear += floorDivide(month, 12, remainder); |
| month = remainder[0]; |
| } |
| |
| if(isGregorianLeapYear(extendedYear + INDIAN_ERA_START) && month == 0) { |
| return 31; |
| } |
| |
| if(month >= 1 && month <=5) { |
| return 31; |
| } |
| |
| return 30; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| protected void handleComputeFields(int julianDay){ |
| double jdAtStartOfGregYear; |
| int leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday; |
| computeGregorianFields(julianDay); |
| int gregorianYear = getGregorianYear(); // Stores gregorian date corresponding to Julian day; |
| IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era |
| |
| jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0 /* first month in 0 base */, 1); // JD at start of Gregorian year |
| yday = (int)(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0) |
| |
| if (yday < INDIAN_YEAR_START) { |
| // Day is at the end of the preceding Saka year |
| IndianYear -= 1; |
| leapMonth = isGregorianLeapYear(gregorianYear - 1) ? 31 : 30; // Days in leapMonth this year, previous Gregorian year |
| yday += leapMonth + (31 * 5) + (30 * 3) + 10; |
| } else { |
| leapMonth = isGregorianLeapYear(gregorianYear) ? 31 : 30; // Days in leapMonth this year |
| yday -= INDIAN_YEAR_START; |
| } |
| |
| if (yday < leapMonth) { |
| IndianMonth = 0; |
| IndianDayOfMonth = yday + 1; |
| } else { |
| mday = yday - leapMonth; |
| if (mday < (31 * 5)) { |
| IndianMonth = mday / 31 + 1; |
| IndianDayOfMonth = (mday % 31) + 1; |
| } else { |
| mday -= 31 * 5; |
| IndianMonth = mday / 30 + 6; |
| IndianDayOfMonth = (mday % 30) + 1; |
| } |
| } |
| |
| internalSet(ERA, 0); |
| internalSet(EXTENDED_YEAR, IndianYear); |
| internalSet(YEAR, IndianYear); |
| internalSet(MONTH, IndianMonth); |
| internalSet(ORDINAL_MONTH, IndianMonth); |
| internalSet(DAY_OF_MONTH, IndianDayOfMonth ); |
| internalSet(DAY_OF_YEAR, yday + 1); // yday is 0-based |
| } |
| |
| private static final int LIMITS[][] = { |
| // Minimum Greatest Least Maximum |
| // Minimum Maximum |
| { 0, 0, 0, 0}, // ERA |
| { -5000000, -5000000, 5000000, 5000000}, // YEAR |
| { 0, 0, 11, 11}, // MONTH |
| { 1, 1, 52, 53}, // WEEK_OF_YEAR |
| {/* */}, // WEEK_OF_MONTH |
| { 1, 1, 30, 31}, // DAY_OF_MONTH |
| { 1, 1, 365, 366}, // DAY_OF_YEAR |
| {/* */}, // DAY_OF_WEEK |
| { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH |
| {/* */}, // AM_PM |
| {/* */}, // HOUR |
| {/* */}, // HOUR_OF_DAY |
| {/* */}, // MINUTE |
| {/* */}, // SECOND |
| {/* */}, // MILLISECOND |
| {/* */}, // ZONE_OFFSET |
| {/* */}, // DST_OFFSET |
| { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY |
| {/* */}, // DOW_LOCAL |
| { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR |
| {/* */}, // JULIAN_DAY |
| {/* */}, // MILLISECONDS_IN_DAY |
| {/* */}, // IS_LEAP_MONTH |
| { 0, 0, 11, 11 }, // ORDINAL_MONTH |
| }; |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| protected int handleGetLimit(int field, int limitType) { |
| return LIMITS[field][limitType]; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| protected int handleComputeMonthStart(int year, int month, boolean useMonth) { |
| |
| //month is 0 based; converting it to 1-based |
| int imonth; |
| |
| // If the month is out of range, adjust it into range, and adjust the extended year accordingly |
| if (month < 0 || month > 11) { |
| year += month / 12; |
| month %= 12; |
| } |
| |
| imonth = month + 1; |
| |
| double jd = IndianToJD(year ,imonth, 1); |
| |
| return (int)jd; |
| } |
| |
| |
| |
| /* |
| * This routine converts an Indian date to the corresponding Julian date" |
| * @param year The year in Saka Era according to Indian calendar. |
| * @param month The month according to Indian calendar (between 1 to 12) |
| * @param date The date in month |
| */ |
| private double IndianToJD(int year, int month, int date) { |
| int leapMonth, gyear, m; |
| double start, jd; |
| |
| gyear = year + INDIAN_ERA_START; |
| |
| |
| if(isGregorianLeapYear(gyear)) { |
| leapMonth = 31; |
| start = gregorianToJD(gyear, 2 /* third month in 0 based */, 21); |
| } else { |
| leapMonth = 30; |
| start = gregorianToJD(gyear, 2 /* third month in 0 based */, 22); |
| } |
| |
| if (month == 1) { |
| jd = start + (date - 1); |
| } else { |
| jd = start + leapMonth; |
| m = month - 2; |
| m = Math.min(m, 5); |
| jd += m * 31; |
| if (month >= 8) { |
| m = month - 7; |
| jd += m * 30; |
| } |
| jd += date - 1; |
| } |
| |
| return jd; |
| } |
| |
| /* |
| * The following function is not needed for basic calendar functioning. |
| * This routine converts a gregorian date to the corresponding Julian date" |
| * @param year The year in standard Gregorian calendar (AD/BC) . |
| * @param month The month according to Gregorian calendar (between 0 to 11) |
| * @param date The date in month |
| */ |
| private double gregorianToJD(int year, int month, int date) { |
| return computeGregorianMonthStart(year, month) + date - 0.5; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getType() { |
| return "indian"; |
| } |
| } |