The perpetual calendar production here mainly uses the Calendar class and the GregorianCalendar class. Let’s first review the basics:
Basic parts
1. Calendar class.
1. Main fields:
YEAR (Year), MONTH (Month starts from 0), DATE (January day), HOUR (indicates the hour in the morning or afternoon), HOUR_F_DAY (indicates the hour in the day.), DAY_OF_WEEK (indicates the number of weeks in the week), DAY_OF_MONTH (indicates the number of weeks in the year), DAY_OF_YEAR (indicates the number of weeks in the year), DAY_OF_WEEK _IN_MONTH (indicates the number of weeks in the month), WEEK_OF_YEAR (indicates the number of weeks in the year)
2. Get Calendar class object.
//Get through the static method getInstance of the Calendar class. Calendar ca = Calendar.getInstance();
3. Main methods
void set(int field,int value)//The parameters of the field calendar class, such as YEAR MONTH DATE, etc....void set(int year,int month,int date)//Set year, month and day. void set(int year, int month, int date, int hourOfDay, int minute)//Set year, month, day, hour, and minute)//Set year, month, day, hour, minute, and second void setTime(Date date);//Set the time of this Calendar with the given Date. int get(int field)//Returns the value of the given calendar field. For example: int month = acobj.get(Calendar.MONTH);Date getTime()//Returns a Date object representing the Calendar time value. long getTimeInMillis()//Returns the number of milliseconds from 1970.1.1 00:00:00 to the calendar. void add(int field,amont);//According to the calendar rules, add or subtract the specified amount of time for a given calendar field. Can be added or subtracted. For example: caobj.add(Calendar.MONTH,1) next month.
2. GregorianCalendar class.
1. Obtain this class object
Calendar ca = new GregorianCalendar()//Default current moment. Calendar ca = new GregorianCanlendar(int year,int month,int dayOfMonth)//Initially, the Gregorian class object with a specified year, month and day. Calendar ca = new GregorianCanlendar(int year,int month,int dayOfMonth,int hourOfDay,int minute) The Gregorian class object initially has a specified year, month and day. Calendar ca = new GregorianCanlendar(int year,int month,int dayOfMonth,int hourOfDay,int minute,int second)//Initially, the Gregorian class object with a specified year, month and day. The above are all obtained by obtaining the default locale and the default time zone objects.
2. Usage usage mainly inherits the parent class Calendar.
Example section
3. Perpetual calendar code
package com.via.mce.monthcalendar.utils;import java.util.Calendar;import java.util.Date;import java.util.GregorianCalendar;import java.util.HashMap;/** * Lunar calendar. <br> * Save the size of the year, month and previous solar terms between 1901 and 2100 of the lunar calendar, and then calculate based on these data. <br> * <br> * Several constant attribute fields for the lunar calendar have been added, and you can use the get() method to get the corresponding value of the calendar; <br> * Lunar calendar year, month, and day can also be set using the set()/add()/roll() method, and other lunar calendar attributes are automatically calculated; <br> * In addition, the getChinese(int field) method is also provided to obtain Chinese text of the lunar calendar (only applicable to lunar calendar attributes and week). <br> * <ul> * <li>CHINESE_YEAR - Lunar Year </li> * <li>CHINESE_MONTH - Lunar Month </li> * <li>CHINESE_DATE - Lunar Day </li> * <li>CHINESE_SECTIONAL_TERM - Solar Terms of the Month </li> * <li>CHINESE_PRINCIPLE_TERM - Central Qi of the Month </li> * <li>CHINESE_HEAVENLY_STEM - Heavenly Stems of the Lunar Year </li> * <li>CHINESE_EARTHLY_BRANCH - Earthly Branches of the Lunar Year </li> * <li>CHINESE_ZODIAC - Zodiac of the Lunar Year </li> * <li>CHINESE_TERM_OR_DATE - If there is a solar term on the day, it indicates the solar term. Otherwise, if the day is the first day of the day, it indicates the lunar month, otherwise it indicates the lunar day. * </ul> * Note: <br> * Due to the setting of the Calendar class, the Gregorian month starts from 0. All methods follow this convention. <br> * But all lunar attributes start from 1. Even in the method provided by Calendar, the lunar month starts with 1 and represents the leap month with a negative number. <br> * The clear() method will cause the lunar calendar and the Gregorian calendar dates to be inconsistent or the expected reset effect cannot be achieved. It should be avoided as much as possible. <br> * When using getSimpleDateString() to obtain the Gregorian calendar date string, the Gregorian calendar month has been corrected; <br> * When using getSimpleChineseDateString() to obtain the lunar calendar date string, the lunar leap month is represented by *. <br> * * @version 0.12 2011-9-5 <br> * <blockquote> Fixed an issue where the calendar was trapped in a dead cycle when initializing the calendar using the first month of the lunar calendar. </blockquote> * @version 0.11 2009-12-27 <br> * <blockquote> Fixed the issue where the lunar calendar was not calculated when obtaining the Chinese lunar calendar; <br> * Add a field CHINESE_TERM_OR_DATE to imitate the display method of the desk calendar: if there is a solar term on that day, it indicates the solar term, if it is the first day of the lunar month, * Otherwise it indicates the lunar day. </blockquote> * @version 0.10 2009-12-22 */public final class ChineseCalendar extends GregorianCalendar { private static final long serialVersionUID = 8L; /** Lunar Year*/ public static final int CHINESE_YEAR = 801; /** Lunar Month*/ public static final int CHINESE_MONTH = 802; /** Lunar Day*/ public static final int CHINESE_DATE = 803; /** Gregorian day corresponding to the solar term of the month (the previous solar term) */ public static final int CHINESE_SECTIONAL_TERM = 804; /** Gregorian day corresponding to the solar term of the month (the next solar term) */ public static final int CHINESE_PRINCIPLE_TERM = 805; /** Heavenly Stems*/ public static final int CHINESE_HEAVENLY_STEM = 806; /** Earthly Branches*/ public static final int CHINESE_EARTHLY_BRANCH = 807; /** Zodiac signs (zodiac signs) */ public static final int CHINESE_ZODIAC = 808; /** solar term or lunar day*/ public static final int CHINESE_TERM_OR_DATE = 888; // add by skywang /** Lunar Festival*/ public static final int LUNAR_FESTIVAL = 809; /** solar term*/ public static final int SOLAR_FESTIVAL = 810; /** solar term*/ public static final int CHINESE_TERM = 811; /** month or lunar day*/ public static final int CHINESE_MONTH_OR_DATE = 812; /** Festival or solar term or lunar day*/ public static final int FESTIVAL_OR_TERM_OR_DATE = 813; private int chineseYear; private int chineseMonth; // Start with 1, negative numbers represent leap month private int chineseDate; private int sectionTerm; // Gregorian day private int principleTerm; // Gregorian day private boolean are ChineseFieldsComputed; // Whether the lunar date has been calculated and confirmed private boolean areSolarTermsComputed; // Whether the solar term has been calculated and confirmed private boolean lastSetChinese; // Is the last setting of the lunar attribute/** Construct an instance using the current time. */ public ChineseCalendar() { super(); } /** Construct an instance using the specified time. */ public ChineseCalendar(Date d) { super.setTime(d); } /** Construct an instance using the specified time. */ public ChineseCalendar(Calendar c) { this(c.getTime()); } /** Construct an instance using the specified Gregorian date. */ public ChineseCalendar(int y, int m, int d) { super(y, m, d); } /** * Construct an instance with the specified date. * * @param isChinese * Is it the lunar date* @param y * @param m * @param d */ public ChineseCalendar(boolean isChinese, int y, int m, int d) { if (isChinese) { set(CHINESE_YEAR, y); set(CHINESE_MONTH, m); set(CHINESE_DATE, d); } else { set(y, m, d); } } public void set(int field, int value) { computeIfNeed(field); if (isChineseField(field)) { // Lunar calendar attribute switch (field) { case CHINESE_YEAR: chineseYear = value; break; case CHINESE_MONTH: chineseMonth = value; break; case CHINESE_DATE: chineseDate = value; break; default: throw new IllegalArgumentException("Unsupported field settings: " + field); } lastSetChinese = true; } else { // Non-lunar calendar attribute super.set(field, value); lastSetChinese = false; } areFieldsSet = false; areChineseFieldsComputed = false; areSolarTermsComputed = false; } public int get(int field) { computeIfNeed(field); if (!isChineseField(field)) { return super.get(field); } switch (field) { case CHINESE_YEAR: return chineseYear; case CHINESE_MONTH: return chineseMonth; case CHINESE_DATE: return chineseDate; case CHINESE_SECTIONAL_TERM: return sectionalTerm; case CHINESE_PRINCIPLE_TERM: return principleTerm; case CHINESE_HEAVENLY_STEM: return (chineseYear - 4) % 10 + 1; case CHINESE_EARTHLY_BRANCH: case CHINESE_ZODIAC: return (chineseYear - 4) % 12 + 1; case CHINESE_MONTH_OR_DATE: if (get(CHINESE_DATE) == 1) { return CHINESE_MONTH; } else { return CHINESE_DATE; } case CHINESE_TERM_OR_DATE: int option; if (get(Calendar.DATE) == get(CHINESE_SECTIONAL_TERM)) { option = CHINESE_SECTIONAL_TERM; } else if (get(Calendar.DATE) == get(CHINESE_PRINCIPLE_TERM)) { option = CHINESE_PRINCIPLE_TERM; } else if (get(CHINESE_DATE) == 1) { option = CHINESE_MONTH; } else { option = CHINESE_DATE; } return option; default: throw new IllegalArgumentException("Unsupported field get: " + field); } } public void add(int field, int amount) { computeIfNeed(field); if (!isChineseField(field)) { super.add(field, amount); lastSetChinese = false; areChineseFieldsComputed = false; areSolarTermsComputed = false; return; } switch (field) { case CHINESE_YEAR: chineseYear += amount; break; case CHINESE_MONTH: for (int i = 0; i < amount; i++) { chineseMonth = nextChineseMonth(chineseYear, chineseMonth); if (chineseMonth == 1) { chineseYear++; } } break; case CHINESE_DATE: int maxDate = daysInChineseMonth(chineseYear, chineseMonth); for (int i = 0; i < amount; i++) { chineseDate++; if (chineseDate > maxDate) { chineseDate = 1; chineseMonth = nextChineseMonth(chineseYear, chineseMonth); if (chineseMonth == 1) { chineseYear++; } maxDate = daysInChineseMonth(chineseYear, chineseMonth); } } default: throw new IllegalArgumentException("unsupported field:" + field); } lastSetChinese = true; areFieldsSet = false; areChineseFieldsComputed = false; areSolarTermsComputed = false; } public void roll(int field, int amount) { computeIfNeed(field); if (!isChineseField(field)) { super.roll(field, amount); lastSetChinese = false; areChineseFieldsComputed = false; areSolarTermsComputed = false; return; } switch (field) { case CHINESE_YEAR: chineseYear += amount; break; case CHINESE_MONTH: for (int i = 0; i < amount; i++) { chineseMonth = nextChineseMonth(chineseYear, chineseMonth); } break; case CHINESE_DATE: int maxDate = daysInChineseMonth(chineseYear, chineseMonth); for (int i = 0; i < amount; i++) { chineseDate++; if (chineseDate > maxDate) { chineseDate = 1; } } default: throw new IllegalArgumentException("Unsupported field:" + field); } lastSetChinese = true; areFieldsSet = false; areChineseFieldsComputed = false; areSolarTermsComputed = false; } /** * Get the Chinese language of the attribute, the attribute fields that can be used are DAY_OF_WEEK and all lunar attribute fields. * * @param field * @return */ public String getChinese(int field) { computeIfNeed(field); switch (field) { case CHINESE_YEAR: return getChinese(CHINESE_HEAVENLY_STEM) + getChinese(CHINESE_EARTHLY_BRANCH) + "Year"; case CHINESE_MONTH: if (chineseMonth > 0) return chineseMonthNames[chineseMonth] + "month"; else return "leap" + chineseMonthNames[-chineseMonth] + "month"; case CHINESE_DATE: return chineseDateNames[chineseDate]; case CHINESE_SECTIONAL_TERM: return sectionTermNames[get(Calendar.MONTH)]; case CHINESE_PRINCIPLE_TERM: return principleTermNames[get(Calendar.MONTH)]; case CHINESE_HEAVENLY_STEM: return stemNames[get(field)]; case CHINESE_EARTHLY_BRANCH: return branchNames[get(field)]; case CHINESE_ZODIAC: return animalNames[get(field)]; case Calendar.DAY_OF_WEEK: return chineseWeekNames[get(field)]; case CHINESE_TERM_OR_DATE: return getChinese(get(CHINESE_TERM_OR_DATE)); case LUNAR_FESTIVAL: return getLunarFestival(); case SOLAR_FESTIVAL: return getSolarFestival(); case FESTIVAL_OR_TERM_OR_DATE: return getFestivalOrTermOrDate(); // TODO CHECK case CHINESE_MONTH_OR_DATE: return getChinese(get(CHINESE_MONTH_OR_DATE)); case CHINESE_TERM: return getChineseTerm(); default: throw new IllegalArgumentException("Unsupported field Chinese get: " + field); } } public String getSimpleGregorianDateString() { return new StringBuffer().append(get(YEAR)).append("-") .append(get(MONTH) + 1).append("-").append(get(DATE)) .toString(); } public String getSimpleChineseDateString() { return new StringBuffer() .append(get(CHINESE_YEAR)) .append("-") .append(get(CHINESE_MONTH) > 0 ? "" + get(CHINESE_MONTH) : "*" + (-get(CHINESE_MONTH))).append("-") .append(get(CHINESE_DATE)).toString(); } public String getChineseDateString() { return new StringBuffer().append(getChinese(CHINESE_YEAR)) .append(getChinese(CHINESE_MONTH)) .append(getChinese(CHINESE_DATE)).toString(); } public String toString() { StringBuffer buf = new StringBuffer(); buf.append(getSimpleGregorianDateString()).append(" | ") .append(getChinese(DAY_OF_WEEK)).append(" | [Lunar calendar]") .append(getChineseDateString()).append(" ") .append(getChinese(CHINESE_ZODIAC)).append("Year") .append(get(CHINESE_SECTIONAL_TERM)).append("Day") .append(getChinese(CHINESE_SECTIONAL_TERM)).append(" ") .append(get(CHINESE_PRINCIPLE_TERM)).append("Day") .append(getChinese(CHINESE_PRINCIPLE_TERM)); return buf.toString(); } /** * Determine whether it is a lunar attribute* * @param field * @return */ private boolean isChineseField(int field) { switch (field) { case CHINESE_YEAR: case CHINESE_MONTH: case CHINESE_DATE: case CHINESE_SECTIONAL_TERM: case CHINESE_PRINCIPLE_TERM: case CHINESE_HEAVENLY_STEM: case CHINESE_EARTHLY_BRANCH: case CHINESE_ZODIAC: case CHINESE_TERM_OR_DATE: case CHINESE_MONTH_OR_DATE: return true; default: return false; } } /** * Determine whether it is an attribute related to the solar term* * @param field * @return */ private boolean isChineseTermsField(int field) { switch (field) { case CHINESE_SECTIONAL_TERM: case CHINESE_PRINCIPLE_TERM: case CHINESE_TERM_OR_DATE: return true; default: return false; } } /** * If the attributes that were set last time are not the same as the ones to be set or obtained this time (lunar calendar/gregorian calendar), <br> * For example, the last time I set it was the lunar calendar and now I want to set or obtain the Gregorian calendar, <br> * You need to calculate the Gregorian calendar date based on the previously set lunar calendar date. * * @param field */ private void computeIfNeed(int field) { if (isChineseField(field)) { if (!lastSetChinese && !areChineseFieldsComputed) { super.complete(); computeChineseFields(); areFieldsSet = true; areChineseFieldsComputed = true; areSolarTermsComputed = false; } if (isChineseTermsField(field) && !areSolarTermsComputed) { computeSolarTerms(); areSolarTermsComputed = true; } } else { if (lastSetChinese && !areFieldsSet) { computeGregorianFields(); super.complete(); areFieldsSet = true; areChineseFieldsComputed = true; areSolarTermsComputed = false; } } } /** * Use lunar date to calculate the GregorianDate*/ private void computeGregorianFields() { int y = chineseYear; int m = chineseMonth; int d = chineseDate; areChineseFieldsComputed = true; areFieldsSet = true; lastSetChinese = false; // Adjust the date range if (y < 1900) y = 1899; else if (y > 2100) y = 2101; if (m < -12) m = -12; else if (m > 12) m = 12; if (d < 1) d = 1; else if (d > 30) d = 30; int dateint = y * 10000 + Math.abs(m) * 100 + d; if (dateint < 19001111) { // too small set(1901, Calendar.JANUARY, 1); super.complete(); } else if (dateint > 21001201) { // too large set(2100, Calendar.DECEMBER, 31); super.complete(); } else { if (Math.abs(m) > 12) { m = 12; } int days = ChineseCalendar.daysInChineseMonth(y, m); if (days == 0) { m = -m; days = ChineseCalendar.daysInChineseMonth(y, m); } if (d > days) { d = days; } set(y, Math.abs(m) - 1, d); computeChineseFields(); int amount = 0; while (chineseYear != y || chineseMonth != m) { amount += daysInChineseMonth(chineseYear, chineseMonth); chineseMonth = nextChineseMonth(chineseYear, chineseMonth); if (chineseMonth == 1) { chineseYear++; } } amount += d - chineseDate; super.add(Calendar.DATE, amount); } computeChineseFields(); } /** * Calculate the lunar calendar date using the Gregorian date*/ private void computeChineseFields() { int gregorianYear = internalGet(Calendar.YEAR); int gregorianMonth = internalGet(Calendar.MONTH) + 1; int gregorianDate = internalGet(Calendar.DATE); if (gregorianYear < 1901 || gregorianYear > 2100) { return; } int startYear, startMonth, startDate; if (gregorianYear < 2000) { startYear = baseYear; startMonth = baseMonth; startDate = baseDate; chineseYear = baseChineseYear; chineseMonth = baseChineseMonth; chineseDate = baseChineseDate; } else { // The second corresponding day is used to improve computing efficiency// January 1, 2000, the corresponding lunar calendar 4697 (1999), startYear = baseYear + 99; startMonth = 1; startDate = 1; chineseYear = baseChineseYear + 99; chineseMonth = 11; chineseDate = 25; } int daysDiff = 0; // year for (int i = startYear; i < gregorianYear; i++) { if (isGregorianLeapYear(i)) { daysDiff += 366; // leap year } else { daysDiff += 365; } } // month for (int i = startMonth; i < gregorianMonth; i++) { daysDiff += daysInGregorianMonth(gregorianYear, i - 1); } // daydaysDiff += gregorianDate - startDate; chineseDate += daysDiff; int lastDate = daysInChineseMonth(chineseYear, chineseMonth); while (chineseDate > lastDate) { chineseDate -= lastDate; chineseMonth = nextChineseMonth(chineseYear, chineseMonth); if (chineseMonth == 1) { chineseYear++; } lastDate = daysInChineseMonth(chineseYear, chineseMonth); } } /** * Calculate solar terms*/ private void computeSolarTerms() { int gregorianYear = internalGet(Calendar.YEAR); int gregorianMonth = internalGet(Calendar.MONTH); if (gregorianYear < 1901 || gregorianYear > 2100) { return; } sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth); principleTerm = principalTerm(gregorianYear, gregorianMonth); } /* Next is the static method~ */ /** * Is it a leap year in the Gregorian year* * @param year * @return */ public static boolean isGregorianLeapYear(int year) { boolean isLeap = false; if (year % 4 == 0) { isLeap = true; } if (year % 100 == 0) { isLeap = false; } if (year % 400 == 0) { isLeap = true; } return isLeap; } /** * Calculate the number of days in the Gregorian year, and the Gregorian month starts from 0! * * @param y * @param m * @return */ public static int daysInGregorianMonth(int y, int m) { int d = daysInGregorianMonth[m]; if (m == Calendar.FEBRUARY && isGregorianLeapYear(y)) { d++; // One more day in a leap year in the Gregorian year} return d; } /** * Calculate the solar terms of the Gregorian month, the Gregorian month starts from 0! * * @param y * @param m * @return */ public static int sectionalTerm(int y, int m) { m++; if (y < 1901 || y > 2100) { return 0; } int index = 0; int ry = y - baseYear + 1; while (ry >= sectionalTermYear[m - 1][index]) { index++; } int term = sectionalTermMap[m - 1][4 * index + ry % 4]; if ((ry == 121) && (m == 4)) { term = 5; } if ((ry == 132) && (m == 4)) { term = 5; } if ((ry == 194) && (m == 6)) { term = 6; } return term; } /** * Calculate the Zhongqi of the Gregorian year, and the Gregorian month starts from 0! * * @param y * @param m * @return */ public static int principleTerm(int y, int m) { m++; if (y < 1901 || y > 2100) { return 0; } int index = 0; int ry = y - baseYear + 1; while (ry >= principleTermYear[m - 1][index]) { index++; } int term = principalTermMap[m - 1][4 * index + ry % 4]; if ((ry == 171) && (m == 3)) { term = 21; } if ((ry == 181) && (m == 5)) { term = 21; } return term; } /** * Calculate the number of days in the lunar year* * @param y * @param m * @return */ public static int daysInChineseMonth(int y, int m) { // Note: leap month m < 0 int index = y - baseChineseYear + baseIndex; int v = 0; int l = 0; int d = 30; if (1 <= m && m <= 8) { v = chineseMonths[2 * index]; l = m - 1; if (((v >> l) & 0x01) == 1) { d = 29; } } else if (9 <= m && m <= 12) { v = chineseMonths[2 * index + 1]; l = m - 9; if (((v >> l) & 0x01) == 1) { d = 29; } } else { v = chineseMonths[2 * index + 1]; v = (v >> 4) & 0x0F; if (v != Math.abs(m)) { d = 0; } else { d = 29; for (int i = 0; i < bigLeapMonthYears.length; i++) { if (bigLeapMonthYears[i] == index) { d = 30; break; } } } } return d; } /** * Calculate the next month of the lunar calendar* * @param y * @param m * @return */ public static int nextChineseMonth(int y, int m) { int n = Math.abs(m) + 1; if (m > 0) { int index = y - baseChineseYear + baseIndex; int v = chineseMonths[2 * index + 1]; v = (v >> 4) & 0x0F; if (v == m) { n = -m; } } if (n == 13) { n = 1; } return n; } /* Date of the first day of the calendar*/ private static final int baseYear = 1901; private static final int baseMonth = 1; private static final int baseDate = 1; private static final int baseIndex = 0; private static final int baseChineseYear = 1900; private static final int baseChineseMonth = 11; private static final int baseChineseDate = 11; /* Chinese string*/ private static final String[] chineseWeekNames = { "", "Sunday", "Monday", "Tuesday", "Thursday", "Friday", "Saturday" }; private static final String[] chineseMonthNames = { "", "First", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Ten", "Eleven", "Twelve" }; private static final String[] chineseDateNames = { "", "First", "First", "Fourth", "Five", "Sixth", "Seventh", "Eighth", "Nine", "Nine", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth", "Tenth" }; private static final String[] principleTermNames = { "Great Cold", "Rain Water", "Spring Equinox", "Green Rain", "Summer Solar", "Green Summer", "Green Summer", "Green Summer", "Green Summer", "Summer Solar", "Green Summer", "Starry Summer", "September Equinox", "September Equinox", "Frost fall", "Light snow", "Winter Solstice" }; private static final String[] sectionTermNames = { "Little Cold", "Bird Spring", "Jingzhe", "Qingming", "Beginning of Summer", "Graining Seeds", "Little Heat", "Bird Autumn", "White Dew", "Cold Dew", "Breaking Winter", "High Snow" }; private static final String[] stemNames = { "", "Jia", "Yi", "Bing", "Ding", "Wu", "Ji", "Geng", "Xin", "Ren", "Gui" }; private static final String[] branchNames = { "", "Zi", "Ug", "Yin", "Mao", "Chen", "Si", "Wu", "Shen", "You", "Xu", "Hai" }; private static final String[] animalNames = { "", "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Sheep", "Monkey", "Chicken", "Dog", "Pig" }; /* Next is the data compression table~ */ private static final int[] bigLeapMonthYears = { 6, 14, 19, 25, 33, 36, 38, 41, 44, 52, 55, 79, 117, 136, 147, 150, 155, 158, 185, 193 }; private static final char[][] sectionalTermMap = { { 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5 }, { 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 3, 3, 4, 4, 3, 3, 3 }, { 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5 }, { 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4, 4, 5, 4, 4, 4, 4, 5 }, { 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5 }, { 6, 6, 7, 7, 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5 }, { 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 6, 6, 6, 7, 7 }, { 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7 }, { 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 7 }, { 9, 9, 9, 9, 8, 9, 9, 9, 8, 8, 9, 9, 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 8 }, { 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7 }, { 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 6, 6, 6, 7, 7 } }; private static final char[][] sectionalTermYear = { { 13, 49, 85, 117, 149, 185, 201, 250, 250 }, { 13, 45, 81, 117, 149, 185, 201, 250 }, { 13, 48, 84, 112, 148, 184, 200, 201, 250 }, { 13, 45, 76, 108, 140, 172, 200, 201, 250 }, { 13, 44, 72, 104, 132, 168, 200, 201, 250 }, { 5, 33, 68, 96, 124, 152, 188, 200, 201 }, { 29, 57, 85, 120, 148, 176, 200, 201, 250 }, { 13, 48, 76, 104, 132, 168, 196, 200, 201 }, { 25, 60, 88, 120, 148, 184, 200, 201, 250 }, { 16, 44, 76, 108, 144, 172, 200, 201, 250 }, { 28, 60, 92, 124, 160, 192, 200, 201, 250 }, { 17, 53, 85, 124, 156, 188, 200, 201, 250 } }; private static final char[][] principleTermMap = { { 21, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 19, 20, 20, 20, 19, 19, 20 }, { 20, 19, 19, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, 19, 19, 19, 18, 18, 19, 19, 18, 18, 18, 18, 18, 18, 18 }, { 21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 20, 20, 20, 20, 19, 20, 20, 20, 20 }, { 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 20, 20, 20, 20, 19, 20, 20, 20, 19, 19, 20, 20, 19, 19, 19, 20, 20 }, { 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 21 }, { 22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 21 }, { 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 23 }, { 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 }, { 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 }, { 24, 24, 24, 24, 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 23 }, { 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 22 }, { 22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 22 } }; private static final char[][] principleTermYear = { { 13, 45, 81, 113, 149, 185, 201 }, { 21, 57, 93, 125, 161, 193, 201 }, { 21, 56, 88, 120, 152, 188, 200, 201 }, { 21, 49, 81, 116, 144, 176, 200, 201 }, { 17, 49, 201 }, { 28, 60, 88, 116, 148, 180, 200, 201 }, { 25, 53, 84, 112, 144, 172, 200, 201 }, { 29, 57, 89, 120, 148, 180, 200, 201 }, { 17, 45, 73, 108, 140, 168, 200, 201 }, { 28, 60, 92, 124, 160, 192, 200, 201 }, { 16, 44, 80, 112, 148, 180, 200, 201 }, { 17, 53, 88, 120, 156, 188, 200, 201 } }; private static final char[] daysInGregorianMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31 }; private static final char[] chineseMonths = { 0x00, 0x04, 0xad, 0x08, 0x5a, 0x01, 0xd5, 0x54, 0xb4, 0x09, 0x64, 0x05, 0x59, 0x45, 0x95, 0x95, 0x0a, 0xa6, 0x04, 0x55, 0x24, 0xad, 0x08, 0x5a, 0x62, 0xda, 0x04, 0xb4, 0x05, 0xb4, 0x55, 0x52, 0x0d, 0x94, 0x0a, 0x4a, 0x2a, 0x56, 0x02, 0x6d, 0x71, 0x6d, 0x01, 0xda, 0x02, 0xd2, 0x52, 0xa9, 0x05, 0x49, 0x0d, 0x2a, 0x45, 0x2b, 0x09, 0x56, 0x01, 0xb5, 0x20, 0x6d, 0x01, 0x59, 0x69, 0xd4, 0x0a, 0xa8, 0x05, 0xa9, 0x56, 0xa5, 0x04, 0x2b, 0x09, 0x9e, 0x38, 0xb6, 0x08, 0xec, 0x74, 0x6c, 0x05, 0xd4, 0x0a, 0xe4, 0x6a, 0x52, 0x05, 0x95, 0x0a, 0x5a, 0x42, 0x5b, 0x04, 0xb6, 0x04, 0xb4, 0x22, 0x6a, 0x05, 0x52, 0x75, 0xc9, 0x0a, 0x52, 0x05, 0x35, 0x55, 0x4d, 0x0a, 0x5a, 0x02, 0x5d, 0x31, 0xb5, 0x02, 0x6a, 0x8a, 0x68, 0x05, 0xa9, 0x0a, 0x8a, 0x6a, 0x2a, 0x05, 0x2d, 0x09, 0xaa, 0x48, 0x5a, 0x01, 0xb5, 0x09, 0xb0, 0x39, 0x64, 0x05, 0x25, 0x75, 0x95, 0x0a, 0x96, 0x04, 0x4d, 0x54, 0xad, 0x04, 0xda, 0x04, 0xd4, 0x44, 0xb4, 0x05, 0x54, 0x85, 0x52, 0x0d, 0x92, 0x0a, 0x56, 0x6a, 0x56, 0x02, 0x6a, 0x41, 0xda, 0x02, 0xb2, 0xa1, 0xa9, 0x05, 0x49, 0x0d, 0x0a, 0x6d, 0x2a, 0x09, 0x56, 0x01, 0xad, 0x50, 0x6d, 0x01, 0xd9, 0x02, 0xd1, 0x3a, 0xa8, 0x05, 0x29, 0x85, 0xa5, 0x0c, 0x2a, 0x09, 0x96, 0x54, 0xb6, 0x08, 0x6c, 0x09, 0x64, 0x45, 0xd4, 0x0a, 0xa4, 0x05, 0x51, 0x25, 0x95, 0x0a, 0x2a, 0x72, 0x5b, 0x04, 0xb6, 0x04, 0xac, 0x52, 0x6a, 0x05, 0xd2, 0x0a, 0xa2, 0x4a, 0x4a, 0x05, 0x55, 0x94, 0x2d, 0x0a, 0x5a, 0x02, 0x75, 0x61, 0xb5, 0x02, 0x6a, 0x03, 0x61, 0x45, 0xa9, 0x0a, 0x4a, 0x05, 0x25, 0x2d, 0x09, 0x9a, 0x68, 0xda, 0x08, 0xb4, 0x09, 0xa8, 0x59, 0x54, 0x03, 0xa5, 0x0a, 0x91, 0x3a, 0x96, 0x04, 0xad, 0xb0, 0xad, 0x04, 0xda, 0x04, 0xf4, 0x62, 0xb4, 0x05, 0x54, 0x0b, 0x44, 0x5d, 0x52, 0x0a, 0x95, 0x04, 0x55, 0x22, 0x6d, 0x02, 0x5a, 0x71, 0xda, 0x02, 0xaa, 0x05, 0xb2, 0x55, 0x49, 0x0b, 0x4a, 0x0a, 0x2d, 0x39, 0x36, 0x01, 0x6d, 0x80, 0x6d, 0x01, 0xd9, 0x02, 0xe9, 0x6a, 0xa8, 0x05, 0x29, 0x0b, 0x9a, 0x4c, 0xaa, 0x08, 0xb6, 0x08, 0xb4, 0x38, 0x6c, 0x09, 0x54, 0x75, 0xd4, 0x0a, 0xa4, 0x05, 0x45, 0x55, 0x95, 0x0a, 0x9a, 0x04, 0x55, 0x44, 0xb5, 0x04, 0x6a, 0x82, 0x6a, 0x05, 0xd2, 0x0a, 0x92, 0x6a, 0x4a, 0x05, 0x55, 0x0a, 0x2a, 0x4a, 0x5a, 0x02, 0xb5, 0x02, 0x31, 0x69, 0x31, 0x73, 0xa9, 0x0a, 0x4a, 0x05, 0x2d, 0x55, 0x2d, 0x09, 0x5a, 0x01, 0xd5, 0x48, 0xb4, 0x09, 0x68, 0x89, 0x54, 0x0b, 0xa4, 0x0a, 0xa5, 0x6a, 0x95, 0x04, 0xad, 0x08, 0x6a, 0x44, 0xda, 0x04, 0x74, 0x05, 0xb0, 0x25, 0x54, 0x03 }; private String getChineseTerm() { if (get(Calendar.DATE) == get(CHINESE_SECTIONAL_TERM)) { return sectionalTermNames[get(Calendar.MONTH)]; } else if (get(Calendar.DATE) == get(CHINESE_PRINCIPLE_TERM)) { return principleTermNames[get(Calendar.MONTH)]; } else return null; } // add by skywang private String getLunarFestival() { int day = get(CHINESE_DATE); int month = get(CHINESE_MONTH); String sToday = day < 10 ? "0" + day:"" + day; String sMonth = month<10 ? "0" +(month):"+(month); return lFestival.get(sMonth+sToday); } private String getSolarFestival() { int day = get(Calendar.DATE); int month = get(Calendar.MONTH); String sToday = day < 10 ? "0" + day:"" + day; String sMonth = month<10 ? "0" +(month+1):"+(month+1); return sFestival.get(sMonth+sToday); } private String getFestivalOrTermOrDate() { String ret; if ((ret = getSolarFestival()) != null) return ret; if ((ret = getLunarFestival()) != null) return ret; return getChinese(get(CHINESE_TERM_OR_DATE)); } //Gregorian festival private static HashMap<String,String> sFestival =new HashMap<String,String>(); // Lunar intervene private static HashMap<String,String> lFestival =new HashMap<String,String>(); static { sFestival.put("0101","New Year's Day"); sFestival.put("0214","Valenteen Day"); sFestival.put("0308","Women's Day"); sFestival.put("0312","Arbor Day"); sFestival.put("0401","April's Day"); sFestival.put("0501","Labor Day"); sFestival.put("0504","Youth Day"); sFestival.put("0601","Children's Day"); sFestival.put("0701","Centering Day"); sFestival.put("0801","Army Day"); sFestival.put("0910","Teacher's Day"); sFestival.put("1001","National Day"); sFestival.put("1031","Halloween"); // sFestival.put("1112","Birthday of Sun Yat-sen"); sFestival.put("1225","Christmas"); lFestival.put("0101","Spring Festival"); // lFestival.put("0102","Quan 2"); // lFestival.put("0103","Quan 3"); lFestival.put("0115","Lantern Festival"); lFestival.put("0505","Dragon Boat Festival"); lFestival.put("0707","Qianxi Festival"); lFestival.put("0815","Mid-Autumn Festival"); lFestival.put("0909","Dongyang Festival"); lFestival.put("1208","Laba Festival"); // lFestival.put("1299","New Year's Eve"); } }