本章主要是收藏一些常用的類和接口,包括:萬年歷(農歷、陽歷節日、陰歷節日)、自定義的Calendar接口。
萬年歷
源碼如下(ChineseCalendar.java):
package com.via.mce.monthcalendar.utils;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
/**
* 農歷日歷。<br>
* 將農歷從1901年到2100年之間各年、月的大小以及歷年節氣保存,然後基於這些數據進行計算。<br>
* <br>
* 新增了幾個用於農歷的常量屬性字段,可以使用get()方法獲取日歷對應的值;<br>
* 農歷年、月、日還可以使用set()/add()/roll()方法設置,其他農歷屬性自動計算;<br>
* 另外,還提供了getChinese(int field)方法用於獲得農歷的中文文字(僅適用於農歷屬性和星期)。<br>
* <ul>
* <li>CHINESE_YEAR - 農歷年</li>
* <li>CHINESE_MONTH - 農歷月</li>
* <li>CHINESE_DATE - 農歷日</li>
* <li>CHINESE_SECTIONAL_TERM - 當月的節氣</li>
* <li>CHINESE_PRINCIPLE_TERM - 當月的中氣</li>
* <li>CHINESE_HEAVENLY_STEM - 農歷年的天干</li>
* <li>CHINESE_EARTHLY_BRANCH - 農歷年的地支</li>
* <li>CHINESE_ZODIAC - 農歷年的屬相</li>
* <li>CHINESE_TERM_OR_DATE - 如果當天存在一個節氣則指示節氣,否則如果當天是初一則指示農歷月,否則指示農歷日</li>
* </ul>
* 注意:<br>
* 由於Calendar類的設定,公歷月份從0起始。所有方法都遵循了這一約定。<br>
* 但所有的農歷屬性從1起始。即使是在Calendar提供的方法中,農歷月也是從1起始的,並以負數表示閏月。<br>
* clear()方法在某些情況下會導致農歷和公歷日期不對應或是不能達到預期的重置效果,應盡量避免使用。<br>
* 使用getSimpleDateString()獲得公歷日期字符串時,公歷月已經修正;<br>
* 使用getSimpleChineseDateString()獲得農歷日期字符串時,農歷閏月以*表示。<br>
*
* @version 0.12 2011-9-5 <br>
* <blockquote>修復一個當使用農歷正月日期初始化日歷時陷入死循環的問題。</blockquote>
* @version 0.11 2009-12-27 <br>
* <blockquote>修復了獲取中文農歷時未計算農歷日期的問題;<br>
* 加入一個字段CHINESE_TERM_OR_DATE用於模仿台歷的顯示方式:如果當天有節氣則指示節氣,如果是初一指示農歷月,
* 否則指示農歷日。</blockquote>
* @version 0.10 2009-12-22
*/
public final class ChineseCalendar extends GregorianCalendar {
private static final long serialVersionUID = 8L;
/** 農歷年 */
public static final int CHINESE_YEAR = 801;
/** 農歷月 */
public static final int CHINESE_MONTH = 802;
/** 農歷日 */
public static final int CHINESE_DATE = 803;
/** 當月的節氣對應的公歷日(前一個節氣) */
public static final int CHINESE_SECTIONAL_TERM = 804;
/** 當月的中氣對應的公歷日(後一個節氣) */
public static final int CHINESE_PRINCIPLE_TERM = 805;
/** 天干 */
public static final int CHINESE_HEAVENLY_STEM = 806;
/** 地支 */
public static final int CHINESE_EARTHLY_BRANCH = 807;
/** 農歷年的屬相(生肖) */
public static final int CHINESE_ZODIAC = 808;
/** 節氣或者農歷日 */
public static final int CHINESE_TERM_OR_DATE = 888;
// add by skywang
/** 農歷節日 */
public static final int LUNAR_FESTIVAL = 809;
/** 陽歷節日 */
public static final int SOLAR_FESTIVAL = 810;
/** 節氣 */
public static final int CHINESE_TERM = 811;
/** 月或者農歷日 */
public static final int CHINESE_MONTH_OR_DATE = 812;
/** 節日 或 節氣 或 農歷日 */
public static final int FESTIVAL_OR_TERM_OR_DATE = 813;
private int chineseYear;
private int chineseMonth; // 1起始,負數表示閏月
private int chineseDate;
private int sectionalTerm; // 當月節氣的公歷日
private int principleTerm; // 當月中氣的公歷日
private boolean areChineseFieldsComputed; // 農歷日期是否已經經過計算確認
private boolean areSolarTermsComputed; // 節氣是否已經經過計算確認
private boolean lastSetChinese; // 最後設置的是不是農歷屬性
// 查看本欄目
自定義的Calendar接口
這些接口在寫日歷程序時可能會用到。
源代碼如下(CalendarSelfDefineTest.java):
import java.util.Calendar;
/**
* 根據Calendar的API封裝的一些常用函數
*
* @author skywang
* @email kuiwu-wang@163.com
*/
public class CalendarSelfDefineTest {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
// 設置日期為“2013-09-18”
cal.set(2013, Calendar.SEPTEMBER, 18);
// 獲取“年”
System.out.printf("year: %s\n", getYear(cal) );
// 獲取“月”
System.out.printf("month: %s\n", getMonth(cal) );
// 獲取“上月”
System.out.printf("previcou month: %s\n", getLastMonth(cal) );
// 獲取“下月”
System.out.printf("next month: %s\n", getNextMonth(cal) );
// 獲取“日”
System.out.printf("day: %s\n", getDay(cal) );
// 獲取Cal對應星期幾
System.out.printf("weekday: %s\n", getWeekDay(cal) );
// 本月天數
System.out.printf("Current Month days: %s\n", getMonthDays(cal) );
// 上月天數
System.out.printf("Previcous Month days: %s\n", getPrevMonthDays(cal) );
// 下月天數
System.out.printf("Next Month days: %s\n", getNextMonthDays(cal) );
// 獲取當月第一天的星期幾
System.out.printf("First day' weekday : %s\n", getFirstDayWeekday(cal) );
// 獲取當前月最後一天的星期幾
System.out.printf("Last day' weekday : %s\n", getLastDayWeekday(cal) );
// 獲取上月最後一天的星期幾
System.out.printf("PrevMonth Last day' weekday: %s\n", getLastDayWeekdayOfPrevMonth(cal) );
// 獲取下月第一天的星期幾
System.out.printf("NextMonth First day' weekday: %s\n", getFirstDayWeekdayOfNextMonth(cal) );
}
/**
* 獲取“年”
*
* @return 例如,2013-09-18,則返回2013
*/
public static int getYear(Calendar cal) {
return cal.get(Calendar.YEAR);
}
/**
* 獲取“月”
*
* @return 返回值可以為以下值:
* JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
* 其中第一個月是 JANUARY,它為 0。
*
* 例如,2013-09-18,則返回8
*/
public static int getMonth(Calendar cal) {
return cal.get(Calendar.MONTH);
}
/**
* 獲取“上一個月”
*
* @return 返回值可以為以下值:
* JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
* 其中第一個月是 JANUARY,它為 0。
*
* 例如,2012-01-12的上一個月是“11”(即DECEMBER)。
*/
public static int getLastMonth(Calendar cal) {
return (cal.get(Calendar.MONTH) + 11) % 12;
}
/**
* 獲取“下一個月”
*
* @return 返回值可以為以下值:
* JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
* 其中第一個月是 JANUARY,它為 0。
*
* 例如,2013-12-12的下一個月是“1”(即DECEMBER)。
*/
public static int getNextMonth(Calendar cal) {
return (cal.get(Calendar.MONTH) + 13) % 12;
}
/**
* 獲取“日”
*
* @return 例如,2013-09-18,則返回18
*
*/
public static int getDay(Calendar cal) {
return cal.get(Calendar.DATE);
}
/**
* 獲取“本月的天數”
*
* @return 例如,2013-09-18,則返回30
*
*/
public static int getMonthDays(Calendar cal) {
return cal.getActualMaximum(Calendar.DATE);
}
/**
* 獲取“上一個月的天數”
*
* @return 例如,2013-01-18,則返回31 (因為2012-12有31天)
*
*/
public static int getPrevMonthDays(Calendar cal) {
Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。後面對tmpCal操作,就不會改變cal
tmpCal.add(Calendar.MONTH, -1); // 設為“上一個月”
return tmpCal.getActualMaximum(Calendar.DATE);
}
/**
* 獲取“下一個月的天數”
*
* @return 例如,2013-12-18,則返回31 (因為2014-01有31天)
*
*/
public static int getNextMonthDays(Calendar cal) {
Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。後面對tmpCal操作,就不會改變cal
tmpCal.add(Calendar.MONTH, 1); // 設為“下一個月”
return tmpCal.getActualMaximum(Calendar.DATE);
}
/**
* 獲取Cal對應星期幾
*
* @return 返回“星期幾”,可以為以下值:
* SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY 和 SATURDAY。
* SUNDAY為1,MONDAY為2,依次類推。
* 例如,2013-09-18(星期三),則返回4
*/
public static int getWeekDay(Calendar cal) {
return cal.get(Calendar.DAY_OF_WEEK);
}
/**
* 獲取當月第一天對應星期幾
*
* @return SUNDAY為1,MONDAY為2,依次類推。
*/
public static int getFirstDayWeekday(Calendar cal) {
Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。後面對tmpCal操作,就不會改變cal
tmpCal.set(Calendar.DATE, 1); // 把日期設置為當月第一天
return tmpCal.get(Calendar.DAY_OF_WEEK);
}
/**
* 獲取當前月最後一天對應星期幾
*
* @return SUNDAY為1,MONDAY為2,依次類推。
*/
public static int getLastDayWeekday(Calendar cal) {
Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。後面對tmpCal操作,就不會改變cal
tmpCal.set(Calendar.DATE, 1); // 把日期設置為當月第一天
tmpCal.roll(Calendar.DATE, -1); // 把日期設置為當月最後一天
return tmpCal.get(Calendar.DAY_OF_WEEK);
}
/**
* 獲取上月最後一天的星期幾
*
* @return SUNDAY為1,MONDAY為2,依次類推。
*/
public static int getLastDayWeekdayOfPrevMonth(Calendar cal) {
Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。後面對tmpCal操作,就不會改變cal
tmpCal.set(Calendar.DATE, 1); // 把日期設置為當月第一天
tmpCal.add(Calendar.DATE, -1); // 把日期設置為上一個月最後一天
return tmpCal.get(Calendar.DAY_OF_WEEK);
}
/**
* 獲取下月第一天的星期偏移
*
* @return SUNDAY為1,MONDAY為2,依次類推。
*/
public static int getFirstDayWeekdayOfNextMonth(Calendar cal) {
Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。後面對tmpCal操作,就不會改變cal
tmpCal.add(Calendar.MONTH, 1); // 設為“下一個月”
tmpCal.set(Calendar.DATE, 1); // 設為“第一天”
return tmpCal.get(Calendar.DAY_OF_WEEK);
}
}