admin
2021-02-06 d1f26741bddf6f512d62c0100d42c52be8d37e76
utils/src/main/java/org/yeshi/utils/DateLunarUtil.java
@@ -1,539 +1,539 @@
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));
   }
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));
   }
}