农历与公历日期转换(1900年 至 2049年)

1、农历对照数据集

/**
 * 1900年1月31日对应农历正月初一
 * 数据17位长度(二进制),最高位表示闰月的大小,大 30, 小 29,例:((LunarDates[0]) >> 16 & 0x01) > 0 ? 30 : 29
 * 第16 至 5 位 表示 1-12 月的月份天数,((LunarDates[0]) >> [15~4] & 0x01) > 0 ? 30 : 29
 * 第4 至 1 位 表示 闰那个月, 0表示不闰月  LunarDates[0] & 0x0f
 *
**/
private static final int[] LunarDates = 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};

2、公历转农历日期:

public static int[] getLunarDateFromDate(Date date){
    int[] lunarDate = new int[3];
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    int year = calendar.get(Calendar.YEAR);
    if (year < 1900 || year > 2050)return lunarDate;
    else if (year == 1900){
        int month = calendar.get(Calendar.MONTH);
        if (month == 0)return lunarDate;
    }
    long sumDay = sumDay(date);
    return computeLunarDate(sumDay);
}
/**
 * 计算距离1900-01-31的总天数
 *
 * @param date 参与计算的日期
 * **/
private static long sumDay(Date date){
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    int year = calendar.get(Calendar.YEAR);
    int startYear = 1901;
    long day = 365 -30;
    if (startYear == year){
        day  = calendar.get(Calendar.DAY_OF_YEAR);
    }else {
        while (year > startYear){
           if ((startYear % 4 == 0 && startYear % 100 != 0) || startYear % 400 == 0){
               day += 366;
           }else {
               day += 365;
           }
           startYear ++;
        }
        day += calendar.get(Calendar.DAY_OF_YEAR);
    }
    return day;
}
/**
 * 根据天数差计算农历日期
 * @param sumDay 距离1900-01-31的总天数
 *
 * @return 返回农历年月日数组, 当月份为负数是表示闰月
 * **/
private static int[] computeLunarDate(long sumDay){
    int[] lunarDates = new int[3];
    long tDay = 0;
    int lunarDate = 0;
    for (int i=0;i < LunarDates.length; i++){
        lunarDate = LunarDates[i];
        int ltd = lunarYearDays(lunarDate);
        tDay += ltd;
        if (tDay > sumDay){
            tDay = tDay - ltd;
            lunarDates[0] = 1900 + i;
            break;
        }
    }
    long dt = sumDay - tDay;
    int yunDays = ((lunarDate >> 16) & 0x01) == 1 ? 30 : 29;
    int runYue = lunarDate & 0x0f;
    for (int i = 1;i<13;i++){
        int index = 16 - i;
        int day = ((lunarDate>>index) & 0x01) == 1 ? 30 : 29;
        if (dt <= day){
            lunarDates[1] = i;
            lunarDates[2] = (int)dt;
            break;
        }
        dt = dt - day;
        if (runYue == i){
            if (dt <= yunDays){
                lunarDates[1] = -i;
                lunarDates[2] = (int)dt;
                break;
            }
            dt = dt - yunDays;
        }
    }
    return lunarDates;
}
/**
 * 农历某年的总天数
 * @param lunarDate 农历某年数据
 * 
 * **/
private static int lunarYearDays(int lunarDate){
    int yunDays = (lunarDate >> 16) & 0x01;
    int days = 0;
    for (int b = 15; b > 3; b --){
        int day = ((lunarDate >> b) & 0x01) == 1 ? 30 : 29;
        days += day;
    }
    int runYue = lunarDate & 0x0f;
    if (runYue > 0){
        days += yunDays == 1 ? 30 : 29;
    }
    return days;
}

3、农历日期转公历日期

/**
 * 农历日期转公历日期,只能转换 1900年1月31日 至 2049年12月31日
 * 闰月月份为负数,如 润4月 为 -4
 *
 * @param lunarYear 农历年
 * @param lunarMonth 农历月
 * @param lunarDay 农历日
 * **/
public static Date getDateFromLunarDate(@IntRange(from = 1900, to = 2049) int lunarYear, int lunarMonth, int lunarDay){
    int year = lunarYear - 1900;
    int days = 0;
    for (int i=0; i< year; i++){
        days += lunarYearDays(LunarDates[i]);
    }
    int lunarDate = LunarDates[year];
    int yunDays = ((lunarDate >> 16) & 0x01) == 1 ? 30 : 29;
    int runYue = lunarDate & 0x0f;
    if (runYue < Math.abs(lunarMonth) && runYue != 0)days += yunDays;
    for (int i = 1;i<13;i++){
        int index = 16 - i;
        int day = ((lunarDate>>index) & 0x01) == 1 ? 30 : 29;
        if (lunarMonth > 0){
            if (lunarMonth == i){
                days += lunarDay;
                break;
            }else {
                days += day;
            }
        }else {
            if (i < -lunarMonth){
                days += day;
            }else if (i == -lunarDate){
                days += day;
                days += lunarDay;
                break;
            }
        }
    }
    int yearDays = 0;//公历初始天数
    int[] ymd = new int[3];
    for (int i=1900;i<=lunarYear+1;i++){
        int day = 365;
        if (i%100 == 0){
            if (i%400 == 0) day = 366;
        }else if (i%4 == 0){
            day = 366;
        }
        if (yearDays + day > days){
            ymd[0] = i;
            break;
        }
        yearDays += day;
    }
    Calendar calendar = Calendar.getInstance();
    calendar.clear();
    calendar.set(Calendar.YEAR, ymd[0]);
    int cd = days - (yearDays - 30);
    calendar.set(Calendar.DAY_OF_YEAR, cd);
    return calendar.getTime();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值