先献上我靠这个日历算法最终完成的一款简易日历App(相信找这个算法的人应该也在为实现一个日历而头疼吧哈哈)
结合网上的农历算法,完善了关于节假日的部分
(其中
public String getLunarDate(int year_log, int month_log, int day_log, boolean isday)
是核心函数)
注意:lunarHoliday 和 solarHoliday 里面的每一个节假日中一定要有一个空格来分隔日期和节假日名称!
package com.wuchang.wccalendar;
/**
* Created by WuchangI on 2017/8/10.
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* 农历算法
*
*/
public class LunarCalendar
{
private int year; // 农历的年份
private int month;
private int day;
private String lunarMonth; // 农历的月份
public int leapMonth = 0; // 闰的是哪个月
final static String chineseNumber[] = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"};
static SimpleDateFormat chineseDateFormat = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);
final static long[] lunarInfo = new long[]{ //
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, //
0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, //
0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, //
0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, //
0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, //
0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, //
0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, //
0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, //
0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, 0x095b0, //
0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, //
0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, //
0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, //
0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, //
0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, //
0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, //
0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0};
// 农历部分假日
final static String[] lunarHoliday = new String[]{"0101 春节", "0105 五末日", "0115 元宵(上元节)", "0202 龙抬头", "0303 鸡蛋节", "0505 端午节",
"0513 雨节", "0601 过半年", "0606 晒衣节", "0707 七夕(乞巧)", "0715 中元节(鬼节)", "0801 天医节", "0815 中秋节", "0909 重阳节", "1015 下元节",
"1208 腊八", "1224 小年", "0100 除夕"};
// 公历部分节假日
final static String[] solarHoliday = new String[]{
"0101 元旦", "0131 国际麻风节","0202 世界湿地日", "0203 立春", "0210 国际气象节", "0214 情人节", "0301 国际海豹日", "0303 全国爱耳日", "0305 学雷锋纪念日",
"0308 妇女节", "0312 植树节", "0315 消费权益保护", "0401 愚人节", "0402 国际儿童图书日", "0403 寒食节", "0404 清明节", "0407 世界卫生日", "0501 劳动节",
"0503 世界哮喘日", "0504 中国青年节", "0508 世界红十字日", "0512 国际护士节", "0514 母亲节", "0601 国际儿童节", "0605 芒种", "0606 世界爱眼日", "0611 中国文化遗产日",
"0618 父亲节", "0701 建党节", "0707 小暑", "0711 世界人口日", "0801 建军节", "0807 立秋", "0823 处暑", "0903 抗战纪念日", "0907 白露", "0908 国际扫盲日", "0910 教师节",
"0928 孔子诞辰", "1001 国庆", "1004 世界动物日", "1008 寒露", "1101 万圣节", "1107 立冬", "1108 世界记者日", "1109 消防宣传日", "1111 光棍节", "1112 孙中山诞辰",
"1201 世界艾滋病日", "1203 国际残疾人日", "1207 大雪", "1209 世界足球日", "1213 南京大屠杀纪念日", "1220 澳门回归纪念日", "1225 圣诞节"};
/**
* 传回农历 y年的总天数
*
* @param y 年份
* @return 该年的总天数
*/
private static int yearDays(int y)
{
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1)
{
if ((lunarInfo[y - 1900] & i) != 0)
sum += 1;
}
return (sum + leapDays(y));
}
/**
* 传回农历 y年闰月的天数
*
* @param y 年份
* @return 改年闰月天数
*/
private static int leapDays(int y)
{
if (leapMonth(y) != 0)
{
if ((lunarInfo[y - 1900] & 0x10000) != 0)
return 30;
else
return 29;
} else
return 0;
}
/**
* 传回农历 y年闰哪个月 1-12 , 没闰传回 0
*
* @param y 年份
* @return 改年闰月的月数
*/
private static int leapMonth(int y)
{
return (int) (lunarInfo[y - 1900] & 0b1111);
}
/**
* 传回农历 y年m月的总天数
*
* @param y 年份
* @param m 月份
* @return 该月份的总天数
*/
private static int monthDays(int y, int m)
{
if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)
return 29;
else
return 30;
}
/**
* 传回农历 y年的生肖
*
* @param year 年份
* @return 生肖
*/
public String animalsYear(int year)
{
final String[] Animals = new String[]{"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};
return Animals[(year - 4) % 12];
}
/**
* 传入 月日的offset 传回干支, 0=甲子
*/
private static String cyclicalm(int num)
{
final String[] Gan = new String[]{"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
final String[] Zhi = new String[]{"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
return (Gan[num % 10] + Zhi[num % 12]);
}
/**
* 传入 offset 传回干支, 0=甲子
*/
public String cyclical(int year)
{
int num = year - 1900 + 36;
return (cyclicalm(num));
}
public static String getChinaDayString(int day)
{
String chineseTen[] = {"初", "十", "廿", "卅"};
int n = day % 10 == 0 ? 9 : day % 10 - 1;
if (day > 30)
return "";
if (day == 10)
return "初十";
else
return chineseTen[day / 10] + chineseNumber[n];
}
/**
* 传出y年m月d日对应的农历. yearCyl3:农历年与1864的相差数 ? monCyl4:从1900年1月31日以来,闰月数
* dayCyl5:与1900年1月31日相差的天数,再加40 ?
* <p/>
* isday: 这个参数为false---日期为节假日时,阴历日期就返回节假日 ,true---不管日期是否为节假日依然返回这天对应的阴历日期
*
* @return
*/
public String getLunarDate(int year_log, int month_log, int day_log,
boolean isday)
{
// @SuppressWarnings("unused")
int yearCyl, monCyl, dayCyl;
// int leapMonth = 0;
String nowadays;
Date baseDate = null;
Date nowaday = null;
try
{
baseDate = chineseDateFormat.parse("1900年1月31日");
} catch (ParseException e)
{
e.printStackTrace(); // To change body of catch statement use
// Options | File Templates.
}
nowadays = year_log + "年" + month_log + "月" + day_log + "日";
try
{
nowaday = chineseDateFormat.parse(nowadays);
} catch (ParseException e)
{
e.printStackTrace(); // To change body of catch statement use
// Options | File Templates.
}
// 求出和1900年1月31日相差的天数
int offset = (int) ((nowaday.getTime() - baseDate.getTime()) / 86400000L);
dayCyl = offset + 40;
monCyl = 14;
// 用offset减去每农历年的天数
// 计算当天是农历第几天
// i最终结果是农历的年份
// offset是当年的第几天
int iYear, daysOfYear = 0;
for (iYear = 1900; iYear < 10000 && offset > 0; iYear++)
{
daysOfYear = yearDays(iYear);
offset -= daysOfYear;
monCyl += 12;
}
if (offset < 0)
{
offset += daysOfYear;
iYear--;
monCyl -= 12;
}
// 农历年份
year = iYear;
setYear(year); // 设置公历对应的农历年份
yearCyl = iYear - 1864;
leapMonth = leapMonth(iYear); // 闰哪个月,1-12
boolean leap = false;
// 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
int iMonth, daysOfMonth = 0;
for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++)
{
// 闰月
if (leapMonth > 0 && iMonth == (leapMonth + 1) && !leap)
{
--iMonth;
leap = true;
daysOfMonth = leapDays(year);
} else
daysOfMonth = monthDays(year, iMonth);
offset -= daysOfMonth;
// 解除闰月
if (leap && iMonth == (leapMonth + 1))
leap = false;
if (!leap)
monCyl++;
}
// offset为0时,并且刚才计算的月份是闰月,要校正
if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1)
{
if (leap)
{
leap = false;
} else
{
leap = true;
--iMonth;
--monCyl;
}
}
// offset小于0时,也要校正
if (offset < 0)
{
offset += daysOfMonth;
--iMonth;
--monCyl;
}
month = iMonth;
setLunarMonth(chineseNumber[month - 1] + "月"); // 设置对应的阴历月份
day = offset + 1;
if (!isday)
{
// 如果日期为节假日则阴历日期则返回节假日
// setLeapMonth(leapMonth);
for (int i = 0; i < solarHoliday.length; i++)
{
// 返回公历节假日名称
String sd = solarHoliday[i].split(" ")[0]; // 节假日的日期
String sdv = solarHoliday[i].split(" ")[1]; // 节假日的名称
String smonth_v = month_log + "";
String sday_v = day_log + "";
String smd = "";
if (month_log < 10)
{
smonth_v = "0" + month_log;
}
if (day_log < 10)
{
sday_v = "0" + day_log;
}
smd = smonth_v + sday_v;
if (sd.trim().equals(smd.trim()))
{
return sdv;
}
}
for (int i = 0; i < lunarHoliday.length; i++)
{
// 返回农历节假日名称
String ld = lunarHoliday[i].split(" ")[0]; // 节假日的日期
String ldv = lunarHoliday[i].split(" ")[1]; // 节假日的名称
String lmonth_v = month + "";
String lday_v = day + "";
String lmd = "";
if (month < 10)
{
lmonth_v = "0" + month;
}
if (day < 10)
{
lday_v = "0" + day;
}
lmd = lmonth_v + lday_v;
if (ld.trim().equals(lmd.trim()))
{
return ldv;
}
}
}
if (day == 1)
return chineseNumber[month - 1] + "月";
else
return getChinaDayString(day);
}
public String toString()
{
if (chineseNumber[month - 1] == "一" && getChinaDayString(day) == "初一")
return "农历" + year + "年";
else if (getChinaDayString(day) == "初一")
return chineseNumber[month - 1] + "月";
else
return getChinaDayString(day);
// return year + "年" + (leap ? "闰" : "") + chineseNumber[month - 1] +
// "月" + getChinaDayString(day);
}
//
// public static void main(String[] args) {
// System.out.println(new
// LunarCalendar().getLunarDate(2012, 1, 23));
// }
public int getLeapMonth()
{
return leapMonth;
}
public void setLeapMonth(int leapMonth)
{
this.leapMonth = leapMonth;
}
/**
* 得到当前日期对应的阴历月份
*
* @return
*/
public String getLunarMonth()
{
return lunarMonth;
}
public void setLunarMonth(String lunarMonth)
{
this.lunarMonth = lunarMonth;
}
/**
* 得到当前年对应的农历年份
*
* @return
*/
public int getYear()
{
return year;
}
public void setYear(int year)
{
this.year = year;
}
}