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 }
时间: 2024-10-04 18:28:32