パッケージcom.huawei.test。
輸入java.text.DateFormatの。
輸入java.text.ParseException。
輸入java.text.SimpleDateFormatの。
インポートのjava.util.Calendar;
輸入java.util.Date;
輸入java.util.GregorianCalendar;
インポートのjava.util.TimeZone;
パブリッククラスLunar2 {
プライベートカレンダー太陽。
プライベートint型lunarYear。
プライベートint型朔望月。
プライベートint型lunarDay。
プライベートブールISLEAPYEAR。
プライベートブールisLeap。
プライベートint型maxDayInMonth = 29;
民間最終静的INT [] lunarInfo = {
0x4bd8、0x4ae0、0xa570、0x54d5、0xd260、0xd950、0x5554、0x56af、
0x9ad0、0x55d2、0x4ae0、0xa5b6、0xa4d0、0xd250、0xd295、0xb54f、
0xd6a0、0xada2、0x95b0、0x4977、0x497f 、0xa4b0、0xb4b5、0x6a50、
0x6d40、0xab54、0x2b6f、0x9570、0x52f2、0x4970、0x6566、0xd4a0、
0xea50、0x6a95、0x5adf、0x2b60、0x86e3、0x92ef、0xc8d7、0xc95f、
0xd4a0、0xd8a6、0xb55f、0x56a0、0xa5b4、0x25df 、0x92d0、0xd2b2、
0xa950、0xb557、0x6ca0、0xb550、0x5355、0x4daf、0xa5b0、0x4573、
0x52bf、0xa9a8、0xe950、0x6aa0、0xaea6、0xab50、0x4b60、0xaae4、
0xa570、0x5260、0xf263、0xd950、0x5b57、0x56a0、0x96d0、0x4dd5、
0x4ad0、 0xa4d0、0xd4d4、0xd250、0xd558、0xb540、0xb6a0、0x95a6、
0x95bf、0x49b0、0xa974、0xa4b0、0xb27a、0x6a50、0x6d40、0xaf46、
0xab60、0x9570、0x4af5、0x4970、0x64b0、0x74a3、0xea50、0x6b58、
0x5ac0、0xab60、 0x96d5、0x92e0、0xc960、0xd954、0xd4a0、0xda50、
0x7552、0x56a0、0xabb7、0x25d0、0x92d0、0xcab5、0xa950、0xb4a0、
0xbaa4、0xad50、0x55d9、0x4ba0、0xa5b0、0x5176、0x52bf、0xa930、
0x7954、0x6aa0、0xad50、 0x5b52、0x4b60、0xa6e6、0xa4e0、0xd260、
0xea65、0xd530、0x5aa0、0x76a3、0x96d0、0x4afb、0x4ad0、0xa4d0、
0xd0b6、0xd25f、0xd520、0xdd45、0xb5a0、0x56d0、0x55b2、0x49b0、
0xa577、0xa4b0、0xaa50、0xb255、0x6d2f、0xada0、0x4b63、0x937f、
0x49f8、0x4970、0x64b0、0x68a6、0xea5f、0x6b20、0xa6c4、0xaaef、
0x92e0、 0xd2e3、0xc960、0xd557、0xd4a0、0xda50、0x5d55、0x56a0、
0xa6d0、0x55d4、0x52d0、0xa9b8、0xa950、0xb4a0、0xb6a6、0xad50、
0x55a0、0xaba4、0xa5b0、0x52b0、0xb273、0x6930、0x7337、0x6aa0、
0xad50、0x4b55、 0x4b6f、0xa570、0x54e4、0xd260、0xe968、0xd520、
0xdaa0、0x6aa6、0x56df、0x4ae0、0xa9d4、0xa4d0、0xd150、0xf252、0xd520
}。
private int solarYear;
private int solarMonth;
private int solarDay;
private int cyclicalYear = 0;
private int cyclicalMonth = 0;
private int cyclicalDay = 0;
private final static int[] solarTermInfo = {
0, 21208, 42467, 63836, 85337, 107014, 128867, 150921,
173149, 195551, 218072, 240693, 263343, 285989, 308563, 331033,
353350, 375494, 397447, 419210, 440795, 462224, 483532, 504758
};
private static GregorianCalendar utcCal = null;
public final static String[] Tianan = {
"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"
};
public final static String[] Deqi = {
"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"
};
//总方法
public static void main(String args[]) throws ParseException {
DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd");
Date date = fmt.parse("1990-08-20");
Lunar2 l = new Lunar2(date);
// System.out.println("节气:" + l.getTermString());
System.out.println("干支历:" + l.getCyclicalDateString());
}
/**
* 通过 Date 对象构建农历信息
*
* @param date 指定日期对象
*/
public Lunar2(Date date) {
if (date == null) {
date = new Date();
}
this.init(date.getTime());
}
/**
* 通过 TimeInMillis 构建农历信息
*
* @param TimeInMillis
*/
public Lunar2(long TimeInMillis) {
this.init(TimeInMillis);
}
private void init(long TimeInMillis) {
this.solar = Calendar.getInstance();
this.solar.setTimeInMillis(TimeInMillis);
Calendar baseDate = new GregorianCalendar(1900, 0, 31);
long offset = (TimeInMillis - baseDate.getTimeInMillis()) / 86400000;
// 按农历年递减每年的农历天数,确定农历年份
this.lunarYear = 1900;
int daysInLunarYear = Lunar2.getLunarYearDays(this.lunarYear);
while (this.lunarYear < 2100 && offset >= daysInLunarYear) {
offset -= daysInLunarYear;
daysInLunarYear = Lunar2.getLunarYearDays(++this.lunarYear);
}
// 农历年数字
// 按农历月递减每月的农历天数,确定农历月份
int lunarMonth = 1;
// 所在农历年闰哪个月,若没有返回0
int leapMonth = Lunar2.getLunarLeapMonth(this.lunarYear);
// 是否闰年
this.isLeapYear = leapMonth > 0;
// 闰月是否递减
boolean leapDec = false;
boolean isLeap = false;
int daysInLunarMonth = 0;
while (lunarMonth < 13 && offset > 0) {
if (isLeap && leapDec) { // 如果是闰年,并且是闰月
// 所在农历年闰月的天数
daysInLunarMonth = Lunar2.getLunarLeapDays(this.lunarYear);
leapDec = false;
} else {
// 所在农历年指定月的天数
daysInLunarMonth = Lunar2.getLunarMonthDays(this.lunarYear, lunarMonth);
}
if (offset < daysInLunarMonth) {
break;
}
offset -= daysInLunarMonth;
if (leapMonth == lunarMonth && isLeap == false) {
// 下个月是闰月
leapDec = true;
isLeap = true;
} else {
// 月份递增
lunarMonth++;
}
}
this.maxDayInMonth = daysInLunarMonth;
// 农历月数字
this.lunarMonth = lunarMonth;
// 是否闰月
this.isLeap = (lunarMonth == leapMonth && isLeap);
// 农历日数字
this.lunarDay = (int) offset + 1;
// 取得干支历
this.getCyclicalData();
}
/**
* 返回农历年的总天数
* 114-162 目的是求农历的总天数
* @param lunarYear 指定农历年份(数字)
* @return 该农历年的总天数(数字)
*/
private static int getLunarYearDays(int lunarYear) {
// 按小月计算,农历年最少有12 * 29 = 348天
int daysInLunarYear = 348;
// 数据表中,每个农历年用16bit来表示,
// 前12bit分别表示12个月份的大小月,最后4bit表示闰月
// 每个大月累加一天
for (int i = 0x8000; i > 0x8; i >>= 1) {
daysInLunarYear += ((Lunar2.lunarInfo[lunarYear - 1900] & i) != 0) ? 1
: 0;
}
// 加上闰月天数
daysInLunarYear += Lunar2.getLunarLeapDays(lunarYear);
return daysInLunarYear;
}
/**
* 返回农历年闰月的天数
*
* @param lunarYear 指定农历年份(数字)
* @return 该农历年闰月的天数(数字)
*/
private static int getLunarLeapDays(int lunarYear) {
// 下一年最后4bit为1111,返回30(大月)
// 下一年最后4bit不为1111,返回29(小月)
// 若该年没有闰月,返回0
return Lunar2.getLunarLeapMonth(lunarYear) > 0 ? ((Lunar2.lunarInfo[lunarYear - 1899] & 0xf) == 0xf ? 30
: 29)
: 0;
}
/**
* 返回农历年闰月月份
*
* @param lunarYear 指定农历年份(数字)
* @return 该农历年闰月的月份(数字,没闰返回0)
*/
private static int getLunarLeapMonth(int lunarYear) {
// 数据表中,每个农历年用16bit来表示,
// 前12bit分别表示12个月份的大小月,最后4bit表示闰月
// 若4bit全为1或全为0,表示没闰, 否则4bit的值为闰月月份
int leapMonth = Lunar2.lunarInfo[lunarYear - 1900] & 0xf;
leapMonth = (leapMonth == 0xf ? 0 : leapMonth);
return leapMonth;
}
/**
* 返回农历年正常月份的总天数
*
* @param lunarYear 指定农历年份(数字)
* @param lunarMonth 指定农历月份(数字)
* @return 该农历年闰月的月份(数字,没闰返回0)
*/
private static int getLunarMonthDays(int lunarYear, int lunarMonth) {
// 数据表中,每个农历年用16bit来表示,
// 前12bit分别表示12个月份的大小月,最后4bit表示闰月
int daysInLunarMonth = ((Lunar2.lunarInfo[lunarYear - 1900] & (0x10000 >> lunarMonth)) != 0) ? 30
: 29;
return daysInLunarMonth;
}
/**
* 取干支历 不是历年,历月干支,而是中国的从立春节气开始的节月,是中国的太阳十二宫,阳历的。
*
* @param cncaData 日历对象(Tcnca)
*/
private void getCyclicalData() {
this.solarYear = this.solar.get(Calendar.YEAR);
this.solarMonth = this.solar.get(Calendar.MONTH);
this.solarDay = this.solar.get(Calendar.DAY_OF_MONTH);
// 干支历
int cyclicalYear = 0;
int cyclicalMonth = 0;
int cyclicalDay = 0;
int cyclicalHour = 0;
// 干支年 1900年立春後为庚子年(60进制36)
int term2 = Lunar2.getSolarTermDay(solarYear, 2); // 立春日期
// 依节气调整二月分的年柱, 以立春为界
if (solarMonth < 1 || (solarMonth == 1 && solarDay < term2)) {
cyclicalYear = (solarYear - 1900 + 36 - 1) % 60;
} else {
cyclicalYear = (solarYear - 1900 + 36) % 60;
}
// 干支月 1900年1月小寒以前为 丙子月(60进制12)
int firstNode = Lunar2.getSolarTermDay(solarYear, solarMonth * 2); // 传回当月「节」为几日开始
// 依节气月柱, 以「节」为界
if (solarDay < firstNode) {
cyclicalMonth = ((solarYear - 1900) * 12 + solarMonth + 12) % 60;
} else {
cyclicalMonth = ((solarYear - 1900) * 12 + solarMonth + 13) % 60;
}
// 当月一日与 1900/1/1 相差天数
// 1900/1/1与 1970/1/1 相差25567日, 1900/1/1 日柱为甲戌日(60进制10)
cyclicalDay = (int) (Lunar2.UTC(solarYear, solarMonth, solarDay, 0, 0, 0) / 86400000 + 25567 + 10) % 60;
this.cyclicalYear = cyclicalYear;
this.cyclicalMonth = cyclicalMonth;
this.cyclicalDay = cyclicalDay;
}
/**
* 返回公历年节气的日期
*
* @param solarYear 指定公历年份(数字)
* @param index 指定节气序号(数字,0从小寒算起)
* @return 日期(数字,所在月份的第几天)
*/
private static int getSolarTermDay(int solarYear, int index) {
return Lunar.getUTCDay(getSolarTermCalendar(solarYear, index));
}
/**
* 返回公历年节气的日期
*
* @param solarYear 指定公历年份(数字)
* @param index 指定节气序号(数字,0从小寒算起)
* @return 日期(数字,所在月份的第几天)
*/
public static Date getSolarTermCalendar(int solarYear, int index) {
long l = (long) 31556925974.7 * (solarYear - 1900)
+ solarTermInfo[index] * 60000L;
l = l + Lunar.UTC(1900, 0, 6, 2, 5, 0);
return new Date(l);
}
/**
* 返回全球标准时间 (UTC) (或 GMT) 的 1970 年 1 月 1 日到所指定日期之间所间隔的毫秒数。
*
* @param y 指定年份
* @param m 指定月份
* @param d 指定日期
* @param h 指定小时
* @param min 指定分钟
* @param sec 指定秒数
* @return 全球标准时间 (UTC) (或 GMT) 的 1970 年 1 月 1 日到所指定日期之间所间隔的毫秒数
*/
public static synchronized long UTC(int y, int m, int d, int h, int min, int sec) {
Lunar2.makeUTCCalendar();
synchronized (utcCal) {
utcCal.clear();
utcCal.set(y, m, d, h, min, sec);
return utcCal.getTimeInMillis();
}
}
private static synchronized void makeUTCCalendar() {
if (Lunar2.utcCal == null) {
Lunar2.utcCal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
}
}
//----------------------------------------------------干支历
/**
* 取得干支历字符串
*
* @return 干支历字符串(例:甲子年甲子月甲子日)
*/
public String getCyclicalDateString() {
this.getCyclicaMonth();
String s = "巳";
String hours = null;
//判断时辰
String hour = getCyclicaDay().substring(0,1);
if (hour.equals("甲")||hour.equals("己")) {
String[] hor = {"甲子","乙丑","丙寅","丁卯","戊辰","己巳","庚午","辛未","壬申","癸酉","甲戌","乙亥"};
for(String a : hor) {
if(a.substring(1, 2).equals(s)) {
hours = a;
}
}
}else if (hour.equals("乙")||hour.equals("庚")) {
String[] hor = {"丙子","丁丑","戊寅","己卯","庚辰","辛巳","壬午","癸未","甲申","乙酉","丙戌","丁亥"};
for(String a : hor) {
if(a.substring(1, 2).equals(s)) {
hours = a;
}
}
}else if (hour.equals("丙")||hour.equals("辛")) {
String[] hor = {"戊子","己丑","庚寅","辛卯","壬辰","癸巳","甲午","乙未","丙申","丁酉","戊戌","己亥"};
for(String a : hor) {
if(a.substring(1, 2).equals(s)) {
hours = a;
}
}
}else if (hour.equals("丁")||hour.equals("壬")) {
String[] hor = {"庚子","辛丑","壬寅","癸卯","甲辰","乙巳","丙午","丁未","戊申","己酉","庚戌","辛亥"};
for(String a : hor) {
if(a.substring(1, 2).equals(s)) {
hours = a;
}
}
}else {
String[] hor = {"壬子","癸丑","甲寅","乙卯","丙辰","丁巳","戊午","己未","庚申","辛酉","壬戌","癸亥"};
for(String a : hor) {
if(a.substring(1, 2).equals(s)) {
hours = a;
}
}
}
return this.getCyclicaYear() + "年" + this.getCyclicaMonth() + "月"
+ this.getCyclicaDay() + "日"+hours+"时";
}
/**
* 取得干支月字符串
*
* @return 干支月字符串
*/
public String getCyclicaMonth() {
return Lunar2.getCyclicalString(this.cyclicalMonth);
}
/**
* 干支字符串
*
* @param cyclicalNumber 指定干支位置(数字,0为甲子)
* @return 干支字符串
*/
private static String getCyclicalString(int cyclicalNumber) {
return Lunar2.Tianan[Lunar2.getTianan(cyclicalNumber)] + Lunar2.Deqi[Lunar2.getDeqi(cyclicalNumber)];
}
/**
* 获得天干
*
* @param cyclicalNumber
* @return 天干 (数字)
*/
private static int getTianan(int cyclicalNumber) {
return cyclicalNumber % 10;
}
/**
* 获得地支
*
* @param cyclicalNumber
* @return 地支 (数字)
*/
private static int getDeqi(int cyclicalNumber) {
return cyclicalNumber % 12;
}
/**
* 取得干支年字符串
*
* @return 干支年字符串
*/
public String getCyclicaYear() {
return Lunar2.getCyclicalString(this.cyclicalYear);
}
/**
* 取得干支日字符串
*
* @return 干支日字符串
*/
public String getCyclicaDay() {
return Lunar2.getCyclicalString(this.cyclicalDay);
}
}