首页 > 代码库 > java根据日期计算24节气

java根据日期计算24节气

  1 package com.test;
  2 
  3 import java.util.Calendar;
  4 import java.util.Date;
  5 
  6 /**
  7  * Created by json
  8  */
  9 public class SolarTermsUtil {
 10     /**
 11      * 计算得到公历的年份
 12      */
 13     private int gregorianYear;
 14 
 15     /**
 16      * 计算得到公历的月份
 17      */
 18     private int gregorianMonth;
 19 
 20     /**
 21      * 用于计算得到公历的日期
 22      */
 23     private int gregorianDate;
 24 
 25     private int chineseYear;
 26     private int chineseMonth;
 27     private int chineseDate;
 28 
 29     // 初始日,公历农历对应日期:
 30     // 公历 1901 年 1 月 1 日,对应农历 4598 年 11 月 11 日
 31     private static int baseYear = 1901;
 32     private static int baseMonth = 1;
 33     private static int baseDate = 1;
 34     private static int baseIndex = 0;
 35     private static int baseChineseYear = 4598 - 1;
 36     private static int baseChineseMonth = 11;
 37     private static int baseChineseDate = 11;
 38     private static char[] daysInGregorianMonth = {31, 28, 31, 30, 31, 30, 31,
 39             31, 30, 31, 30, 31};
 40 
 41     private int sectionalTerm;
 42     private int principleTerm;
 43 
 44     private static char[][] sectionalTermMap = {
 45             {7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 5, 5,
 46                     5, 5, 5, 4, 5, 5},
 47             {5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 3,
 48                     3, 4, 4, 3, 3, 3},
 49             {6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
 50                     5, 5, 4, 5, 5, 5, 5},
 51             {5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4,
 52                     4, 5, 4, 4, 4, 4, 5},
 53             {6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
 54                     5, 5, 4, 5, 5, 5, 5},
 55             {6, 6, 7, 7, 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5,
 56                     5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5},
 57             {7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
 58                     7, 7, 6, 6, 6, 7, 7},
 59             {8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
 60                     7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7},
 61             {8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
 62                     7, 7, 6, 7, 7, 7, 7},
 63             {9, 9, 9, 9, 8, 9, 9, 9, 8, 8, 9, 9, 8, 8, 8, 9, 8, 8, 8, 8, 7, 8,
 64                     8, 8, 7, 7, 8, 8, 8},
 65             {8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7,
 66                     7, 7, 6, 6, 7, 7, 7},
 67             {7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
 68                     7, 7, 6, 6, 6, 7, 7}};
 69     private static char[][] sectionalTermYear = {
 70             {13, 49, 85, 117, 149, 185, 201, 250, 250},
 71             {13, 45, 81, 117, 149, 185, 201, 250, 250},
 72             {13, 48, 84, 112, 148, 184, 200, 201, 250},
 73             {13, 45, 76, 108, 140, 172, 200, 201, 250},
 74             {13, 44, 72, 104, 132, 168, 200, 201, 250},
 75             {5, 33, 68, 96, 124, 152, 188, 200, 201},
 76             {29, 57, 85, 120, 148, 176, 200, 201, 250},
 77             {13, 48, 76, 104, 132, 168, 196, 200, 201},
 78             {25, 60, 88, 120, 148, 184, 200, 201, 250},
 79             {16, 44, 76, 108, 144, 172, 200, 201, 250},
 80             {28, 60, 92, 124, 160, 192, 200, 201, 250},
 81             {17, 53, 85, 124, 156, 188, 200, 201, 250}};
 82     private static char[][] principleTermMap = {
 83             {21, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20,
 84                     20, 20, 20, 20, 20, 19, 20, 20, 20, 19, 19, 20},
 85             {20, 19, 19, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, 19, 19,
 86                     19, 18, 18, 19, 19, 18, 18, 18, 18, 18, 18, 18},
 87             {21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21,
 88                     20, 20, 20, 21, 20, 20, 20, 20, 19, 20, 20, 20, 20},
 89             {20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 20, 20, 20, 20,
 90                     19, 20, 20, 20, 19, 19, 20, 20, 19, 19, 19, 20, 20},
 91             {21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21,
 92                     20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 21},
 93             {22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22,
 94                     21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 21},
 95             {23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23,
 96                     22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 23},
 97             {23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
 98                     22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23},
 99             {23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
100                     22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23},
101             {24, 24, 24, 24, 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24,
102                     23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 23},
103             {23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23,
104                     22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 22},
105             {22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 21, 22, 22, 22,
106                     21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 22}};
107     private static char[][] principleTermYear = {
108             {13, 45, 81, 113, 149, 185, 201},
109             {21, 57, 93, 125, 161, 193, 201},
110             {21, 56, 88, 120, 152, 188, 200, 201},
111             {21, 49, 81, 116, 144, 176, 200, 201},
112             {17, 49, 77, 112, 140, 168, 200, 201},
113             {28, 60, 88, 116, 148, 180, 200, 201},
114             {25, 53, 84, 112, 144, 172, 200, 201},
115             {29, 57, 89, 120, 148, 180, 200, 201},
116             {17, 45, 73, 108, 140, 168, 200, 201},
117             {28, 60, 92, 124, 160, 192, 200, 201},
118             {16, 44, 80, 112, 148, 180, 200, 201},
119             {17, 53, 88, 120, 156, 188, 200, 201}};
120 
121     private static char[] chineseMonths = {
122             // 农历月份大小压缩表,两个字节表示一年。两个字节共十六个二进制位数,
123             // 前四个位数表示闰月月份,后十二个位数表示十二个农历月份的大小。
124             0x00, 0x04, 0xad, 0x08, 0x5a, 0x01, 0xd5, 0x54, 0xb4, 0x09, 0x64,
125             0x05, 0x59, 0x45, 0x95, 0x0a, 0xa6, 0x04, 0x55, 0x24, 0xad, 0x08,
126             0x5a, 0x62, 0xda, 0x04, 0xb4, 0x05, 0xb4, 0x55, 0x52, 0x0d, 0x94,
127             0x0a, 0x4a, 0x2a, 0x56, 0x02, 0x6d, 0x71, 0x6d, 0x01, 0xda, 0x02,
128             0xd2, 0x52, 0xa9, 0x05, 0x49, 0x0d, 0x2a, 0x45, 0x2b, 0x09, 0x56,
129             0x01, 0xb5, 0x20, 0x6d, 0x01, 0x59, 0x69, 0xd4, 0x0a, 0xa8, 0x05,
130             0xa9, 0x56, 0xa5, 0x04, 0x2b, 0x09, 0x9e, 0x38, 0xb6, 0x08, 0xec,
131             0x74, 0x6c, 0x05, 0xd4, 0x0a, 0xe4, 0x6a, 0x52, 0x05, 0x95, 0x0a,
132             0x5a, 0x42, 0x5b, 0x04, 0xb6, 0x04, 0xb4, 0x22, 0x6a, 0x05, 0x52,
133             0x75, 0xc9, 0x0a, 0x52, 0x05, 0x35, 0x55, 0x4d, 0x0a, 0x5a, 0x02,
134             0x5d, 0x31, 0xb5, 0x02, 0x6a, 0x8a, 0x68, 0x05, 0xa9, 0x0a, 0x8a,
135             0x6a, 0x2a, 0x05, 0x2d, 0x09, 0xaa, 0x48, 0x5a, 0x01, 0xb5, 0x09,
136             0xb0, 0x39, 0x64, 0x05, 0x25, 0x75, 0x95, 0x0a, 0x96, 0x04, 0x4d,
137             0x54, 0xad, 0x04, 0xda, 0x04, 0xd4, 0x44, 0xb4, 0x05, 0x54, 0x85,
138             0x52, 0x0d, 0x92, 0x0a, 0x56, 0x6a, 0x56, 0x02, 0x6d, 0x02, 0x6a,
139             0x41, 0xda, 0x02, 0xb2, 0xa1, 0xa9, 0x05, 0x49, 0x0d, 0x0a, 0x6d,
140             0x2a, 0x09, 0x56, 0x01, 0xad, 0x50, 0x6d, 0x01, 0xd9, 0x02, 0xd1,
141             0x3a, 0xa8, 0x05, 0x29, 0x85, 0xa5, 0x0c, 0x2a, 0x09, 0x96, 0x54,
142             0xb6, 0x08, 0x6c, 0x09, 0x64, 0x45, 0xd4, 0x0a, 0xa4, 0x05, 0x51,
143             0x25, 0x95, 0x0a, 0x2a, 0x72, 0x5b, 0x04, 0xb6, 0x04, 0xac, 0x52,
144             0x6a, 0x05, 0xd2, 0x0a, 0xa2, 0x4a, 0x4a, 0x05, 0x55, 0x94, 0x2d,
145             0x0a, 0x5a, 0x02, 0x75, 0x61, 0xb5, 0x02, 0x6a, 0x03, 0x61, 0x45,
146             0xa9, 0x0a, 0x4a, 0x05, 0x25, 0x25, 0x2d, 0x09, 0x9a, 0x68, 0xda,
147             0x08, 0xb4, 0x09, 0xa8, 0x59, 0x54, 0x03, 0xa5, 0x0a, 0x91, 0x3a,
148             0x96, 0x04, 0xad, 0xb0, 0xad, 0x04, 0xda, 0x04, 0xf4, 0x62, 0xb4,
149             0x05, 0x54, 0x0b, 0x44, 0x5d, 0x52, 0x0a, 0x95, 0x04, 0x55, 0x22,
150             0x6d, 0x02, 0x5a, 0x71, 0xda, 0x02, 0xaa, 0x05, 0xb2, 0x55, 0x49,
151             0x0b, 0x4a, 0x0a, 0x2d, 0x39, 0x36, 0x01, 0x6d, 0x80, 0x6d, 0x01,
152             0xd9, 0x02, 0xe9, 0x6a, 0xa8, 0x05, 0x29, 0x0b, 0x9a, 0x4c, 0xaa,
153             0x08, 0xb6, 0x08, 0xb4, 0x38, 0x6c, 0x09, 0x54, 0x75, 0xd4, 0x0a,
154             0xa4, 0x05, 0x45, 0x55, 0x95, 0x0a, 0x9a, 0x04, 0x55, 0x44, 0xb5,
155             0x04, 0x6a, 0x82, 0x6a, 0x05, 0xd2, 0x0a, 0x92, 0x6a, 0x4a, 0x05,
156             0x55, 0x0a, 0x2a, 0x4a, 0x5a, 0x02, 0xb5, 0x02, 0xb2, 0x31, 0x69,
157             0x03, 0x31, 0x73, 0xa9, 0x0a, 0x4a, 0x05, 0x2d, 0x55, 0x2d, 0x09,
158             0x5a, 0x01, 0xd5, 0x48, 0xb4, 0x09, 0x68, 0x89, 0x54, 0x0b, 0xa4,
159             0x0a, 0xa5, 0x6a, 0x95, 0x04, 0xad, 0x08, 0x6a, 0x44, 0xda, 0x04,
160             0x74, 0x05, 0xb0, 0x25, 0x54, 0x03};
161 
162     /**
163      * 用于保存24节气
164      */
165     private static String[] principleTermNames = {"大寒", "雨水", "春分", "谷雨",
166             "小满", "夏至", "大暑", "处暑", "秋分", "霜降", "小雪", "冬至"};
167     /**
168      * 用于保存24节气
169      */
170     private static String[] sectionalTermNames = {"小寒", "立春", "惊蛰", "清明",
171             "立夏", "芒种", "小暑", "立秋", "白露", "寒露", "立冬", "大雪"};
172 
173     public SolarTermsUtil(Calendar calendar) {
174         gregorianYear = calendar.get(Calendar.YEAR);
175         gregorianMonth = calendar.get(Calendar.MONTH) + 1;
176         gregorianDate = calendar.get(Calendar.DATE);
177         computeChineseFields();
178         computeSolarTerms();
179     }
180 
181     public int computeChineseFields() {
182         if (gregorianYear < 1901 || gregorianYear > 2100)
183             return 1;
184         int startYear = baseYear;
185         int startMonth = baseMonth;
186         int startDate = baseDate;
187         chineseYear = baseChineseYear;
188         chineseMonth = baseChineseMonth;
189         chineseDate = baseChineseDate;
190         // 第二个对应日,用以提高计算效率
191         // 公历 2000 年 1 月 1 日,对应农历 4697 年 11 月 25 日
192         if (gregorianYear >= 2000) {
193             startYear = baseYear + 99;
194             startMonth = 1;
195             startDate = 1;
196             chineseYear = baseChineseYear + 99;
197             chineseMonth = 11;
198             chineseDate = 25;
199         }
200         int daysDiff = 0;
201         for (int i = startYear; i < gregorianYear; i++) {
202             daysDiff += 365;
203             if (isGregorianLeapYear(i))
204                 daysDiff += 1; // leap year
205         }
206         for (int i = startMonth; i < gregorianMonth; i++) {
207             daysDiff += daysInGregorianMonth(gregorianYear, i);
208         }
209         daysDiff += gregorianDate - startDate;
210 
211         chineseDate += daysDiff;
212         int lastDate = daysInChineseMonth(chineseYear, chineseMonth);
213         int nextMonth = nextChineseMonth(chineseYear, chineseMonth);
214         while (chineseDate > lastDate) {
215             if (Math.abs(nextMonth) < Math.abs(chineseMonth))
216                 chineseYear++;
217             chineseMonth = nextMonth;
218             chineseDate -= lastDate;
219             lastDate = daysInChineseMonth(chineseYear, chineseMonth);
220             nextMonth = nextChineseMonth(chineseYear, chineseMonth);
221         }
222         return 0;
223     }
224 
225     public int computeSolarTerms() {
226         if (gregorianYear < 1901 || gregorianYear > 2100)
227             return 1;
228         sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth);
229         principleTerm = principleTerm(gregorianYear, gregorianMonth);
230         return 0;
231     }
232 
233     public static int sectionalTerm(int y, int m) {
234         if (y < 1901 || y > 2100)
235             return 0;
236         int index = 0;
237         int ry = y - baseYear + 1;
238         while (ry >= sectionalTermYear[m - 1][index])
239             index++;
240         int term = sectionalTermMap[m - 1][4 * index + ry % 4];
241         if ((ry == 121) && (m == 4))
242             term = 5;
243         if ((ry == 132) && (m == 4))
244             term = 5;
245         if ((ry == 194) && (m == 6))
246             term = 6;
247         return term;
248     }
249 
250     public static int principleTerm(int y, int m) {
251         if (y < 1901 || y > 2100)
252             return 0;
253         int index = 0;
254         int ry = y - baseYear + 1;
255         while (ry >= principleTermYear[m - 1][index])
256             index++;
257         int term = principleTermMap[m - 1][4 * index + ry % 4];
258         if ((ry == 171) && (m == 3))
259             term = 21;
260         if ((ry == 181) && (m == 5))
261             term = 21;
262         return term;
263     }
264 
265     /**
266      * 用于判断输入的年份是否为闰年
267      *
268      * @param year 输入的年份
269      * @return true 表示闰年
270      */
271     public static boolean isGregorianLeapYear(int year) {
272         boolean isLeap = false;
273         if (year % 4 == 0)
274             isLeap = true;
275         if (year % 100 == 0)
276             isLeap = false;
277         if (year % 400 == 0)
278             isLeap = true;
279         return isLeap;
280     }
281 
282     public static int daysInGregorianMonth(int y, int m) {
283         int d = daysInGregorianMonth[m - 1];
284         if (m == 2 && isGregorianLeapYear(y))
285             d++; // 公历闰年二月多一天
286         return d;
287     }
288 
289     public static int daysInChineseMonth(int y, int m) {
290         // 注意:闰月 m < 0
291         int index = y - baseChineseYear + baseIndex;
292         int v = 0;
293         int l = 0;
294         int d = 30;
295         if (1 <= m && m <= 8) {
296             v = chineseMonths[2 * index];
297             l = m - 1;
298             if (((v >> l) & 0x01) == 1)
299                 d = 29;
300         } else if (9 <= m && m <= 12) {
301             v = chineseMonths[2 * index + 1];
302             l = m - 9;
303             if (((v >> l) & 0x01) == 1)
304                 d = 29;
305         } else {
306             v = chineseMonths[2 * index + 1];
307             v = (v >> 4) & 0x0F;
308             if (v != Math.abs(m)) {
309                 d = 0;
310             } else {
311                 d = 29;
312                 for (int i = 0; i < bigLeapMonthYears.length; i++) {
313                     if (bigLeapMonthYears[i] == index) {
314                         d = 30;
315                         break;
316                     }
317                 }
318             }
319         }
320         return d;
321     }
322 
323     public static int nextChineseMonth(int y, int m) {
324         int n = Math.abs(m) + 1;
325         if (m > 0) {
326             int index = y - baseChineseYear + baseIndex;
327             int v = chineseMonths[2 * index + 1];
328             v = (v >> 4) & 0x0F;
329             if (v == m)
330                 n = -m;
331         }
332         if (n == 13)
333             n = 1;
334         return n;
335     }
336 
337     // 大闰月的闰年年份
338     private static int[] bigLeapMonthYears = {6, 14, 19, 25, 33, 36, 38, 41,
339             44, 52, 55, 79, 117, 136, 147, 150, 155, 158, 185, 193};
340 
341     /**
342      * 用于获取24节气的值
343      *
344      * @return 24节气的值
345      */
346     public String getSolartermsName() {
347         String str = "";
348         String gm = String.valueOf(gregorianMonth);
349         if (gm.length() == 1)
350             gm = ‘ ‘ + gm;
351         String cm = String.valueOf(Math.abs(chineseMonth));
352         if (cm.length() == 1)
353             cm = ‘ ‘ + cm;
354         String gd = String.valueOf(gregorianDate);
355         if (gd.length() == 1)
356             gd = ‘ ‘ + gd;
357         String cd = String.valueOf(chineseDate);
358         if (cd.length() == 1)
359             cd = ‘ ‘ + cd;
360         if (gregorianDate == sectionalTerm) {
361             str = sectionalTermNames[gregorianMonth - 1];
362         } else if (gregorianDate == principleTerm) {
363             str = principleTermNames[gregorianMonth - 1];
364         }
365         return str;
366     }
367     
368     public static void main(String[] args) {
369         Calendar today = Calendar.getInstance();
370         today.setTime(new Date());
371         SolarTermsUtil solarTermsUtil = new SolarTermsUtil(today);
372         String solarTerms = solarTermsUtil.getSolartermsName();
373         System.out.println(solarTerms);
374     }
375 }

 

java根据日期计算24节气