《utils》java农历util,阳历转农历,阿里编码规范插件扫描过.

/**
 *
 * @author guokaige
 *
 */
public class LunarSolarConverter {


    private static final long MIN_TIME_MILLIS, MAX_TIME_MILLIS;





    private static final long YEAR_1900=1900;

    private static final long YEAR_1900_MONTH_11=11;

    private static final long MONTH_NUM=12;

    private static final int MEM_0X8000=0x8000;

    private static final int MEM_0X8=0x8;

    /**
     * 农历年数据表(1900-2100年)
     * 每个农历年用16进制来表示,解析时转为2进制
     * 二进码长度为16位,如解码为15位高位补0,(当解码为17位时,最高位1即所闰月位大月,反之为小月)
     * 前12位分别表示12个农历月份的大小月,1是大月,0是小月
     * 最后4位表示闰月,转为十进制后即为闰月值,例如0110,则为闰6月
     */

    private final static int[] LUNAR_INFO = {
            0x10, 0x4ae0, 0xa570, 0x54d5, 0xd260, 0xd950, 0x16554, 0x56a0, 0x9ad0, 0x55d2,
            0x4ae0, 0xa5b6, 0xa4d0, 0xd250, 0x1d255, 0xb540, 0xd6a0, 0xada2, 0x95b0, 0x14977,
            0x4970, 0xa4b0, 0xb4b5, 0x6a50, 0x6d40, 0x1ab54, 0x2b60, 0x9570, 0x52f2, 0x4970,
            0x6566, 0xd4a0, 0xea50, 0x16a95, 0x5ad0, 0x2b60, 0x186e3, 0x92e0, 0x1c8d7, 0xc950,
            0xd4a0, 0x1d8a6, 0xb550, 0x56a0, 0x1a5b4, 0x25d0, 0x92d0, 0xd2b2, 0xa950, 0xb557,
            0x6ca0, 0xb550, 0x15355, 0x4da0, 0xa5b0, 0x14573, 0x52b0, 0xa9a8, 0xe950, 0x6aa0,
            0xaea6, 0xab50, 0x4b60, 0xaae4, 0xa570, 0x5260, 0xf263, 0xd950, 0x5b57, 0x56a0,
            0x96d0, 0x4dd5, 0x4ad0, 0xa4d0, 0xd4d4, 0xd250, 0xd558, 0xb540, 0xb6a0, 0x195a6,
            0x95b0, 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, 0x15176, 0x52b0, 0xa930,
            0x7954, 0x6aa0, 0xad50, 0x5b52, 0x4b60, 0xa6e6, 0xa4e0, 0xd260, 0xea65, 0xd530,
            0x5aa0, 0x76a3, 0x96d0, 0x26fb, 0x4ad0, 0xa4d0, 0x1d0b6, 0xd250, 0xd520, 0xdd45,
            0xb5a0, 0x56d0, 0x55b2, 0x49b0, 0xa577, 0xa4b0, 0xaa50, 0x1b255, 0x6d20, 0xada0,
            0x14b63, 0x9370, 0x49f8, 0x4970, 0x64b0, 0x168a6, 0xea50, 0x6aa0, 0x1a6c4, 0xaae0,
            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, 0x14b55, 0x4b60, 0xa570, 0x54e4, 0xd160,
            0xe968, 0xd520, 0xdaa0, 0x16aa6, 0x56d0, 0x4ae0, 0xa9d4, 0xa2d0, 0xd150, 0xf252,
            0xd520
    };

