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)); } }