package org.yeshi.utils;
|
|
import java.text.ParseException;
|
import java.text.SimpleDateFormat;
|
import java.util.Calendar;
|
import java.util.Date;
|
|
import javax.script.Invocable;
|
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngineManager;
|
|
import org.yeshi.utils.entity.DateInfo;
|
|
/**
|
* 〈将日期转换为干支历法的年月日时,并计算生肖、阴历、星期几〉
|
*
|
*/
|
public class DateLunarUtil {
|
|
static int[] lunarInfo = new int[] { 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, 0x0a5b0, 0x14573,
|
0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950,
|
0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 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, 0x14b63 };
|
|
static String[] Gan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
|
static String[] Zhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
|
|
static long[] sTermInfo = new long[] { 0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551,
|
218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795, 462224, 483532,
|
504758 };
|
|
final static String chineseNumber[] = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊" };
|
final static String chineseNumber1[] = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" };
|
static SimpleDateFormat chineseDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
|
|
// 当前年
|
private static Integer year;
|
// 当前月
|
private static Integer month;
|
// 当前日
|
private static Integer day;
|
|
// 当前星期几
|
private static String weekDay;
|
// 农历-年
|
private static String lunar_year;
|
// 农历-月
|
private static String lunar_month;
|
// 农历-日
|
private static String lunar_day;
|
|
// 天干地支-年
|
private static String agenary_year;
|
// 天干地支-月
|
private static String agenary_month;
|
// 天干地支-日
|
private static String agenary_day;
|
// 天干地支-时辰
|
private static String agenary_hour;
|
|
/**
|
* 分裂当前成 年、月、日
|
*
|
* @param date
|
*/
|
public static void splitDate(Date date) {
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(date);
|
year = cal.get(Calendar.YEAR);
|
month = cal.get(Calendar.MONTH) + 1;
|
day = cal.get(Calendar.DAY_OF_MONTH);
|
}
|
|
/**
|
* 转换成阴历
|
*
|
* @param date
|
* @return
|
*/
|
public static String toLunar(Date date) {
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(date);
|
|
int leapMonth = 0;
|
Date baseDate = null;
|
try {
|
baseDate = chineseDateFormat.parse("1900年1月31日");
|
} catch (ParseException e) {
|
e.printStackTrace(); // To change body of catch statement use
|
// Options | File Templates.
|
}
|
|
// 求出和1900年1月31日相差的天数
|
int offset = (int) ((cal.getTime().getTime() - baseDate.getTime()) / 86400000L);
|
|
// 用offset减去每农历年的天数
|
// 计算当天是农历第几天
|
// i最终结果是农历的年份
|
// offset是当年的第几天
|
int iYear, daysOfYear = 0;
|
for (iYear = 1900; iYear < 2050 && offset > 0; iYear++) {
|
daysOfYear = lYearDays(iYear);
|
offset -= daysOfYear;
|
}
|
if (offset < 0) {
|
offset += daysOfYear;
|
iYear--;
|
}
|
|
// 农历年份
|
int year = iYear;
|
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;
|
}
|
// offset为0时,并且刚才计算的月份是闰月,要校正
|
if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) {
|
if (leap) {
|
leap = false;
|
} else {
|
leap = true;
|
--iMonth;
|
}
|
}
|
// offset小于0时,也要校正
|
if (offset < 0) {
|
offset += daysOfMonth;
|
--iMonth;
|
}
|
|
lunar_year = chineseNumberYear(iYear) + "年";
|
if (leap) {
|
lunar_month = "闰" + chineseNumber[iMonth - 1] + "月";
|
} else {
|
lunar_month = chineseNumber[iMonth - 1] + "月";
|
}
|
lunar_day = getChinaDayString(offset + 1);
|
return lunar_year + lunar_month + lunar_day;
|
}
|
|
/**
|
* 将年份转换为中文
|
*
|
* @param year
|
* @return
|
*/
|
public static String chineseNumberYear(int year) {
|
String year_str = year + "";
|
String newYear = "";
|
for (int i = 0; i < year_str.length(); i++) {
|
newYear += formatDigit(year_str.charAt(i));
|
}
|
return newYear;
|
}
|
|
|
public static char formatDigit(char sign) {
|
if (sign == '0')
|
sign = '〇';
|
if (sign == '1')
|
sign = '一';
|
if (sign == '2')
|
sign = '二';
|
if (sign == '3')
|
sign = '三';
|
if (sign == '4')
|
sign = '四';
|
if (sign == '5')
|
sign = '五';
|
if (sign == '6')
|
sign = '六';
|
if (sign == '7')
|
sign = '七';
|
if (sign == '8')
|
sign = '八';
|
if (sign == '9')
|
sign = '九';
|
return sign;
|
}
|
|
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 "初十";
|
|
if (day == 20)
|
return "二十";
|
|
if (day == 30)
|
return "三十";
|
|
return chineseTen[day / 10] + chineseNumber1[n];
|
}
|
|
|
/**
|
* 计算输出星期几
|
*
|
* @param weekday
|
* @return
|
*/
|
public static String getChinaWeekdayString(String weekday) {
|
if (weekday.equals("Mon"))
|
return "一";
|
if (weekday.equals("Tue"))
|
return "二";
|
if (weekday.equals("Wed"))
|
return "三";
|
if (weekday.equals("Thu"))
|
return "四";
|
if (weekday.equals("Fri"))
|
return "五";
|
if (weekday.equals("Sat"))
|
return "六";
|
if (weekday.equals("Sun"))
|
return "日";
|
else
|
return "";
|
}
|
|
|
/**
|
* 获取星期几中文
|
*
|
* @param date
|
* @return
|
*/
|
public static String getWeekd(Date date) {
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(date);
|
weekDay = "星期" + getChinaWeekdayString(calendar.getTime().toString().substring(0, 3));
|
return weekDay;
|
}
|
|
|
/**
|
* 返回农历 y年的总天数
|
*
|
* @param y
|
*/
|
public static int lYearDays(int y) {
|
int i, sum = 348;
|
for (i = 0x8000; i > 0x8; i >>= 1) {
|
sum += (lunarInfo[y - 1900] & i) > 0 ? 1 : 0;
|
}
|
return (sum + leapDays(y));
|
}
|
|
|
/**
|
* 返回农历 y年闰月的天数
|
*
|
* @param y
|
* @return
|
*/
|
public static int leapDays(int y) {
|
if (leapMonth(y) > 0) {
|
long day = lunarInfo[y - 1900] & 0x10000;
|
return day > 0 ? 30 : 29;
|
} else
|
return 0;
|
}
|
|
|
/**
|
* 返回农历 y年闰哪个月 1-12 , 没闰返回 0
|
*
|
* @param y
|
* @return
|
*/
|
public static int leapMonth(int y) {
|
return (lunarInfo[y - 1900] & 0xf);
|
}
|
|
|
/**
|
* 返回农历 y年m月的总天数
|
*
|
* @param y
|
* @param m
|
* @return
|
*/
|
public static int monthDays(int y, int m) {
|
return ((lunarInfo[y - 1900] & (0x10000 >> m)) > 0 ? 30 : 29);
|
}
|
|
final public String animalsYear(int year) {
|
final String[] Animals = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
|
return Animals[(year - 4) % 12];
|
}
|
|
// ===== 某年的第n个节气为几日(从0小寒起算) Date.UTC(1900, 0, 6, 2, 5)
|
|
/**
|
* 正确的立春时间应该是以小时来进行计算的
|
*
|
* @param y
|
* @param n
|
* @return
|
*/
|
public static int sTerm(int y, int n) {
|
long times = 31556925974l * (y - 1900) + sTermInfo[n] * 60000l + (long) 0.7 * (y - 1900);
|
Date offDate = new Date(times - 2208549300000l);
|
// 1、取得本地时间:
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(offDate);
|
// 2、取得时间偏移量:
|
int zoneOffset = cal.get(cal.ZONE_OFFSET);
|
// 3、取得夏令时差:
|
int dstOffset = cal.get(cal.DST_OFFSET);
|
// 4、从本地时间里扣除这些差量,即可以取得UTC时间:
|
cal.add(cal.MILLISECOND, -(zoneOffset + dstOffset));
|
// 之后调用cal.get(int x)或cal.getTimeInMillis()方法所取得的时间即是UTC标准时间。
|
return (cal.get(Calendar.DATE));
|
}
|
|
/**
|
* 传入 offset 返回干支, 0=甲子
|
*
|
* @param num
|
* @return
|
*/
|
public static String cyclical(int num) {
|
return (Gan[num % 10] + Zhi[num % 12]);
|
}
|
|
/**
|
* 计算 并 打印 八字
|
*
|
* @param date
|
* @throws ParseException
|
*/
|
public static String horoscope(Date date) throws ParseException {
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(date);
|
|
int y = cal.get(Calendar.YEAR);
|
int m = cal.get(Calendar.MONTH);
|
int i = cal.get(Calendar.DATE) - 1;
|
|
String cY = null;
|
String cM = null;
|
String cD = null;
|
String cH = null;
|
|
// 年柱 1900年立春后为庚子年(60进制36)
|
if (m < 2) {
|
cY = cyclical(y - 1900 + 36 - 1);
|
} else {
|
cY = cyclical(y - 1900 + 36);
|
}
|
int term2 = sTerm(y, 2); // 立春日期
|
// 月柱 1900年1月小寒以前为 丙子月(60进制12)
|
int firstNode = sTerm(y, m * 2); // 返回当月「节」为几日开始
|
cM = cyclical((y - 1900) * 12 + m + 12);
|
int dayCyclical = jlday(y, m);
|
// 依节气调整二月分的年柱, 以立春为界
|
if (m == 1 && (i + 1) >= term2)
|
cY = cyclical(y - 1900 + 36);
|
// 依节气月柱, 以「节」为界
|
if ((i + 1) >= firstNode)
|
cM = cyclical((y - 1900) * 12 + m + 13);
|
// 日柱
|
cD = cyclical(dayCyclical + i);
|
|
// 时柱
|
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
cH = Gan[hourG(cD.substring(0, 1), hour)] + Zhi[hourZ(hour)];
|
|
agenary_year = cY + "年";
|
agenary_month = cM + "月";
|
agenary_day = cD + "日";
|
agenary_hour = cH + "时";
|
|
return agenary_year + agenary_month + agenary_day + agenary_hour;
|
}
|
|
/**
|
* 根据 日干 推算 时柱 根据提供的推算图来计算
|
*
|
* @param dG
|
* @param hour
|
* @return
|
*/
|
public static int hourG(String dG, int hour) {
|
int ind = 1;
|
for (String s : Gan) {
|
if (s.equals(dG)) {
|
break;
|
}
|
ind++;
|
}
|
ind = ind % 5; // 五个为一周期
|
int hourind = hourZ(hour);
|
if (hourind > 10)
|
return hourind - 10 + (ind - 1) * 2;
|
else {
|
hourind = hourind + (ind - 1) * 2;
|
return hourind >= 10 ? hourind - 10 : hourind;
|
}
|
}
|
|
/**
|
* 返回 小时对应的 支的索引
|
*
|
* @param hour
|
* @return
|
*/
|
public static int hourZ(int hour) {
|
if (hour >= 23 || hour < 1)
|
return 0;
|
else if (hour >= 1 && hour < 3)
|
return 1;
|
else if (hour >= 3 && hour < 5)
|
return 2;
|
else if (hour >= 5 && hour < 7)
|
return 3;
|
else if (hour >= 7 && hour < 9)
|
return 4;
|
else if (hour >= 9 && hour < 11)
|
return 5;
|
else if (hour >= 11 && hour < 13)
|
return 6;
|
else if (hour >= 13 && hour < 15)
|
return 7;
|
else if (hour >= 15 && hour < 17)
|
return 8;
|
else if (hour >= 17 && hour < 19)
|
return 9;
|
else if (hour >= 19 && hour < 21)
|
return 10;
|
else if (hour >= 21 && hour < 23)
|
return 11;
|
return 0;
|
}
|
|
/**
|
* 间隔天数
|
*
|
* @param y
|
* @param m
|
* @return
|
*/
|
public static int jlday(int y, int m) {
|
ScriptEngineManager sem = new ScriptEngineManager(); /* script引擎管理 */
|
ScriptEngine se = sem.getEngineByName("javascript"); /* script引擎 */
|
try {
|
se.eval(" var y =" + y + ",m=" + m + " ;"); /* 执行一段script */
|
se.eval("function jlday( ) { " + "return Date.UTC(y,m,1,0,0,0,0)/86400000+25567+10;" + "}"); /* 添加一个方法 */
|
Invocable invocableEngine = (Invocable) se;
|
Object callbackvalue = invocableEngine.invokeFunction("jlday"); /* 调用方法中的函数 */
|
if (callbackvalue != null) {
|
double numdb = Double.valueOf(callbackvalue.toString());
|
return (int) numdb;
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return 0;
|
}
|
|
/**
|
* 获取日期信息
|
*
|
* @param date
|
* @return
|
* @throws ParseException
|
*/
|
public static DateInfo getDateInfo(Date date) throws ParseException {
|
|
DateInfo dateInfo = new DateInfo();
|
// 分裂成年、月、日
|
splitDate(date);
|
dateInfo.setDay(day);
|
dateInfo.setMonth(month);
|
dateInfo.setYear(year);
|
|
// 星期几
|
getWeekd(date);
|
dateInfo.setWeekDay(weekDay);
|
|
// 转换成农历日期
|
toLunar(date);
|
dateInfo.setLunar_year(lunar_year);
|
dateInfo.setLunar_month(lunar_month);
|
dateInfo.setLunar_day(lunar_day);
|
|
// 天干地支
|
horoscope(date);
|
dateInfo.setAgenary_year(agenary_year);
|
dateInfo.setAgenary_month(agenary_month);
|
dateInfo.setAgenary_day(agenary_day);
|
dateInfo.setAgenary_hour(agenary_hour);
|
|
return dateInfo;
|
}
|
|
public static void main(String[] args) throws ParseException {
|
Date date = new Date();
|
|
String lunar = DateLunarUtil.toLunar(date);
|
System.out.println(lunar);
|
|
String horoscope = DateLunarUtil.horoscope(date);
|
System.out.println(horoscope);
|
|
System.out.println(getWeekd(date));
|
|
}
|
|
}
|