中国阴历算法

中国农历算法
Java代码
  1. /**  
  2.  * ChineseCalendarGB.java  
  3.  * Copyright (c) 1997-2002 by Dr. Herong Yang  
  4.  * 中国农历算法 - 实用于公历 1901 年至 2100 年之间的 200 年  
  5.  */   
  6. import  java.text.*;  
  7. import  java.util.*;  
  8. class  ChineseCalendarGB {  
  9.    private   int  gregorianYear;  
  10.    private   int  gregorianMonth;  
  11.    private   int  gregorianDate;  
  12.    private   boolean  isGregorianLeap;  
  13.    private   int  dayOfYear;  
  14.    private   int  dayOfWeek;  // 周日一星期的第一天   
  15.    private   int  chineseYear;  
  16.    private   int  chineseMonth;  // 负数表示闰月   
  17.    private   int  chineseDate;  
  18.    private   int  sectionalTerm;  
  19.    private   int  principleTerm;  
  20.    private   static   char [] daysInGregorianMonth =  
  21.       {31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 };  
  22.    private   static  String[] stemNames =  
  23.       {"甲" , "乙" , "丙" , "丁" , "戊" , "己" , "庚" , "辛" , "壬" , "癸" };  
  24.    private   static  String[] branchNames =  
  25.       {"子" , "丑" , "寅" , "卯" , "辰" , "巳" , "午" , "未" , "申" , "酉" , "戌" , "亥" };  
  26.    private   static  String[] animalNames =  
  27.       {"鼠" , "牛" , "虎" , "兔" , "龙" , "蛇" , "马" , "羊" , "猴" , "鸡" , "狗" , "猪" };  
  28.    public   static   void  main(String[] arg) {  
  29.       ChineseCalendarGB c = new  ChineseCalendarGB();  
  30.       String cmd = "day" ;  
  31.       int  y =  1901 ;  
  32.       int  m =  1 ;  
  33.       int  d =  1 ;  
  34.       if  (arg.length> 0 ) cmd = arg[ 0 ];  
  35.       if  (arg.length> 1 ) y = Integer.parseInt(arg[ 1 ]);  
  36.       if  (arg.length> 2 ) m = Integer.parseInt(arg[ 2 ]);  
  37.       if  (arg.length> 3 ) d = Integer.parseInt(arg[ 3 ]);  
  38.       c.setGregorian(y,m,d);  
  39.       c.computeChineseFields();  
  40.       c.computeSolarTerms();  
  41.       if  (cmd.equalsIgnoreCase( "year" )) {  
  42.          String[] t = c.getYearTable();  
  43.          for  ( int  i= 0 ; i<t.length; i++) System.out.println(t[i]);  
  44.       } else   if  (cmd.equalsIgnoreCase( "month" )) {  
  45.          String[] t = c.getMonthTable();  
  46.          for  ( int  i= 0 ; i<t.length; i++) System.out.println(t[i]);  
  47.       } else  {  
  48.          System.out.println(c.toString());  
  49.       }  
  50.    }  
  51.    public  ChineseCalendarGB() {  
  52.       setGregorian(1901 , 1 , 1 );  
  53.    }  
  54.    public   void  setGregorian( int  y,  int  m,  int  d) {  
  55.       gregorianYear = y;  
  56.       gregorianMonth = m;  
  57.       gregorianDate = d;  
  58.       isGregorianLeap = isGregorianLeapYear(y);  
  59.       dayOfYear = dayOfYear(y,m,d);  
  60.       dayOfWeek = dayOfWeek(y,m,d);  
  61.       chineseYear = 0 ;  
  62.       chineseMonth = 0 ;  
  63.       chineseDate = 0 ;  
  64.       sectionalTerm = 0 ;  
  65.       principleTerm = 0 ;  
  66.    }  
  67.    public   static   boolean  isGregorianLeapYear( int  year) {  
  68.       boolean  isLeap =  false ;  
  69.       if  (year% 4 == 0 ) isLeap =  true ;  
  70.       if  (year% 100 == 0 ) isLeap =  false ;  
  71.       if  (year% 400 == 0 ) isLeap =  true ;  
  72.       return  isLeap;  
  73.    }  
  74.    public   static   int  daysInGregorianMonth( int  y,  int  m) {  
  75.       int  d = daysInGregorianMonth[m- 1 ];  
  76.       if  (m== 2  && isGregorianLeapYear(y)) d++;  // 公历闰年二月多一天   
  77.       return  d;  
  78.    }  
  79.    public   static   int  dayOfYear( int  y,  int  m,  int  d) {  
  80.       int  c =  0 ;  
  81.       for  ( int  i= 1 ; i<m; i++) {  
  82.          c = c + daysInGregorianMonth(y,i);  
  83.       }  
  84.       c = c + d;  
  85.       return  c;       
  86.    }  
  87.    public   static   int  dayOfWeek( int  y,  int  m,  int  d) {  
  88.       int  w =  1 // 公历一年一月一日是星期一,所以起始值为星期日   
  89.       y = (y-1 )% 400  +  1 // 公历星期值分部 400 年循环一次   
  90.       int  ly = (y- 1 )/ 4 // 闰年次数   
  91.       ly = ly - (y-1 )/ 100 ;  
  92.       ly = ly + (y-1 )/ 400 ;  
  93.       int  ry = y -  1  - ly;  // 常年次数   
  94.       w = w + ry; // 常年星期值增一   
  95.       w = w + 2 *ly;  // 闰年星期值增二   
  96.       w = w + dayOfYear(y,m,d);  
  97.       w = (w-1 )% 7  +  1 ;  
  98.       return  w;  
  99.    }  
  100.    private   static   char [] chineseMonths = {  
  101.    // 农历月份大小压缩表,两个字节表示一年。两个字节共十六个二进制位数,   
  102.    // 前四个位数表示闰月月份,后十二个位数表示十二个农历月份的大小。   
  103.    0x00 , 0x04 , 0xad , 0x08 , 0x5a , 0x01 , 0xd5 , 0x54 , 0xb4 , 0x09 , 0x64 , 0x05 , 0x59 , 0x45 ,  
  104.    0x95 , 0x0a , 0xa6 , 0x04 , 0x55 , 0x24 , 0xad , 0x08 , 0x5a , 0x62 , 0xda , 0x04 , 0xb4 , 0x05 ,  
  105.    0xb4 , 0x55 , 0x52 , 0x0d , 0x94 , 0x0a , 0x4a , 0x2a , 0x56 , 0x02 , 0x6d , 0x71 , 0x6d , 0x01 ,  
  106.    0xda , 0x02 , 0xd2 , 0x52 , 0xa9 , 0x05 , 0x49 , 0x0d , 0x2a , 0x45 , 0x2b , 0x09 , 0x56 , 0x01 ,  
  107.    0xb5 , 0x20 , 0x6d , 0x01 , 0x59 , 0x69 , 0xd4 , 0x0a , 0xa8 , 0x05 , 0xa9 , 0x56 , 0xa5 , 0x04 ,  
  108.    0x2b , 0x09 , 0x9e , 0x38 , 0xb6 , 0x08 , 0xec , 0x74 , 0x6c , 0x05 , 0xd4 , 0x0a , 0xe4 , 0x6a ,  
  109.    0x52 , 0x05 , 0x95 , 0x0a , 0x5a , 0x42 , 0x5b , 0x04 , 0xb6 , 0x04 , 0xb4 , 0x22 , 0x6a , 0x05 ,  
  110.    0x52 , 0x75 , 0xc9 , 0x0a , 0x52 , 0x05 , 0x35 , 0x55 , 0x4d , 0x0a , 0x5a , 0x02 , 0x5d , 0x31 ,  
  111.    0xb5 , 0x02 , 0x6a , 0x8a , 0x68 , 0x05 , 0xa9 , 0x0a , 0x8a , 0x6a , 0x2a , 0x05 , 0x2d , 0x09 ,  
  112.    0xaa , 0x48 , 0x5a , 0x01 , 0xb5 , 0x09 , 0xb0 , 0x39 , 0x64 , 0x05 , 0x25 , 0x75 , 0x95 , 0x0a ,  
  113.    0x96 , 0x04 , 0x4d , 0x54 , 0xad , 0x04 , 0xda , 0x04 , 0xd4 , 0x44 , 0xb4 , 0x05 , 0x54 , 0x85 ,  
  114.    0x52 , 0x0d , 0x92 , 0x0a , 0x56 , 0x6a , 0x56 , 0x02 , 0x6d , 0x02 , 0x6a , 0x41 , 0xda , 0x02 ,  
  115.    0xb2 , 0xa1 , 0xa9 , 0x05 , 0x49 , 0x0d , 0x0a , 0x6d , 0x2a , 0x09 , 0x56 , 0x01 , 0xad , 0x50 ,  
  116.    0x6d , 0x01 , 0xd9 , 0x02 , 0xd1 , 0x3a , 0xa8 , 0x05 , 0x29 , 0x85 , 0xa5 , 0x0c , 0x2a , 0x09 ,  
  117.    0x96 , 0x54 , 0xb6 , 0x08 , 0x6c , 0x09 , 0x64 , 0x45 , 0xd4 , 0x0a , 0xa4 , 0x05 , 0x51 , 0x25 ,  
  118.    0x95 , 0x0a , 0x2a , 0x72 , 0x5b , 0x04 , 0xb6 , 0x04 , 0xac , 0x52 , 0x6a , 0x05 , 0xd2 , 0x0a ,  
  119.    0xa2 , 0x4a , 0x4a , 0x05 , 0x55 , 0x94 , 0x2d , 0x0a , 0x5a , 0x02 , 0x75 , 0x61 , 0xb5 , 0x02 ,  
  120.    0x6a , 0x03 , 0x61 , 0x45 , 0xa9 , 0x0a , 0x4a , 0x05 , 0x25 , 0x25 , 0x2d , 0x09 , 0x9a , 0x68 ,  
  121.    0xda , 0x08 , 0xb4 , 0x09 , 0xa8 , 0x59 , 0x54 , 0x03 , 0xa5 , 0x0a , 0x91 , 0x3a , 0x96 , 0x04 ,  
  122.    0xad , 0xb0 , 0xad , 0x04 , 0xda , 0x04 , 0xf4 , 0x62 , 0xb4 , 0x05 , 0x54 , 0x0b , 0x44 , 0x5d ,  
  123.    0x52 , 0x0a , 0x95 , 0x04 , 0x55 , 0x22 , 0x6d , 0x02 , 0x5a , 0x71 , 0xda , 0x02 , 0xaa , 0x05 ,  
  124.    0xb2 , 0x55 , 0x49 , 0x0b , 0x4a , 0x0a , 0x2d , 0x39 , 0x36 , 0x01 , 0x6d , 0x80 , 0x6d , 0x01 ,  
  125.    0xd9 , 0x02 , 0xe9 , 0x6a , 0xa8 , 0x05 , 0x29 , 0x0b , 0x9a , 0x4c , 0xaa , 0x08 , 0xb6 , 0x08 ,  
  126.    0xb4 , 0x38 , 0x6c , 0x09 , 0x54 , 0x75 , 0xd4 , 0x0a , 0xa4 , 0x05 , 0x45 , 0x55 , 0x95 , 0x0a ,  
  127.    0x9a , 0x04 , 0x55 , 0x44 , 0xb5 , 0x04 , 0x6a , 0x82 , 0x6a , 0x05 , 0xd2 , 0x0a , 0x92 , 0x6a ,  
  128.    0x4a , 0x05 , 0x55 , 0x0a , 0x2a , 0x4a , 0x5a , 0x02 , 0xb5 , 0x02 , 0xb2 , 0x31 , 0x69 , 0x03 ,  
  129.    0x31 , 0x73 , 0xa9 , 0x0a , 0x4a , 0x05 , 0x2d , 0x55 , 0x2d , 0x09 , 0x5a , 0x01 , 0xd5 , 0x48 ,  
  130.    0xb4 , 0x09 , 0x68 , 0x89 , 0x54 , 0x0b , 0xa4 , 0x0a , 0xa5 , 0x6a , 0x95 , 0x04 , 0xad , 0x08 ,  
  131.    0x6a , 0x44 , 0xda , 0x04 , 0x74 , 0x05 , 0xb0 , 0x25 , 0x54 , 0x03   
  132.    };  
  133.    // 初始日,公历农历对应日期:   
  134.    // 公历 1901 年 1 月 1 日,对应农历 4598 年 11 月 11 日   
  135.    private   static   int  baseYear =  1901 ;  
  136.    private   static   int  baseMonth =  1 ;  
  137.    private   static   int  baseDate =  1 ;  
  138.    private   static   int  baseIndex =  0 ;  
  139.    private   static   int  baseChineseYear =  4598 - 1 ;  
  140.    private   static   int  baseChineseMonth =  11 ;  
  141.    private   static   int  baseChineseDate =  11 ;  
  142.    public   int  computeChineseFields() {  
  143.       if  (gregorianYear< 1901  || gregorianYear> 2100 return   1 ;  
  144.       int  startYear = baseYear;  
  145.       int  startMonth = baseMonth;  
  146.       int  startDate = baseDate;       
  147.       chineseYear = baseChineseYear;  
  148.       chineseMonth = baseChineseMonth;  
  149.       chineseDate = baseChineseDate;  
  150.       // 第二个对应日,用以提高计算效率   
  151.       // 公历 2000 年 1 月 1 日,对应农历 4697 年 11 月 25 日   
  152.       if  (gregorianYear >=  2000 ) {  
  153.          startYear = baseYear + 99 ;  
  154.          startMonth = 1 ;  
  155.          startDate = 1 ;  
  156.          chineseYear = baseChineseYear + 99 ;  
  157.          chineseMonth = 11 ;  
  158.          chineseDate = 25 ;  
  159.       }  
  160.       int  daysDiff =  0 ;  
  161.       for  ( int  i=startYear; i<gregorianYear; i++) {  
  162.          daysDiff += 365 ;  
  163.          if  (isGregorianLeapYear(i)) daysDiff +=  1 // leap year   
  164.       }  
  165.       for  ( int  i=startMonth; i<gregorianMonth; i++) {  
  166.          daysDiff += daysInGregorianMonth(gregorianYear,i);  
  167.       }  
  168.       daysDiff += gregorianDate - startDate;  
  169.        
  170.       chineseDate += daysDiff;  
  171.       int  lastDate = daysInChineseMonth(chineseYear, chineseMonth);  
  172.       int  nextMonth = nextChineseMonth(chineseYear, chineseMonth);  
  173.       while  (chineseDate>lastDate) {  
  174.          if  (Math.abs(nextMonth)<Math.abs(chineseMonth)) chineseYear++;  
  175.          chineseMonth = nextMonth;  
  176.          chineseDate -= lastDate;  
  177.          lastDate = daysInChineseMonth(chineseYear, chineseMonth);  
  178.          nextMonth = nextChineseMonth(chineseYear, chineseMonth);  
  179.       }  
  180.       return   0 ;  
  181.    }  
  182.    private   static   int [] bigLeapMonthYears = {  
  183.       // 大闰月的闰年年份   
  184.         6 14 19 25 33 36 38 41 44 52 ,  
  185.        55 79 , 117 , 136 , 147 , 150 , 155 , 158 , 185 , 193   
  186.       };  
  187.    public   static   int  daysInChineseMonth( int  y,  int  m) {  
  188.       // 注意:闰月 m < 0   
  189.       int  index = y - baseChineseYear + baseIndex;  
  190.       int  v =  0 ;  
  191.       int  l =  0 ;  
  192.       int  d =  30 ;  
  193.       if  ( 1 <=m && m<= 8 ) {  
  194.          v = chineseMonths[2 *index];  
  195.          l = m - 1 ;  
  196.          if  ( ((v>>l)& 0x01 )== 1  ) d =  29 ;  
  197.       } else   if  ( 9 <=m && m<= 12 ) {  
  198.          v = chineseMonths[2 *index+ 1 ];  
  199.          l = m - 9 ;  
  200.          if  ( ((v>>l)& 0x01 )== 1  ) d =  29 ;  
  201.       } else  {  
  202.          v = chineseMonths[2 *index+ 1 ];  
  203.          v = (v>>4 )& 0x0F ;  
  204.          if  (v!=Math.abs(m)) {  
  205.             d = 0 ;  
  206.          } else  {  
  207.             d = 29 ;  
  208.             for  ( int  i= 0 ; i<bigLeapMonthYears.length; i++) {  
  209.                if  (bigLeapMonthYears[i]==index) {  
  210.                   d = 30 ;  
  211.                   break ;  
  212.                }  
  213.             }  
  214.          }  
  215.       }  
  216.       return  d;  
  217.    }  
  218.    public   static   int  nextChineseMonth( int  y,  int  m) {  
  219.       int  n = Math.abs(m) +  1 ;  
  220.       if  (m> 0 ) {  
  221.          int  index = y - baseChineseYear + baseIndex;  
  222.          int  v = chineseMonths[ 2 *index+ 1 ];  
  223.          v = (v>>4 )& 0x0F ;  
  224.          if  (v==m) n = -m;  
  225.       }  
  226.       if  (n== 13 ) n =  1 ;  
  227.       return  n;  
  228.    }  
  229.    private   static   char [][] sectionalTermMap = {  
  230.    {7 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 5 , 6 , 6 , 6 , 5 , 5 , 6 , 6 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 4 , 5 , 5 },   
  231.    {5 , 4 , 5 , 5 , 5 , 4 , 4 , 5 , 5 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 4 , 4 , 4 , 3 , 3 , 4 , 4 , 3 , 3 , 3 },   
  232.    {6 , 6 , 6 , 7 , 6 , 6 , 6 , 6 , 5 , 6 , 6 , 6 , 5 , 5 , 6 , 6 , 5 , 5 , 5 , 6 , 5 , 5 , 5 , 5 , 4 , 5 , 5 , 5 , 5 },  
  233.    {5 , 5 , 6 , 6 , 5 , 5 , 5 , 6 , 5 , 5 , 5 , 5 , 4 , 5 , 5 , 5 , 4 , 4 , 5 , 5 , 4 , 4 , 4 , 5 , 4 , 4 , 4 , 4 , 5 },  
  234.    {6 , 6 , 6 , 7 , 6 , 6 , 6 , 6 , 5 , 6 , 6 , 6 , 5 , 5 , 6 , 6 , 5 , 5 , 5 , 6 , 5 , 5 , 5 , 5 , 4 , 5 , 5 , 5 , 5 },  
  235.    {6 , 6 , 7 , 7 , 6 , 6 , 6 , 7 , 6 , 6 , 6 , 6 , 5 , 6 , 6 , 6 , 5 , 5 , 6 , 6 , 5 , 5 , 5 , 6 , 5 , 5 , 5 , 5 , 4 , 5 , 5 , 5 , 5 },  
  236.    {7 , 8 , 8 , 8 , 7 , 7 , 8 , 8 , 7 , 7 , 7 , 8 , 7 , 7 , 7 , 7 , 6 , 7 , 7 , 7 , 6 , 6 , 7 , 7 , 6 , 6 , 6 , 7 , 7 },  
  237.    {8 , 8 , 8 , 9 , 8 , 8 , 8 , 8 , 7 , 8 , 8 , 8 , 7 , 7 , 8 , 8 , 7 , 7 , 7 , 8 , 7 , 7 , 7 , 7 , 6 , 7 , 7 , 7 , 6 , 6 , 7 , 7 , 7 },  
  238.    {8 , 8 , 8 , 9 , 8 , 8 , 8 , 8 , 7 , 8

文章评论