zoukankan      html  css  js  c++  java
  • java日期工具类DateUtil-续二

    该版本是一次较大的升级,农历相比公历复杂太多(真佩服古人的智慧),虽然有规律,但涉及到的取舍、近似的感念太多,况且本身的概念就已经很多了,我在网上也是查阅了很多的资料,虽然找到一些计算的方法,但都有些计算缺陷,后来才终于找到“寿天星文历”:一个十分精准的万年历。虽然它的功能十分强大,但相对的涉及到的计算也很多,逻辑和思路都相当的复杂了,维护成本很大,有时候项目中并不一定要用到这么强大的农历,因此该版本目前仅提供了农历的一些基本功能,在下一版本中,我会引入“寿天星文历”,以适合更多的大众需求。
    源码:
    DateUtil类
    新加入代码:(其他代码请参见java日期工具类DateUtil-续一)
    [java] view plaincopy
    /** 
     * 获取简单农历对象 
     * @param date 日期字符串 
     * @return 简单农历对象 
     */  
    public static SimpleLunarCalendar getSimpleLunarCalendar(String date) {  
        return new SimpleLunarCalendar(DateUtil.StringToDate(date));  
    }  
      
    /** 
     * 获取简单农历对象 
     * @param date 日期 
     * @return 简单农历对象 
     */  
    public static SimpleLunarCalendar getSimpleLunarCalendar(Date date) {  
        return new SimpleLunarCalendar(date);  
    }  
    SimpleLunarCalendar类
    [java] view plaincopy
    package com.util;  
      
    import java.util.Calendar;  
    import java.util.Date;  
    import java.util.GregorianCalendar;  
      
    public class SimpleLunarCalendar {  
      
        /** 最小时间1900-1-31*/  
        private final static long minTimeInMillis = -2206425952001L;  
        /** 最大时间2099-12-31 */  
        private final static long maxTimeInMillis = 4102416000000L;  
        /** 
         * 农历年数据表(1900-2099年)<br> 
         * <br> 
         * 每个农历年用16进制来表示,解析时转为2进制<br> 
         * 前12位分别表示12个农历月份的大小月,1是大月,0是小月<br> 
         * 最后4位表示闰月,转为十进制后即为闰月值,例如0110,则为闰6月 
         */  
        private final static int[] lunarInfo = { 0x4bd8, 0x4ae0, 0xa570, 0x54d5, 0xd260, 0xd950, 0x5554, 0x56af, 0x9ad0, 0x55d2, 0x4ae0, 0xa5b6, 0xa4d0, 0xd250, 0xd295, 0xb54f, 0xd6a0, 0xada2, 0x95b0,  
                0x4977, 0x497f, 0xa4b0, 0xb4b5, 0x6a50, 0x6d40, 0xab54, 0x2b6f, 0x9570, 0x52f2, 0x4970, 0x6566, 0xd4a0, 0xea50, 0x6a95, 0x5adf, 0x2b60, 0x86e3, 0x92ef, 0xc8d7, 0xc95f, 0xd4a0, 0xd8a6,  
                0xb55f, 0x56a0, 0xa5b4, 0x25df, 0x92d0, 0xd2b2, 0xa950, 0xb557, 0x6ca0, 0xb550, 0x5355, 0x4daf, 0xa5b0, 0x4573, 0x52bf, 0xa9a8, 0xe950, 0x6aa0, 0xaea6, 0xab50, 0x4b60, 0xaae4, 0xa570,  
                0x5260, 0xf263, 0xd950, 0x5b57, 0x56a0, 0x96d0, 0x4dd5, 0x4ad0, 0xa4d0, 0xd4d4, 0xd250, 0xd558, 0xb540, 0xb6a0, 0x95a6, 0x95bf, 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, 0x5176, 0x52bf, 0xa930, 0x7954, 0x6aa0, 0xad50, 0x5b52, 0x4b60, 0xa6e6, 0xa4e0, 0xd260, 0xea65, 0xd530, 0x5aa0, 0x76a3, 0x96d0, 0x4afb,  
                0x4ad0, 0xa4d0, 0xd0b6, 0xd25f, 0xd520, 0xdd45, 0xb5a0, 0x56d0, 0x55b2, 0x49b0, 0xa577, 0xa4b0, 0xaa50, 0xb255, 0x6d2f, 0xada0, 0x4b63, 0x937f, 0x49f8, 0x4970, 0x64b0, 0x68a6, 0xea5f,  
                0x6b20, 0xa6c4, 0xaaef, 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, 0x4b55, 0x4b6f, 0xa570, 0x54e4, 0xd260, 0xe968, 0xd520, 0xdaa0, 0x6aa6, 0x56df, 0x4ae0, 0xa9d4, 0xa4d0, 0xd150, 0xf252, 0xd520 };  
        /** 十二生肖 */  
        private final static String[] Animals = { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };  
        /** 农历中文字符串一 */  
        private final static String[] lunarString1 = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };  
        /** 农历中文字符串二 */  
        private final static String[] lunarString2 = { "初", "十", "廿", "卅", "正", "腊", "冬", "闰" };  
        /** 农历年 */  
        private int lunarYear;  
        /** 农历月 */  
        private int lunarMonth;  
        /** 农历日 */  
        private int lunarDay;  
        /** 是否是闰月 */  
        private boolean isLeap;  
        /** 是否是闰年 */  
        private boolean isLeapYear;  
        /** 某农历月的最大天数 */  
        private int maxDayInMonth = 29;  
      
        /** 
         * 通过 TimeInMillis 构建农历信息 
         * @param TimeInMillis 
         */  
        public SimpleLunarCalendar(long TimeInMillis) {  
            this.init(TimeInMillis);  
        }  
      
        /** 
         * 通过 Date 对象构建农历信息 
         * @param date 指定日期对象 
         */  
        public SimpleLunarCalendar(Date date) {  
            if (date == null)  
                date = new Date();  
            this.init(date.getTime());  
        }  
      
        /** 
         * 农历初始化 
         * @param timeInMillis 时间毫秒数 
         */  
        private void init(long timeInMillis) {  
            if (timeInMillis > minTimeInMillis && timeInMillis < maxTimeInMillis) {  
                // 以农历为1900年正月一日的1900-1-31作为起始日期  
                Calendar baseDate = new GregorianCalendar(1900, 0, 31);  
                // 距离起始日期间隔的总天数  
                long offset = (timeInMillis - baseDate.getTimeInMillis()) / 86400000;  
                // 默认农历年为1900年,且由此开始推算农历年份  
                this.lunarYear = 1900;  
                int daysInLunarYear = SimpleLunarCalendar.getLunarYearDays(this.lunarYear);  
                // 递减每个农历年的总天数,确定农历年份  
                while (this.lunarYear < 2100 && offset >= daysInLunarYear) {  
                    offset -= daysInLunarYear;  
                    daysInLunarYear = SimpleLunarCalendar.getLunarYearDays(++this.lunarYear);  
                }  
                // 获取该农历年的闰月月份  
                int leapMonth = SimpleLunarCalendar.getLunarLeapMonth(this.lunarYear);  
                // 没有闰月则不是闰年  
                this.isLeapYear = leapMonth > 0;  
      
                // 默认农历月为正月,且由此开始推荐农历月  
                int lunarMonth = 1;  
                // 是否递减农历月  
                boolean isDecrease = true;  
                boolean isLeap = false;  
                int daysInLunarMonth = 0;  
                // 递减每个农历月的总天数,确定农历月份  
                while (lunarMonth < 13 && offset > 0) {  
                    if (isLeap && !isDecrease) {  
                        // 该农历年闰月的总天数  
                        daysInLunarMonth = SimpleLunarCalendar.getLunarLeapDays(this.lunarYear);  
                        isDecrease = true;  
                    } else {  
                        // 该农历年正常农历月份的天数  
                        daysInLunarMonth = SimpleLunarCalendar.getLunarMonthDays(this.lunarYear, lunarMonth);  
                    }  
                    if (offset < daysInLunarMonth) {  
                        break;  
                    }  
                    offset -= daysInLunarMonth;  
      
                    // 如果农历月是闰月,则不递增农历月份  
                    if (leapMonth == lunarMonth && isLeap == false) {  
                        isDecrease = false;  
                        isLeap = true;  
                    } else {  
                        lunarMonth++;  
                    }  
                }  
                // 如果daysInLunarMonth为0则说明默认农历月即为返回的农历月  
                this.maxDayInMonth = daysInLunarMonth != 0 ? daysInLunarMonth : SimpleLunarCalendar.getLunarMonthDays(this.lunarYear, lunarMonth);  
                this.lunarMonth = lunarMonth;  
                this.isLeap = (lunarMonth == leapMonth && isLeap);  
                this.lunarDay = (int) offset + 1;  
            }  
        }  
      
        /** 
         * 获取某农历年的总天数 
         * @param lunarYear 农历年份 
         * @return 该农历年的总天数 
         */  
        private static int getLunarYearDays(int lunarYear) {  
            // 按小月计算,农历年最少有12 * 29 = 348天  
            int daysInLunarYear = 348;  
      
            // 遍历前12位  
            for (int i = 0x8000; i > 0x8; i >>= 1) {  
                // 每个大月累加一天  
                daysInLunarYear += ((SimpleLunarCalendar.lunarInfo[lunarYear - 1900] & i) != 0) ? 1 : 0;  
            }  
            // 加上闰月天数  
            daysInLunarYear += SimpleLunarCalendar.getLunarLeapDays(lunarYear);  
      
            return daysInLunarYear;  
        }  
      
        /** 
         * 获取某农历年闰月的总天数 
         * @param lunarYear 农历年份 
         * @return 该农历年闰月的总天数,没有闰月返回0 
         */  
        private static int getLunarLeapDays(int lunarYear) {  
            // 下一年最后4bit为1111,返回30(大月)  
            // 下一年最后4bit不为1111,返回29(小月)  
            // 若该年没有闰月,返回0  
            return SimpleLunarCalendar.getLunarLeapMonth(lunarYear) > 0 ? ((SimpleLunarCalendar.lunarInfo[lunarYear - 1899] & 0xf) == 0xf ? 30 : 29) : 0;  
        }  
      
        /** 
         * 获取某农历年闰月月份 
         * @param lunarYear 农历年份 
         * @return 该农历年闰月的月份,没有闰月返回0 
         */  
        private static int getLunarLeapMonth(int lunarYear) {  
            // 匹配后4位  
            int leapMonth = SimpleLunarCalendar.lunarInfo[lunarYear - 1900] & 0xf;  
            // 若最后4位全为1或全为0,表示没闰  
            leapMonth = (leapMonth == 0xf ? 0 : leapMonth);  
            return leapMonth;  
        }  
      
        /** 
         * 获取某农历年某农历月份的总天数 
         * @param lunarYear 农历年份 
         * @param lunarMonth 农历月份 
         * @return 该农历年该农历月的总天数 
         */  
        private static int getLunarMonthDays(int lunarYear, int lunarMonth) {  
            // 匹配前12位代表的相应农历月份的大小月,大月30天,小月29天  
            int daysInLunarMonth = ((SimpleLunarCalendar.lunarInfo[lunarYear - 1900] & (0x10000 >> lunarMonth)) != 0) ? 30 : 29;  
            return daysInLunarMonth;  
        }  
      
        /** 
         * 返回指定数字的农历年份表示字符串 
         * @param lunarYear 农历年份(数字,0为甲子) 
         * @return 农历年份字符串 
         */  
        private static String getLunarYearString(int lunarYear) {  
            String lunarYearString = "";  
            String year = String.valueOf(lunarYear);  
            for (int i = 0; i < year.length(); i++) {  
                char yearChar = year.charAt(i);  
                int index = Integer.parseInt(String.valueOf(yearChar));  
                lunarYearString += lunarString1[index];  
            }  
            return lunarYearString;  
        }  
      
        /** 
         * 返回指定数字的农历月份表示字符串 
         * @param lunarMonth 农历月份(数字) 
         * @return 农历月份字符串 (例:正) 
         */  
        private static String getLunarMonthString(int lunarMonth) {  
            String lunarMonthString = "";  
            if (lunarMonth == 1) {  
                lunarMonthString = SimpleLunarCalendar.lunarString2[4];  
            } else {  
                if (lunarMonth > 9)  
                    lunarMonthString += SimpleLunarCalendar.lunarString2[1];  
                if (lunarMonth % 10 > 0)  
                    lunarMonthString += SimpleLunarCalendar.lunarString1[lunarMonth % 10];  
            }  
            return lunarMonthString;  
        }  
      
        /** 
         * 返回指定数字的农历日表示字符串 
         * @param lunarDay 农历日(数字) 
         * @return 农历日字符串 (例: 廿一) 
         */  
        private static String getLunarDayString(int lunarDay) {  
            if (lunarDay < 1 || lunarDay > 30)  
                return "";  
            int i1 = lunarDay / 10;  
            int i2 = lunarDay % 10;  
            String c1 = SimpleLunarCalendar.lunarString2[i1];  
            String c2 = SimpleLunarCalendar.lunarString1[i2];  
            if (lunarDay < 11)  
                c1 = SimpleLunarCalendar.lunarString2[0];  
            if (i2 == 0)  
                c2 = SimpleLunarCalendar.lunarString2[1];  
            return c1 + c2;  
        }  
      
        /** 
         * 取农历年生肖 
         * @return 农历年生肖(例:龙) 
         */  
        public String getAnimalString() {  
            if (lunarYear == 0)  
                return null;  
            return SimpleLunarCalendar.Animals[(this.lunarYear - 4) % 12];  
        }  
      
        /** 
         * 返回农历日期字符串 
         * @return 农历日期字符串 
         */  
        public String getDayString() {  
            if (lunarDay == 0)  
                return null;  
            return SimpleLunarCalendar.getLunarDayString(this.lunarDay);  
        }  
      
        /** 
         * 返回农历日期字符串 
         * @return 农历日期字符串 
         */  
        public String getMonthString() {  
            if (lunarMonth == 0)  
                return null;  
            return (this.isLeap() ? "闰" : "") + SimpleLunarCalendar.getLunarMonthString(this.lunarMonth);  
        }  
      
        /** 
         * 返回农历日期字符串 
         * @return 农历日期字符串 
         */  
        public String getYearString() {  
            if (lunarYear == 0)  
                return null;  
            return SimpleLunarCalendar.getLunarYearString(this.lunarYear);  
        }  
      
        /** 
         * 返回农历表示字符串 
         * @return 农历字符串(例:甲子年正月初三) 
         */  
        public String getDateString() {  
            if (lunarYear == 0)  
                return null;  
            return this.getYearString() + "年" + this.getMonthString() + "月" + this.getDayString() + "日";  
        }  
      
        /** 
         * 农历年是否是闰月 
         * @return 农历年是否是闰月 
         */  
        public boolean isLeap() {  
            return isLeap;  
        }  
      
        /** 
         * 农历年是否是闰年 
         * @return 农历年是否是闰年 
         */  
        public boolean isLeapYear() {  
            return isLeapYear;  
        }  
      
        /** 
         * 当前农历月是否是大月 
         * @return 当前农历月是大月 
         */  
        public boolean isBigMonth() {  
            return this.getMaxDayInMonth() > 29;  
        }  
      
        /** 
         * 当前农历月有多少天 
         * @return 天数 
         */  
        public int getMaxDayInMonth() {  
            if (lunarYear == 0)  
                return 0;  
            return this.maxDayInMonth;  
        }  
      
        /** 
         * 农历日期 
         * @return 农历日期 
         */  
        public int getDay() {  
            return lunarDay;  
        }  
      
        /** 
         * 农历月份 
         * @return 农历月份 
         */  
        public int getMonth() {  
            return lunarMonth;  
        }  
      
        /** 
         * 农历年份 
         * @return 农历年份 
         */  
        public int getYear() {  
            return lunarYear;  
        }  
    }  
    说明:该农历核心算法是从网上寻找而来,但我进行了完善,适用的年份为:1900年——2099年,我去掉了不精准的部分(如天干地支),目前该简单农历只能满足显示阴历信息,适合需要较为简单的用户适用。另外若想支持的年限范围更广,则需要修改lunarInfo(农历年数据表),并做适当的调整(默认农历年)即可。
  • 相关阅读:
    js实现点击隐藏图片
    绝对定位给图片四角加上图片修饰
    雪碧图实现登陆页面
    弹性盒模型
    数组练习--求数组和,平均值,最大值,最小值
    h5与c3权威指南笔记--css3结构性伪类选择器root,not,empty,target
    h5与c3权威指南笔记--css3新属性选择器
    闲聊Java里的随机数
    Python之简单抓取豆瓣读书信息
    中本聪比特币论文
  • 原文地址:https://www.cnblogs.com/jym-sunshine/p/4905452.html
Copyright © 2011-2022 走看看