    private final static String[] LUNAR_MONTH_ARRAYS = {"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"};
    private final static String[] LUNAR_DAY_ARRAYS = {"初", "十", "廿", "卅"};
    private final static String[] NUMBERS = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};

    static {
        Calendar calendar = Calendar.getInstance();
        //公历1901-1-1 即农历1900-11-11
        calendar.set(1901, 0, 1, 0, 0, 0);
        MIN_TIME_MILLIS = calendar.getTimeInMillis();
        //公历2100-12-31 即农历2100-12-1
        calendar.set(2100, 11, 31, 23, 59, 59);
        MAX_TIME_MILLIS = calendar.getTimeInMillis();
    }

    /**
     * 根据时间毫秒值转换 农历
     *
     * @param timeInMillis 时间毫秒值
     * @return Lunar 农历对象
     */
    public static Lunar converterDate(long timeInMillis) {
        if (timeInMillis < MIN_TIME_MILLIS || timeInMillis > MAX_TIME_MILLIS) {
            throw new RuntimeException("日期超出农历计算范围,-->minDate:1900-1-1 maxDate 2100-12-31");
        }
        Lunar lunar = new Lunar();
        // 距离起始日期间隔的总天数 间隔天数和目标日期差一天
        long offset = (timeInMillis - MIN_TIME_MILLIS) / (24 * 60 * 60 * 1000);
        // 默认农历年为1900年,且由此开始推算农历年份
        int lunarYear = 1900;
        while (true) {
            int daysInLunarYear = getLunarYearDays(lunarYear);
            if (offset > daysInLunarYear) {
                offset -= daysInLunarYear;
                lunarYear++;
            } else {
                break;
            }
        }
        lunar.year = lunarYear;
        // 获取该农历年的闰月月份
        int leapMonth = getLunarLeapMonth(lunarYear);
        // 没有闰月则不是闰年
        lunar.leapMonth = leapMonth;
        // 默认农历月为正月,且由此开始推荐农历月
        int lunarMonth = lunarYear == 1900 ? 11 : 1;
        int daysInLunarMonth;
        // 递减每个农历月的总天数,确定农历月份,先计算非闰月后计算闰月
        while (true) {
            // 该农历年闰月的天数,先算正常月再算闰月 如果润一月 先减去一月再减去润一月
            if (lunarMonth == leapMonth) {
                daysInLunarMonth = getLunarDays(lunarYear, lunarMonth);
                //剩余天数>当月天数
                if (offset > daysInLunarMonth) {
                    //减去差额
                    offset -= daysInLunarMonth;
                    //剩余天数>闰月天数
                    if (offset > getLunarLeapDays(lunarYear)) {
                        //减去闰月天数
                        offset -= getLunarLeapDays(lunarYear);
                        //月份+1
                        lunarMonth++;
                    } else {
                        //标记闰月为当前年
                        lunarMonth = lunarYear;
                        break;
                    }
                } else {
                    break;
                }
            } else { // 该农历年正常农历月份的天数
                daysInLunarMonth = getLunarDays(lunarYear, lunarMonth);
                //剩余天数>当月天数
                if (offset > daysInLunarMonth) {
                    //减去差额
                    offset -= daysInLunarMonth;
                    lunarMonth++;//月份+1
                } else {
                    break;
                }
            }
        }

        lunar.month = lunarMonth;
        lunar.day = (lunarYear == 1900 && lunarMonth == 11) ? (int) Math.abs(-offset + -11) : (int) offset;
        return lunar;
    }

    /**
     * 获取某农历年的总天数
     *
     * @param lunarYear 农历年份
     * @return 该农历年的总天数
     */
    private static int getLunarYearDays(int lunarYear) {
        if (lunarYear == YEAR_1900) {
            //1900天只有48天的数据
            return 48;
        }
        // 按小月计算,农历年最少有12 * 29 = 348天
        int daysInLunarYear = 348;
        // 遍历前12位
        for (int i = MEM_0X8000; i > MEM_0X8; i >>= 1) {
            // 每个大月累加一天
            daysInLunarYear += ((LUNAR_INFO[lunarYear - 1900] & i) != 0) ? 1 : 0;
        }
        // 加上闰月天数
        daysInLunarYear += getLunarLeapDays(lunarYear);

        return daysInLunarYear;
    }

    /**
     * 获取某农历年闰月的总天数
     *
     * @param lunarYear 农历年份
     * @return 该农历年闰月的天数, 无闰月返回0 (闰月的天数等于所润月的天数)
     */
    private static int getLunarLeapDays(int lunarYear) {
        // 计算所闰月为大月还是小月 如果该年的二进制码为17位,最高位为1则该年闰月为大月,反之则为小月(2017/2055)
        // 若该年没有闰月,返回0
        return getLunarLeapMonth(lunarYear) > 0 ? ((LUNAR_INFO[lunarYear - 1900] & 0x10000) > 0 ? 30 : 29) : 0;
    }

    /**
     * 获取某农历年闰月月份
     *
     * @param lunarYear 农历年份
     * @return 该农历年闰月的月份, 四位二进制码即为闰月的月份, 0为不闰月
     */
    private static int getLunarLeapMonth(int lunarYear) {
        // 匹配后4位
        int leapMonth = LUNAR_INFO[lunarYear - 1900] & 0xf;
        leapMonth = (leapMonth == 0xf ? 0 : leapMonth);
        //闰月月份不能大于12 否则数据肯定是错误的
        if (leapMonth > MONTH_NUM) {
            throw new RuntimeException(lunarYear + "年数据错误,lunarYear:" + Integer.toBinaryString(LUNAR_INFO[lunarYear - 1900]));
        }
        return leapMonth;
    }

    /**
     * 获取某农历年某月的总天数
     *
     * @param lunarYear 农历年份
     * @return 该农历年某月的天数
     */
    private static int getLunarDays(int lunarYear, int month) {
        if (lunarYear == YEAR_1900 && month == YEAR_1900_MONTH_11) {
            //1900年11月18天
            return 18;
        }
        return (LUNAR_INFO[lunarYear - 1900] & (0x10000 >> month)) != 0 ? 30 : 29;
    }


    public static class Lunar {
        public int year;
        public int month;
        public int day;
        public int leapMonth;

        public String getMonth() {
            return month > LUNAR_MONTH_ARRAYS.length ? "润" + LUNAR_MONTH_ARRAYS[leapMonth - 1] : LUNAR_MONTH_ARRAYS[month - 1];
        }

        public String getDay() {
            int result = day / 10;
            return LUNAR_DAY_ARRAYS[(result == 1 && day % 10 == 0) ? result - 1 : result] +
                    (day % 10 == 0 ? NUMBERS[NUMBERS.length - 1] : NUMBERS[Math.abs(day - result * 10) - 1]);
        }

        @Override
        public String toString() {
            return "Lunar{" +
                    "年=" + year +
                    ", 月=" + month +
                    ", 日=" + day +
                    ", 闰月=" + leapMonth +
                    ", 月/日:" + getMonth() + "月" + getDay() +
                    '}';
        }
    }


    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        System.out.println("DATE:" + calendar.get(Calendar.DATE));
        Lunar lunar=LunarSolarConverter.converterDate(calendar.getTimeInMillis());
        System.out.println(lunar.getDay());
    }
}

 

你可能感兴趣的:(java)