「utils」java旧暦util、陽暦転旧暦、アリ符号化規範プラグインはスキャンしたことがある.

9313 ワード

/**
 *
 * @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());
    }
}