zoukankan      html  css  js  c++  java
  • Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口

    本章主要是收藏一些常用的类和接口,包括:万年历(农历、阳历节日、阴历节日)、自定义的Calendar接口。 

    万年历

    源码如下(ChineseCalendar.java):

      1 package com.via.mce.monthcalendar.utils;
      2 
      3 import java.util.Calendar;
      4 import java.util.Date;
      5 import java.util.GregorianCalendar;
      6 import java.util.HashMap;
      7 
      8 /**
      9  * 农历日历。<br>
     10  * 将农历从1901年到2100年之间各年、月的大小以及历年节气保存,然后基于这些数据进行计算。<br>
     11  * <br>
     12  * 新增了几个用于农历的常量属性字段,可以使用get()方法获取日历对应的值;<br>
     13  * 农历年、月、日还可以使用set()/add()/roll()方法设置,其他农历属性自动计算;<br>
     14  * 另外,还提供了getChinese(int field)方法用于获得农历的中文文字(仅适用于农历属性和星期)。<br>
     15  * <ul>
     16  * <li>CHINESE_YEAR - 农历年</li>
     17  * <li>CHINESE_MONTH - 农历月</li>
     18  * <li>CHINESE_DATE - 农历日</li>
     19  * <li>CHINESE_SECTIONAL_TERM - 当月的节气</li>
     20  * <li>CHINESE_PRINCIPLE_TERM - 当月的中气</li>
     21  * <li>CHINESE_HEAVENLY_STEM - 农历年的天干</li>
     22  * <li>CHINESE_EARTHLY_BRANCH - 农历年的地支</li>
     23  * <li>CHINESE_ZODIAC - 农历年的属相</li>
     24  * <li>CHINESE_TERM_OR_DATE - 如果当天存在一个节气则指示节气,否则如果当天是初一则指示农历月,否则指示农历日</li>
     25  * </ul>
     26  * 注意:<br>
     27  * 由于Calendar类的设定,公历月份从0起始。所有方法都遵循了这一约定。<br>
     28  * 但所有的农历属性从1起始。即使是在Calendar提供的方法中,农历月也是从1起始的,并以负数表示闰月。<br>
     29  * clear()方法在某些情况下会导致农历和公历日期不对应或是不能达到预期的重置效果,应尽量避免使用。<br>
     30  * 使用getSimpleDateString()获得公历日期字符串时,公历月已经修正;<br>
     31  * 使用getSimpleChineseDateString()获得农历日期字符串时,农历闰月以*表示。<br>
     32  * 
     33  * @version 0.12 2011-9-5 <br>
     34  *          <blockquote>修复一个当使用农历正月日期初始化日历时陷入死循环的问题。</blockquote>
     35  * @version 0.11 2009-12-27 <br>
     36  *          <blockquote>修复了获取中文农历时未计算农历日期的问题;<br>
     37  *          加入一个字段CHINESE_TERM_OR_DATE用于模仿台历的显示方式:如果当天有节气则指示节气,如果是初一指示农历月,
     38  *          否则指示农历日。</blockquote>
     39  * @version 0.10 2009-12-22
     40  */
     41 public final class ChineseCalendar extends GregorianCalendar {
     42     private static final long serialVersionUID = 8L;
     43  
     44     /** 农历年 */
     45     public static final int CHINESE_YEAR = 801;
     46     /** 农历月 */
     47     public static final int CHINESE_MONTH = 802;
     48     /** 农历日 */
     49     public static final int CHINESE_DATE = 803;
     50     /** 当月的节气对应的公历日(前一个节气) */
     51     public static final int CHINESE_SECTIONAL_TERM = 804;
     52     /** 当月的中气对应的公历日(后一个节气) */
     53     public static final int CHINESE_PRINCIPLE_TERM = 805;
     54     /** 天干 */
     55     public static final int CHINESE_HEAVENLY_STEM = 806;
     56     /** 地支 */
     57     public static final int CHINESE_EARTHLY_BRANCH = 807;
     58     /** 农历年的属相(生肖) */
     59     public static final int CHINESE_ZODIAC = 808;
     60     /** 节气或者农历日 */
     61     public static final int CHINESE_TERM_OR_DATE = 888;
     62     
     63 
     64     // add by skywang
     65     /** 农历节日 */
     66     public static final int LUNAR_FESTIVAL = 809;
     67     /** 阳历节日 */
     68     public static final int SOLAR_FESTIVAL = 810;
     69     /** 节气 */
     70     public static final int CHINESE_TERM = 811;
     71     /** 月或者农历日 */
     72     public static final int CHINESE_MONTH_OR_DATE = 812;
     73     /** 节日 或 节气 或 农历日 */
     74     public static final int FESTIVAL_OR_TERM_OR_DATE = 813;
     75     
     76     private int chineseYear;
     77     private int chineseMonth; // 1起始,负数表示闰月
     78     private int chineseDate;
     79     private int sectionalTerm; // 当月节气的公历日
     80     private int principleTerm; // 当月中气的公历日
     81  
     82     private boolean areChineseFieldsComputed; // 农历日期是否已经经过计算确认
     83     private boolean areSolarTermsComputed; // 节气是否已经经过计算确认
     84     private boolean lastSetChinese; // 最后设置的是不是农历属性
     85  
     86     /** 使用当前时间构造一个实例。 */
     87     public ChineseCalendar() {
     88         super();
     89     }
     90  
     91     /** 使用指定时间构造一个实例。 */
     92     public ChineseCalendar(Date d) {
     93         super.setTime(d);
     94     }
     95  
     96     /** 使用指定时间构造一个实例。 */
     97     public ChineseCalendar(Calendar c) {
     98         this(c.getTime());
     99     }
    100  
    101     /** 使用指定公历日期构造一个实例。 */
    102     public ChineseCalendar(int y, int m, int d) {
    103         super(y, m, d);
    104     }
    105  
    106     /**
    107      * 使用指定日期构造一个实例。
    108      * 
    109      * @param isChinese
    110      *            是否为农历日期
    111      * @param y
    112      * @param m
    113      * @param d
    114      */
    115     public ChineseCalendar(boolean isChinese, int y, int m, int d) {
    116         if (isChinese) {
    117             set(CHINESE_YEAR, y);
    118             set(CHINESE_MONTH, m);
    119             set(CHINESE_DATE, d);
    120         } else {
    121             set(y, m, d);
    122         }
    123     }
    124  
    125     public void set(int field, int value) {
    126         computeIfNeed(field);
    127  
    128         if (isChineseField(field)) {
    129             // 农历属性
    130             switch (field) {
    131             case CHINESE_YEAR:
    132                 chineseYear = value;
    133                 break;
    134             case CHINESE_MONTH:
    135                 chineseMonth = value;
    136                 break;
    137             case CHINESE_DATE:
    138                 chineseDate = value;
    139                 break;
    140             default:
    141                 throw new IllegalArgumentException("不支持的field设置:" + field);
    142             }
    143             lastSetChinese = true;
    144         } else {
    145             // 非农历属性
    146             super.set(field, value);
    147             lastSetChinese = false;
    148         }
    149         areFieldsSet = false;
    150         areChineseFieldsComputed = false;
    151         areSolarTermsComputed = false;
    152     }
    153  
    154     public int get(int field) {
    155         computeIfNeed(field);
    156  
    157         if (!isChineseField(field)) {
    158             return super.get(field);
    159         }
    160  
    161         switch (field) {
    162         case CHINESE_YEAR:
    163             return chineseYear;
    164         case CHINESE_MONTH:
    165             return chineseMonth;
    166         case CHINESE_DATE:
    167             return chineseDate;
    168         case CHINESE_SECTIONAL_TERM:
    169             return sectionalTerm;
    170         case CHINESE_PRINCIPLE_TERM:
    171             return principleTerm;
    172         case CHINESE_HEAVENLY_STEM:
    173             return (chineseYear - 4) % 10 + 1;
    174         case CHINESE_EARTHLY_BRANCH:
    175         case CHINESE_ZODIAC:
    176             return (chineseYear - 4) % 12 + 1;
    177         case CHINESE_MONTH_OR_DATE: 
    178             if (get(CHINESE_DATE) == 1) {
    179                 return CHINESE_MONTH;
    180             } else {
    181                 return CHINESE_DATE;
    182             }
    183         case CHINESE_TERM_OR_DATE:
    184             int option;
    185             if (get(Calendar.DATE) == get(CHINESE_SECTIONAL_TERM)) {
    186                 option = CHINESE_SECTIONAL_TERM;
    187             } else if (get(Calendar.DATE) == get(CHINESE_PRINCIPLE_TERM)) {
    188                 option = CHINESE_PRINCIPLE_TERM;
    189             } else if (get(CHINESE_DATE) == 1) {
    190                 option = CHINESE_MONTH;
    191             } else {
    192                 option = CHINESE_DATE;
    193             }
    194             return option;
    195         default:
    196             throw new IllegalArgumentException("不支持的field获取:" + field);
    197         }
    198     }
    199  
    200     public void add(int field, int amount) {
    201         computeIfNeed(field);
    202  
    203         if (!isChineseField(field)) {
    204             super.add(field, amount);
    205             lastSetChinese = false;
    206             areChineseFieldsComputed = false;
    207             areSolarTermsComputed = false;
    208             return;
    209         }
    210  
    211         switch (field) {
    212         case CHINESE_YEAR:
    213             chineseYear += amount;
    214             break;
    215         case CHINESE_MONTH:
    216             for (int i = 0; i < amount; i++) {
    217                 chineseMonth = nextChineseMonth(chineseYear, chineseMonth);
    218                 if (chineseMonth == 1) {
    219                     chineseYear++;
    220                 }
    221             }
    222             break;
    223         case CHINESE_DATE:
    224             int maxDate = daysInChineseMonth(chineseYear, chineseMonth);
    225             for (int i = 0; i < amount; i++) {
    226                 chineseDate++;
    227                 if (chineseDate > maxDate) {
    228                     chineseDate = 1;
    229                     chineseMonth = nextChineseMonth(chineseYear, chineseMonth);
    230                     if (chineseMonth == 1) {
    231                         chineseYear++;
    232                     }
    233                     maxDate = daysInChineseMonth(chineseYear, chineseMonth);
    234                 }
    235             }
    236         default:
    237             throw new IllegalArgumentException("不支持的field:" + field);
    238         }
    239  
    240         lastSetChinese = true;
    241         areFieldsSet = false;
    242         areChineseFieldsComputed = false;
    243         areSolarTermsComputed = false;
    244     }
    245  
    246     public void roll(int field, int amount) {
    247         computeIfNeed(field);
    248  
    249         if (!isChineseField(field)) {
    250             super.roll(field, amount);
    251             lastSetChinese = false;
    252             areChineseFieldsComputed = false;
    253             areSolarTermsComputed = false;
    254             return;
    255         }
    256  
    257         switch (field) {
    258         case CHINESE_YEAR:
    259             chineseYear += amount;
    260             break;
    261         case CHINESE_MONTH:
    262             for (int i = 0; i < amount; i++) {
    263                 chineseMonth = nextChineseMonth(chineseYear, chineseMonth);
    264             }
    265             break;
    266         case CHINESE_DATE:
    267             int maxDate = daysInChineseMonth(chineseYear, chineseMonth);
    268             for (int i = 0; i < amount; i++) {
    269                 chineseDate++;
    270                 if (chineseDate > maxDate) {
    271                     chineseDate = 1;
    272                 }
    273             }
    274         default:
    275             throw new IllegalArgumentException("不支持的field:" + field);
    276         }
    277  
    278         lastSetChinese = true;
    279         areFieldsSet = false;
    280         areChineseFieldsComputed = false;
    281         areSolarTermsComputed = false;
    282     }
    283  
    284     /**
    285      * 获得属性的中文,可以使用的属性字段为DAY_OF_WEEK以及所有农历属性字段。
    286      * 
    287      * @param field
    288      * @return
    289      */
    290     public String getChinese(int field) {
    291         computeIfNeed(field);
    292  
    293         switch (field) {
    294         case CHINESE_YEAR:
    295             return getChinese(CHINESE_HEAVENLY_STEM)
    296                     + getChinese(CHINESE_EARTHLY_BRANCH) + "年";
    297         case CHINESE_MONTH:
    298             if (chineseMonth > 0)
    299                 return chineseMonthNames[chineseMonth] + "月";
    300             else
    301                 return "闰" + chineseMonthNames[-chineseMonth] + "月";
    302         case CHINESE_DATE:
    303             return chineseDateNames[chineseDate];
    304         case CHINESE_SECTIONAL_TERM:
    305             return sectionalTermNames[get(Calendar.MONTH)];
    306         case CHINESE_PRINCIPLE_TERM:
    307             return principleTermNames[get(Calendar.MONTH)];
    308         case CHINESE_HEAVENLY_STEM:
    309             return stemNames[get(field)];
    310         case CHINESE_EARTHLY_BRANCH:
    311             return branchNames[get(field)];
    312         case CHINESE_ZODIAC:
    313             return animalNames[get(field)];
    314         case Calendar.DAY_OF_WEEK:
    315             return chineseWeekNames[get(field)];
    316         case CHINESE_TERM_OR_DATE:
    317             return getChinese(get(CHINESE_TERM_OR_DATE));
    318         case LUNAR_FESTIVAL:
    319             return getLunarFestival();
    320         case SOLAR_FESTIVAL:
    321             return getSolarFestival();
    322         case FESTIVAL_OR_TERM_OR_DATE:
    323             return getFestivalOrTermOrDate();
    324             // TODO CHECK
    325         case CHINESE_MONTH_OR_DATE:
    326             return getChinese(get(CHINESE_MONTH_OR_DATE));
    327         case CHINESE_TERM:
    328             return getChineseTerm();
    329         default:
    330             throw new IllegalArgumentException("不支持的field中文获取:" + field);
    331         }
    332     }
    333  
    334     public String getSimpleGregorianDateString() {
    335         return new StringBuffer().append(get(YEAR)).append("-")
    336                 .append(get(MONTH) + 1).append("-").append(get(DATE))
    337                 .toString();
    338     }
    339  
    340     public String getSimpleChineseDateString() {
    341         return new StringBuffer()
    342                 .append(get(CHINESE_YEAR))
    343                 .append("-")
    344                 .append(get(CHINESE_MONTH) > 0 ? "" + get(CHINESE_MONTH) : "*"
    345                         + (-get(CHINESE_MONTH))).append("-")
    346                 .append(get(CHINESE_DATE)).toString();
    347     }
    348  
    349     public String getChineseDateString() {
    350         return new StringBuffer().append(getChinese(CHINESE_YEAR))
    351                 .append(getChinese(CHINESE_MONTH))
    352                 .append(getChinese(CHINESE_DATE)).toString();
    353     }
    354  
    355     public String toString() {
    356         StringBuffer buf = new StringBuffer();
    357         buf.append(getSimpleGregorianDateString()).append(" | ")
    358                 .append(getChinese(DAY_OF_WEEK)).append(" | [农历]")
    359                 .append(getChineseDateString()).append(" ")
    360                 .append(getChinese(CHINESE_ZODIAC)).append("年 ")
    361                 .append(get(CHINESE_SECTIONAL_TERM)).append("日")
    362                 .append(getChinese(CHINESE_SECTIONAL_TERM)).append(" ")
    363                 .append(get(CHINESE_PRINCIPLE_TERM)).append("日")
    364                 .append(getChinese(CHINESE_PRINCIPLE_TERM));
    365         return buf.toString();
    366     }
    367  
    368     /**
    369      * 判断是不是农历属性
    370      * 
    371      * @param field
    372      * @return
    373      */
    374     private boolean isChineseField(int field) {
    375         switch (field) {
    376         case CHINESE_YEAR:
    377         case CHINESE_MONTH:
    378         case CHINESE_DATE:
    379         case CHINESE_SECTIONAL_TERM:
    380         case CHINESE_PRINCIPLE_TERM:
    381         case CHINESE_HEAVENLY_STEM:
    382         case CHINESE_EARTHLY_BRANCH:
    383         case CHINESE_ZODIAC:
    384         case CHINESE_TERM_OR_DATE:
    385         case CHINESE_MONTH_OR_DATE:
    386             return true;
    387         default:
    388             return false;
    389         }
    390     }
    391  
    392     /**
    393      * 判断是不是与节气有关的属性
    394      * 
    395      * @param field
    396      * @return
    397      */
    398     private boolean isChineseTermsField(int field) {
    399         switch (field) {
    400         case CHINESE_SECTIONAL_TERM:
    401         case CHINESE_PRINCIPLE_TERM:
    402         case CHINESE_TERM_OR_DATE:
    403             return true;
    404         default:
    405             return false;
    406         }
    407     }
    408  
    409     /**
    410      * 如果上一次设置的与这次将要设置或获取的属性不是同一类(农历/公历),<br>
    411      * 例如上一次设置的是农历而现在要设置或获取公历,<br>
    412      * 则需要先根据之前设置的农历日期计算出公历日期。
    413      * 
    414      * @param field
    415      */
    416     private void computeIfNeed(int field) {
    417         if (isChineseField(field)) {
    418             if (!lastSetChinese && !areChineseFieldsComputed) {
    419                 super.complete();
    420                 computeChineseFields();
    421                 areFieldsSet = true;
    422                 areChineseFieldsComputed = true;
    423                 areSolarTermsComputed = false;
    424             }
    425             if (isChineseTermsField(field) && !areSolarTermsComputed) {
    426                 computeSolarTerms();
    427                 areSolarTermsComputed = true;
    428             }
    429         } else {
    430             if (lastSetChinese && !areFieldsSet) {
    431                 computeGregorianFields();
    432                 super.complete();
    433                 areFieldsSet = true;
    434                 areChineseFieldsComputed = true;
    435                 areSolarTermsComputed = false;
    436             }
    437         }
    438     }
    439  
    440     /**
    441      * 使用农历日期计算出公历日期
    442      */
    443     private void computeGregorianFields() {
    444         int y = chineseYear;
    445         int m = chineseMonth;
    446         int d = chineseDate;
    447         areChineseFieldsComputed = true;
    448         areFieldsSet = true;
    449         lastSetChinese = false;
    450  
    451         // 调整日期范围
    452         if (y < 1900)
    453             y = 1899;
    454         else if (y > 2100)
    455             y = 2101;
    456  
    457         if (m < -12)
    458             m = -12;
    459         else if (m > 12)
    460             m = 12;
    461  
    462         if (d < 1)
    463             d = 1;
    464         else if (d > 30)
    465             d = 30;
    466  
    467         int dateint = y * 10000 + Math.abs(m) * 100 + d;
    468         if (dateint < 19001111) { // 太小
    469             set(1901, Calendar.JANUARY, 1);
    470             super.complete();
    471         } else if (dateint > 21001201) { // 太大
    472             set(2100, Calendar.DECEMBER, 31);
    473             super.complete();
    474         } else {
    475             if (Math.abs(m) > 12) {
    476                 m = 12;
    477             }
    478             int days = ChineseCalendar.daysInChineseMonth(y, m);
    479             if (days == 0) {
    480                 m = -m;
    481                 days = ChineseCalendar.daysInChineseMonth(y, m);
    482             }
    483             if (d > days) {
    484                 d = days;
    485             }
    486             set(y, Math.abs(m) - 1, d);
    487             computeChineseFields();
    488  
    489             int amount = 0;
    490             while (chineseYear != y || chineseMonth != m) {
    491                 amount += daysInChineseMonth(chineseYear, chineseMonth);
    492                 chineseMonth = nextChineseMonth(chineseYear, chineseMonth);
    493                 if (chineseMonth == 1) {
    494                     chineseYear++;
    495                 }
    496             }
    497             amount += d - chineseDate;
    498  
    499             super.add(Calendar.DATE, amount);
    500         }
    501         computeChineseFields();
    502     }
    503  
    504     /**
    505      * 使用公历日期计算出农历日期
    506      */
    507     private void computeChineseFields() {
    508         int gregorianYear = internalGet(Calendar.YEAR);
    509         int gregorianMonth = internalGet(Calendar.MONTH) + 1;
    510         int gregorianDate = internalGet(Calendar.DATE);
    511  
    512         if (gregorianYear < 1901 || gregorianYear > 2100) {
    513             return;
    514         }
    515  
    516         int startYear, startMonth, startDate;
    517         if (gregorianYear < 2000) {
    518             startYear = baseYear;
    519             startMonth = baseMonth;
    520             startDate = baseDate;
    521             chineseYear = baseChineseYear;
    522             chineseMonth = baseChineseMonth;
    523             chineseDate = baseChineseDate;
    524         } else {
    525             // 第二个对应日,用以提高计算效率
    526             // 公历 2000 年 1 月 1 日,对应农历 4697(1999) 年 11 月 25 日
    527             startYear = baseYear + 99;
    528             startMonth = 1;
    529             startDate = 1;
    530             chineseYear = baseChineseYear + 99;
    531             chineseMonth = 11;
    532             chineseDate = 25;
    533         }
    534  
    535         int daysDiff = 0;
    536  
    537         //
    538         for (int i = startYear; i < gregorianYear; i++) {
    539             if (isGregorianLeapYear(i)) {
    540                 daysDiff += 366; // leap year
    541             } else {
    542                 daysDiff += 365;
    543             }
    544         }
    545  
    546         //
    547         for (int i = startMonth; i < gregorianMonth; i++) {
    548             daysDiff += daysInGregorianMonth(gregorianYear, i - 1);
    549         }
    550  
    551         //
    552         daysDiff += gregorianDate - startDate;
    553  
    554         chineseDate += daysDiff;
    555  
    556         int lastDate = daysInChineseMonth(chineseYear, chineseMonth);
    557         while (chineseDate > lastDate) {
    558             chineseDate -= lastDate;
    559             chineseMonth = nextChineseMonth(chineseYear, chineseMonth);
    560             if (chineseMonth == 1) {
    561                 chineseYear++;
    562             }
    563             lastDate = daysInChineseMonth(chineseYear, chineseMonth);
    564         }
    565  
    566     }
    567  
    568     /**
    569      * 计算节气
    570      */
    571     private void computeSolarTerms() {
    572         int gregorianYear = internalGet(Calendar.YEAR);
    573         int gregorianMonth = internalGet(Calendar.MONTH);
    574  
    575         if (gregorianYear < 1901 || gregorianYear > 2100) {
    576             return;
    577         }
    578         sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth);
    579         principleTerm = principleTerm(gregorianYear, gregorianMonth);
    580     }
    581  
    582     /* 接下来是静态方法~ */
    583     /**
    584      * 是否为公历闰年
    585      * 
    586      * @param year
    587      * @return
    588      */
    589     public static boolean isGregorianLeapYear(int year) {
    590         boolean isLeap = false;
    591         if (year % 4 == 0) {
    592             isLeap = true;
    593         }
    594         if (year % 100 == 0) {
    595             isLeap = false;
    596         }
    597         if (year % 400 == 0) {
    598             isLeap = true;
    599         }
    600         return isLeap;
    601     }
    602  
    603     /**
    604      * 计算公历年的当月天数,公历月从0起始!
    605      * 
    606      * @param y
    607      * @param m
    608      * @return
    609      */
    610     public static int daysInGregorianMonth(int y, int m) {
    611         int d = daysInGregorianMonth[m];
    612         if (m == Calendar.FEBRUARY && isGregorianLeapYear(y)) {
    613             d++; // 公历闰年二月多一天
    614         }
    615         return d;
    616     }
    617  
    618     /**
    619      * 计算公历年当月的节气,公历月从0起始!
    620      * 
    621      * @param y
    622      * @param m
    623      * @return
    624      */
    625     public static int sectionalTerm(int y, int m) {
    626         m++;
    627         if (y < 1901 || y > 2100) {
    628             return 0;
    629         }
    630         int index = 0;
    631         int ry = y - baseYear + 1;
    632         while (ry >= sectionalTermYear[m - 1][index]) {
    633             index++;
    634         }
    635         int term = sectionalTermMap[m - 1][4 * index + ry % 4];
    636         if ((ry == 121) && (m == 4)) {
    637             term = 5;
    638         }
    639         if ((ry == 132) && (m == 4)) {
    640             term = 5;
    641         }
    642         if ((ry == 194) && (m == 6)) {
    643             term = 6;
    644         }
    645         return term;
    646     }
    647  
    648     /**
    649      * 计算公历年当月的中气,公历月从0起始!
    650      * 
    651      * @param y
    652      * @param m
    653      * @return
    654      */
    655     public static int principleTerm(int y, int m) {
    656         m++;
    657         if (y < 1901 || y > 2100) {
    658             return 0;
    659         }
    660         int index = 0;
    661         int ry = y - baseYear + 1;
    662         while (ry >= principleTermYear[m - 1][index]) {
    663             index++;
    664         }
    665         int term = principleTermMap[m - 1][4 * index + ry % 4];
    666         if ((ry == 171) && (m == 3)) {
    667             term = 21;
    668         }
    669         if ((ry == 181) && (m == 5)) {
    670             term = 21;
    671         }
    672         return term;
    673     }
    674  
    675     /**
    676      * 计算农历年的天数
    677      * 
    678      * @param y
    679      * @param m
    680      * @return
    681      */
    682     public static int daysInChineseMonth(int y, int m) {
    683         // 注意:闰月 m < 0
    684         int index = y - baseChineseYear + baseIndex;
    685         int v = 0;
    686         int l = 0;
    687         int d = 30;
    688         if (1 <= m && m <= 8) {
    689             v = chineseMonths[2 * index];
    690             l = m - 1;
    691             if (((v >> l) & 0x01) == 1) {
    692                 d = 29;
    693             }
    694         } else if (9 <= m && m <= 12) {
    695             v = chineseMonths[2 * index + 1];
    696             l = m - 9;
    697             if (((v >> l) & 0x01) == 1) {
    698                 d = 29;
    699             }
    700         } else {
    701             v = chineseMonths[2 * index + 1];
    702             v = (v >> 4) & 0x0F;
    703             if (v != Math.abs(m)) {
    704                 d = 0;
    705             } else {
    706                 d = 29;
    707                 for (int i = 0; i < bigLeapMonthYears.length; i++) {
    708                     if (bigLeapMonthYears[i] == index) {
    709                         d = 30;
    710                         break;
    711                     }
    712                 }
    713             }
    714         }
    715         return d;
    716     }
    717  
    718     /**
    719      * 计算农历的下个月
    720      * 
    721      * @param y
    722      * @param m
    723      * @return
    724      */
    725     public static int nextChineseMonth(int y, int m) {
    726         int n = Math.abs(m) + 1;
    727         if (m > 0) {
    728             int index = y - baseChineseYear + baseIndex;
    729             int v = chineseMonths[2 * index + 1];
    730             v = (v >> 4) & 0x0F;
    731             if (v == m) {
    732                 n = -m;
    733             }
    734         }
    735         if (n == 13) {
    736             n = 1;
    737         }
    738         return n;
    739     }
    740  
    741     /* 日历第一天的日期 */
    742     private static final int baseYear = 1901;
    743     private static final int baseMonth = 1;
    744     private static final int baseDate = 1;
    745     private static final int baseIndex = 0;
    746     private static final int baseChineseYear = 1900;
    747     private static final int baseChineseMonth = 11;
    748     private static final int baseChineseDate = 11;
    749  
    750     /* 中文字符串 */
    751     private static final String[] chineseWeekNames = { "", "星期日", "星期一", "星期二",
    752             "星期三", "星期四", "星期五", "星期六" };
    753     private static final String[] chineseMonthNames = { "", "正", "二", "三", "四",
    754             "五", "六", "七", "八", "九", "十", "十一", "十二" };
    755     private static final String[] chineseDateNames = { "", "初一", "初二", "初三",
    756             "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一", "十二", "十三", "十四",
    757             "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五",
    758             "廿六", "廿七", "廿八", "廿九", "三十" };
    759     private static final String[] principleTermNames = { "大寒", "雨水", "春分",
    760             "谷雨", "夏满", "夏至", "大暑", "处暑", "秋分", "霜降", "小雪", "冬至" };
    761     private static final String[] sectionalTermNames = { "小寒", "立春", "惊蛰",
    762             "清明", "立夏", "芒种", "小暑", "立秋", "白露", "寒露", "立冬", "大雪" };
    763     private static final String[] stemNames = { "", "甲", "乙", "丙", "丁", "戊",
    764             "己", "庚", "辛", "壬", "癸" };
    765     private static final String[] branchNames = { "", "子", "丑", "寅", "卯", "辰",
    766             "巳", "午", "未", "申", "酉", "戌", "亥" };
    767     private static final String[] animalNames = { "", "鼠", "牛", "虎", "兔", "龙",
    768             "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
    769  
    770     /* 接下来是数据压缩表~ */
    771     private static final int[] bigLeapMonthYears = { 6, 14, 19, 25, 33, 36, 38,
    772             41, 44, 52, 55, 79, 117, 136, 147, 150, 155, 158, 185, 193 };
    773     private static final char[][] sectionalTermMap = {
    774             { 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 5, 5,
    775                     5, 5, 5, 4, 5, 5 },
    776             { 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 3,
    777                     3, 4, 4, 3, 3, 3 },
    778             { 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
    779                     5, 5, 4, 5, 5, 5, 5 },
    780             { 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4,
    781                     4, 5, 4, 4, 4, 4, 5 },
    782             { 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
    783                     5, 5, 4, 5, 5, 5, 5 },
    784             { 6, 6, 7, 7, 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5,
    785                     5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5 },
    786             { 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
    787                     7, 7, 6, 6, 6, 7, 7 },
    788             { 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
    789                     7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7 },
    790             { 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
    791                     7, 7, 6, 7, 7, 7, 7 },
    792             { 9, 9, 9, 9, 8, 9, 9, 9, 8, 8, 9, 9, 8, 8, 8, 9, 8, 8, 8, 8, 7, 8,
    793                     8, 8, 7, 7, 8, 8, 8 },
    794             { 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7,
    795                     7, 7, 6, 6, 7, 7, 7 },
    796             { 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
    797                     7, 7, 6, 6, 6, 7, 7 } };
    798     private static final char[][] sectionalTermYear = {
    799             { 13, 49, 85, 117, 149, 185, 201, 250, 250 },
    800             { 13, 45, 81, 117, 149, 185, 201, 250, 250 },
    801             { 13, 48, 84, 112, 148, 184, 200, 201, 250 },
    802             { 13, 45, 76, 108, 140, 172, 200, 201, 250 },
    803             { 13, 44, 72, 104, 132, 168, 200, 201, 250 },
    804             { 5, 33, 68, 96, 124, 152, 188, 200, 201 },
    805             { 29, 57, 85, 120, 148, 176, 200, 201, 250 },
    806             { 13, 48, 76, 104, 132, 168, 196, 200, 201 },
    807             { 25, 60, 88, 120, 148, 184, 200, 201, 250 },
    808             { 16, 44, 76, 108, 144, 172, 200, 201, 250 },
    809             { 28, 60, 92, 124, 160, 192, 200, 201, 250 },
    810             { 17, 53, 85, 124, 156, 188, 200, 201, 250 } };
    811     private static final char[][] principleTermMap = {
    812             { 21, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20,
    813                     20, 20, 20, 20, 20, 19, 20, 20, 20, 19, 19, 20 },
    814             { 20, 19, 19, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, 19, 19,
    815                     19, 18, 18, 19, 19, 18, 18, 18, 18, 18, 18, 18 },
    816             { 21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21,
    817                     20, 20, 20, 21, 20, 20, 20, 20, 19, 20, 20, 20, 20 },
    818             { 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 20, 20, 20, 20,
    819                     19, 20, 20, 20, 19, 19, 20, 20, 19, 19, 19, 20, 20 },
    820             { 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21,
    821                     20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 21 },
    822             { 22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22,
    823                     21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 21 },
    824             { 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23,
    825                     22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 23 },
    826             { 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
    827                     22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 },
    828             { 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
    829                     22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 },
    830             { 24, 24, 24, 24, 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24,
    831                     23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 23 },
    832             { 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23,
    833                     22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 22 },
    834             { 22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 21, 22, 22, 22,
    835                     21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 22 } };
    836     private static final char[][] principleTermYear = {
    837             { 13, 45, 81, 113, 149, 185, 201 },
    838             { 21, 57, 93, 125, 161, 193, 201 },
    839             { 21, 56, 88, 120, 152, 188, 200, 201 },
    840             { 21, 49, 81, 116, 144, 176, 200, 201 },
    841             { 17, 49, 77, 112, 140, 168, 200, 201 },
    842             { 28, 60, 88, 116, 148, 180, 200, 201 },
    843             { 25, 53, 84, 112, 144, 172, 200, 201 },
    844             { 29, 57, 89, 120, 148, 180, 200, 201 },
    845             { 17, 45, 73, 108, 140, 168, 200, 201 },
    846             { 28, 60, 92, 124, 160, 192, 200, 201 },
    847             { 16, 44, 80, 112, 148, 180, 200, 201 },
    848             { 17, 53, 88, 120, 156, 188, 200, 201 } };
    849  
    850     private static final char[] daysInGregorianMonth = { 31, 28, 31, 30, 31,
    851             30, 31, 31, 30, 31, 30, 31 };
    852     private static final char[] chineseMonths = { 0x00, 0x04, 0xad, 0x08, 0x5a,
    853             0x01, 0xd5, 0x54, 0xb4, 0x09, 0x64, 0x05, 0x59, 0x45, 0x95, 0x0a,
    854             0xa6, 0x04, 0x55, 0x24, 0xad, 0x08, 0x5a, 0x62, 0xda, 0x04, 0xb4,
    855             0x05, 0xb4, 0x55, 0x52, 0x0d, 0x94, 0x0a, 0x4a, 0x2a, 0x56, 0x02,
    856             0x6d, 0x71, 0x6d, 0x01, 0xda, 0x02, 0xd2, 0x52, 0xa9, 0x05, 0x49,
    857             0x0d, 0x2a, 0x45, 0x2b, 0x09, 0x56, 0x01, 0xb5, 0x20, 0x6d, 0x01,
    858             0x59, 0x69, 0xd4, 0x0a, 0xa8, 0x05, 0xa9, 0x56, 0xa5, 0x04, 0x2b,
    859             0x09, 0x9e, 0x38, 0xb6, 0x08, 0xec, 0x74, 0x6c, 0x05, 0xd4, 0x0a,
    860             0xe4, 0x6a, 0x52, 0x05, 0x95, 0x0a, 0x5a, 0x42, 0x5b, 0x04, 0xb6,
    861             0x04, 0xb4, 0x22, 0x6a, 0x05, 0x52, 0x75, 0xc9, 0x0a, 0x52, 0x05,
    862             0x35, 0x55, 0x4d, 0x0a, 0x5a, 0x02, 0x5d, 0x31, 0xb5, 0x02, 0x6a,
    863             0x8a, 0x68, 0x05, 0xa9, 0x0a, 0x8a, 0x6a, 0x2a, 0x05, 0x2d, 0x09,
    864             0xaa, 0x48, 0x5a, 0x01, 0xb5, 0x09, 0xb0, 0x39, 0x64, 0x05, 0x25,
    865             0x75, 0x95, 0x0a, 0x96, 0x04, 0x4d, 0x54, 0xad, 0x04, 0xda, 0x04,
    866             0xd4, 0x44, 0xb4, 0x05, 0x54, 0x85, 0x52, 0x0d, 0x92, 0x0a, 0x56,
    867             0x6a, 0x56, 0x02, 0x6d, 0x02, 0x6a, 0x41, 0xda, 0x02, 0xb2, 0xa1,
    868             0xa9, 0x05, 0x49, 0x0d, 0x0a, 0x6d, 0x2a, 0x09, 0x56, 0x01, 0xad,
    869             0x50, 0x6d, 0x01, 0xd9, 0x02, 0xd1, 0x3a, 0xa8, 0x05, 0x29, 0x85,
    870             0xa5, 0x0c, 0x2a, 0x09, 0x96, 0x54, 0xb6, 0x08, 0x6c, 0x09, 0x64,
    871             0x45, 0xd4, 0x0a, 0xa4, 0x05, 0x51, 0x25, 0x95, 0x0a, 0x2a, 0x72,
    872             0x5b, 0x04, 0xb6, 0x04, 0xac, 0x52, 0x6a, 0x05, 0xd2, 0x0a, 0xa2,
    873             0x4a, 0x4a, 0x05, 0x55, 0x94, 0x2d, 0x0a, 0x5a, 0x02, 0x75, 0x61,
    874             0xb5, 0x02, 0x6a, 0x03, 0x61, 0x45, 0xa9, 0x0a, 0x4a, 0x05, 0x25,
    875             0x25, 0x2d, 0x09, 0x9a, 0x68, 0xda, 0x08, 0xb4, 0x09, 0xa8, 0x59,
    876             0x54, 0x03, 0xa5, 0x0a, 0x91, 0x3a, 0x96, 0x04, 0xad, 0xb0, 0xad,
    877             0x04, 0xda, 0x04, 0xf4, 0x62, 0xb4, 0x05, 0x54, 0x0b, 0x44, 0x5d,
    878             0x52, 0x0a, 0x95, 0x04, 0x55, 0x22, 0x6d, 0x02, 0x5a, 0x71, 0xda,
    879             0x02, 0xaa, 0x05, 0xb2, 0x55, 0x49, 0x0b, 0x4a, 0x0a, 0x2d, 0x39,
    880             0x36, 0x01, 0x6d, 0x80, 0x6d, 0x01, 0xd9, 0x02, 0xe9, 0x6a, 0xa8,
    881             0x05, 0x29, 0x0b, 0x9a, 0x4c, 0xaa, 0x08, 0xb6, 0x08, 0xb4, 0x38,
    882             0x6c, 0x09, 0x54, 0x75, 0xd4, 0x0a, 0xa4, 0x05, 0x45, 0x55, 0x95,
    883             0x0a, 0x9a, 0x04, 0x55, 0x44, 0xb5, 0x04, 0x6a, 0x82, 0x6a, 0x05,
    884             0xd2, 0x0a, 0x92, 0x6a, 0x4a, 0x05, 0x55, 0x0a, 0x2a, 0x4a, 0x5a,
    885             0x02, 0xb5, 0x02, 0xb2, 0x31, 0x69, 0x03, 0x31, 0x73, 0xa9, 0x0a,
    886             0x4a, 0x05, 0x2d, 0x55, 0x2d, 0x09, 0x5a, 0x01, 0xd5, 0x48, 0xb4,
    887             0x09, 0x68, 0x89, 0x54, 0x0b, 0xa4, 0x0a, 0xa5, 0x6a, 0x95, 0x04,
    888             0xad, 0x08, 0x6a, 0x44, 0xda, 0x04, 0x74, 0x05, 0xb0, 0x25, 0x54,
    889             0x03 };
    890     
    891     private String getChineseTerm() {
    892       if (get(Calendar.DATE) == get(CHINESE_SECTIONAL_TERM)) {
    893           return sectionalTermNames[get(Calendar.MONTH)];
    894       } else if (get(Calendar.DATE) == get(CHINESE_PRINCIPLE_TERM)) {
    895           return principleTermNames[get(Calendar.MONTH)];
    896       } else
    897           return null;
    898     }
    899     // add by skywang
    900     private String getLunarFestival() {
    901         int day = get(CHINESE_DATE);
    902         int month = get(CHINESE_MONTH);
    903         String sToday = day < 10 ?  "0" + day:"" + day;  
    904         String sMonth = month<10 ?  "0" +(month):""+(month);
    905 
    906         return lFestival.get(sMonth+sToday);        
    907     }
    908     private String getSolarFestival() {
    909         int day = get(Calendar.DATE);  
    910         int month = get(Calendar.MONTH);  
    911         String sToday = day < 10 ?  "0" + day:"" + day;  
    912         String sMonth = month<10 ?  "0" +(month+1):""+(month+1);
    913 
    914         return sFestival.get(sMonth+sToday);
    915     }
    916     private String getFestivalOrTermOrDate() {
    917         String ret;
    918         if ((ret = getSolarFestival()) != null)
    919             return ret;
    920         if ((ret = getLunarFestival()) != null)
    921             return ret;        
    922         return getChinese(get(CHINESE_TERM_OR_DATE));
    923     }
    924 
    925 
    926     //公历节日
    927     private static HashMap<String,String> sFestival =new HashMap<String,String>();
    928     // 农历介入
    929     private static HashMap<String,String> lFestival =new HashMap<String,String>(); 
    930     static {
    931         sFestival.put("0101","元旦");  
    932         sFestival.put("0214","情人节");  
    933         sFestival.put("0308","妇女节");  
    934         sFestival.put("0312","植树节");  
    935         sFestival.put("0401","愚人节");  
    936         sFestival.put("0501","劳动节");  
    937         sFestival.put("0504","青年节");  
    938         sFestival.put("0601","儿童节");  
    939         sFestival.put("0701","建党节");  
    940         sFestival.put("0801","建军节");  
    941         sFestival.put("0910","教师节");  
    942         sFestival.put("1001","国庆节");  
    943         sFestival.put("1031","万圣节");  
    944 //        sFestival.put("1112","孙中山诞辰");  
    945         sFestival.put("1225","圣诞节");      
    946 
    947         lFestival.put("0101","春节");  
    948 //        lFestival.put("0102","大年初二");  
    949 //        lFestival.put("0103","大年初三");  
    950         lFestival.put("0115","元宵节");  
    951         lFestival.put("0505","端午节");  
    952         lFestival.put("0707","七夕");
    953         lFestival.put("0815","中秋节");  
    954         lFestival.put("0909","重阳节");  
    955         lFestival.put("1208","腊八节");  
    956 //        lFestival.put("1299","除夕");
    957     } 
    958 }
    View Code

     

    自定义的Calendar接口

    这些接口在写日历程序时可能会用到。

    源代码如下(CalendarSelfDefineTest.java):

      1 import java.util.Calendar;
      2 
      3 /**
      4  * 根据Calendar的API封装的一些常用函数
      5  * 
      6  * @author skywang
      7  * @email kuiwu-wang@163.com
      8  */
      9 public class CalendarSelfDefineTest {
     10 
     11     public static void main(String[] args) {
     12         Calendar cal = Calendar.getInstance();
     13 
     14         // 设置日期为“2013-09-18”
     15         cal.set(2013, Calendar.SEPTEMBER, 18);
     16 
     17         // 获取“年”
     18         System.out.printf("year: %s
    ", getYear(cal) );
     19         // 获取“月”
     20         System.out.printf("month: %s
    ", getMonth(cal) );
     21         // 获取“上月”
     22         System.out.printf("previcou month: %s
    ", getLastMonth(cal) );
     23         // 获取“下月”
     24         System.out.printf("next month: %s
    ", getNextMonth(cal) );
     25         // 获取“日”
     26         System.out.printf("day: %s
    ", getDay(cal) );
     27         // 获取Cal对应星期几
     28         System.out.printf("weekday: %s
    ", getWeekDay(cal) );
     29         // 本月天数
     30         System.out.printf("Current Month days: %s
    ", getMonthDays(cal) );
     31         // 上月天数
     32         System.out.printf("Previcous Month days: %s
    ", getPrevMonthDays(cal) );
     33         // 下月天数
     34         System.out.printf("Next Month days: %s
    ", getNextMonthDays(cal) );
     35         // 获取当月第一天的星期几
     36         System.out.printf("First day' weekday : %s
    ", getFirstDayWeekday(cal) );
     37         // 获取当前月最后一天的星期几
     38         System.out.printf("Last day' weekday : %s
    ", getLastDayWeekday(cal) );
     39         // 获取上月最后一天的星期几
     40         System.out.printf("PrevMonth Last day' weekday: %s
    ", getLastDayWeekdayOfPrevMonth(cal) );
     41         // 获取下月第一天的星期几
     42         System.out.printf("NextMonth First day' weekday: %s
    ", getFirstDayWeekdayOfNextMonth(cal) );
     43     }
     44 
     45     /**
     46      * 获取“年”
     47      * 
     48      * @return 例如,2013-09-18,则返回2013
     49      */
     50     public static int getYear(Calendar cal) {
     51         return cal.get(Calendar.YEAR);
     52     } 
     53 
     54     /**
     55      * 获取“月”
     56      * 
     57      * @return 返回值可以为以下值:
     58      *  JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
     59      *  其中第一个月是 JANUARY,它为 0。
     60      *
     61      *  例如,2013-09-18,则返回8
     62      */
     63     public static int getMonth(Calendar cal) {
     64         return cal.get(Calendar.MONTH);
     65     } 
     66 
     67     /**
     68      * 获取“上一个月”
     69      * 
     70      * @return 返回值可以为以下值:
     71      *  JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
     72      *  其中第一个月是 JANUARY,它为 0。
     73      *
     74      *  例如,2012-01-12的上一个月是“11”(即DECEMBER)。
     75      */
     76     public static int getLastMonth(Calendar cal) {
     77         return (cal.get(Calendar.MONTH) + 11) % 12;
     78     } 
     79 
     80     /**
     81      * 获取“下一个月”
     82      * 
     83      * @return 返回值可以为以下值:
     84      *  JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
     85      *  其中第一个月是 JANUARY,它为 0。
     86      *
     87      *  例如,2013-12-12的下一个月是“1”(即DECEMBER)。
     88      */
     89     public static int getNextMonth(Calendar cal) {
     90         return (cal.get(Calendar.MONTH) + 13) % 12;
     91     } 
     92 
     93     /**
     94      * 获取“日”
     95      *
     96      * @return 例如,2013-09-18,则返回18
     97      *
     98      */
     99     public static int getDay(Calendar cal) {
    100         return cal.get(Calendar.DATE);
    101     } 
    102 
    103     /**
    104      * 获取“本月的天数”
    105      *
    106      * @return 例如,2013-09-18,则返回30
    107      *
    108      */
    109     public static int getMonthDays(Calendar cal) {
    110         return cal.getActualMaximum(Calendar.DATE);    
    111     } 
    112 
    113     /**
    114      * 获取“上一个月的天数”
    115      *
    116      * @return 例如,2013-01-18,则返回31 (因为2012-12有31天)
    117      *
    118      */
    119     public static int getPrevMonthDays(Calendar cal) {
    120         Calendar tmpCal = (Calendar)cal.clone();        // 克隆cal。后面对tmpCal操作,就不会改变cal
    121         tmpCal.add(Calendar.MONTH, -1);                    // 设为“上一个月”
    122         return tmpCal.getActualMaximum(Calendar.DATE);    
    123     } 
    124 
    125     /**
    126      * 获取“下一个月的天数”
    127      *
    128      * @return 例如,2013-12-18,则返回31 (因为2014-01有31天)
    129      *
    130      */
    131     public static int getNextMonthDays(Calendar cal) {
    132         Calendar tmpCal = (Calendar)cal.clone();        // 克隆cal。后面对tmpCal操作,就不会改变cal
    133         tmpCal.add(Calendar.MONTH, 1);                    // 设为“下一个月”
    134         return tmpCal.getActualMaximum(Calendar.DATE);    
    135     } 
    136 
    137     /**
    138      * 获取Cal对应星期几
    139      *
    140      * @return 返回“星期几”,可以为以下值:
    141      *   SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY 和 SATURDAY。
    142      *   SUNDAY为1,MONDAY为2,依次类推。
    143      * 例如,2013-09-18(星期三),则返回4
    144      */
    145     public static int getWeekDay(Calendar cal) {
    146         return cal.get(Calendar.DAY_OF_WEEK);
    147     } 
    148 
    149 
    150     /**
    151      * 获取当月第一天对应星期几
    152      *
    153      * @return SUNDAY为1,MONDAY为2,依次类推。
    154      */
    155     public static int getFirstDayWeekday(Calendar cal) {
    156         
    157         Calendar tmpCal = (Calendar)cal.clone();        // 克隆cal。后面对tmpCal操作,就不会改变cal
    158         tmpCal.set(Calendar.DATE, 1);                    // 把日期设置为当月第一天    
    159         return tmpCal.get(Calendar.DAY_OF_WEEK);
    160     } 
    161 
    162     /**
    163      * 获取当前月最后一天对应星期几
    164      * 
    165      * @return SUNDAY为1,MONDAY为2,依次类推。
    166      */
    167     public static int getLastDayWeekday(Calendar cal) {
    168         Calendar tmpCal = (Calendar)cal.clone();        // 克隆cal。后面对tmpCal操作,就不会改变cal
    169         tmpCal.set(Calendar.DATE, 1);                    // 把日期设置为当月第一天    
    170         tmpCal.roll(Calendar.DATE, -1);                    // 把日期设置为当月最后一天    
    171         return tmpCal.get(Calendar.DAY_OF_WEEK);
    172     } 
    173 
    174 
    175     /**
    176      * 获取上月最后一天的星期几
    177      * 
    178      * @return SUNDAY为1,MONDAY为2,依次类推。
    179      */
    180     public static int getLastDayWeekdayOfPrevMonth(Calendar cal) {
    181         
    182         Calendar tmpCal = (Calendar)cal.clone();        // 克隆cal。后面对tmpCal操作,就不会改变cal
    183         tmpCal.set(Calendar.DATE, 1);                    // 把日期设置为当月第一天    
    184         tmpCal.add(Calendar.DATE, -1);                    // 把日期设置为上一个月最后一天    
    185         return tmpCal.get(Calendar.DAY_OF_WEEK);
    186     } 
    187 
    188     /**
    189      * 获取下月第一天的星期偏移
    190      * 
    191      * @return SUNDAY为1,MONDAY为2,依次类推。
    192      */
    193     public static int getFirstDayWeekdayOfNextMonth(Calendar cal) {
    194         
    195         Calendar tmpCal = (Calendar)cal.clone();        // 克隆cal。后面对tmpCal操作,就不会改变cal
    196         tmpCal.add(Calendar.MONTH, 1);                    // 设为“下一个月”
    197         tmpCal.set(Calendar.DATE, 1);                    // 设为“第一天”    
    198         return tmpCal.get(Calendar.DAY_OF_WEEK);
    199     } 
    200 }

    更多内容

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(3) Date

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(4) DateFormat

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(5) SimpleDateFormat

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(6) Locale

    Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(7) TimeZone

  • 相关阅读:
    寻找大富翁
    C++ STL sort()函数用法
    众数
    平方因子
    Hdu 1089 A+B for Input-Output Practice (I)
    Hdu 1090 A+B for Input-Output Practice (II)
    Hdu 1083 Courses
    Hdu 1069 Monkey and Banana
    Hdu 1062 Text Reverse
    Hdu 1068 Girls and Boys
  • 原文地址:https://www.cnblogs.com/skywang12345/p/3329653.html
Copyright © 2011-2022 走看看