本章主要是收藏一些常用的类和接口,包括:万年历(农历、阳历节日、阴历节日)、自定义的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 }
自定义的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\n", getYear(cal) ); 19 // 获取“月” 20 System.out.printf("month: %s\n", getMonth(cal) ); 21 // 获取“上月” 22 System.out.printf("previcou month: %s\n", getLastMonth(cal) ); 23 // 获取“下月” 24 System.out.printf("next month: %s\n", getNextMonth(cal) ); 25 // 获取“日” 26 System.out.printf("day: %s\n", getDay(cal) ); 27 // 获取Cal对应星期几 28 System.out.printf("weekday: %s\n", getWeekDay(cal) ); 29 // 本月天数 30 System.out.printf("Current Month days: %s\n", getMonthDays(cal) ); 31 // 上月天数 32 System.out.printf("Previcous Month days: %s\n", getPrevMonthDays(cal) ); 33 // 下月天数 34 System.out.printf("Next Month days: %s\n", getNextMonthDays(cal) ); 35 // 获取当月第一天的星期几 36 System.out.printf("First day' weekday : %s\n", getFirstDayWeekday(cal) ); 37 // 获取当前月最后一天的星期几 38 System.out.printf("Last day' weekday : %s\n", getLastDayWeekday(cal) ); 39 // 获取上月最后一天的星期几 40 System.out.printf("PrevMonth Last day' weekday: %s\n", getLastDayWeekdayOfPrevMonth(cal) ); 41 // 获取下月第一天的星期几 42 System.out.printf("NextMonth First day' weekday: %s\n", 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