1 package org.quartz; 2 3 import java.io.Serializable ; 4 import java.text.ParseException ; 5 import java.util.Calendar ; 6 import java.util.Date ; 7 import java.util.HashMap ; 8 import java.util.Iterator ; 9 import java.util.Locale ; 10 import java.util.Map ; 11 import java.util.SortedSet ; 12 import java.util.StringTokenizer ; 13 import java.util.TimeZone ; 14 import java.util.TreeSet ; 15 16 172 public class CronExpression implements Serializable , Cloneable { 173 174 private static final long serialVersionUID = 12423409423L; 175 176 protected static final int SECOND = 0; 177 protected static final int MINUTE = 1; 178 protected static final int HOUR = 2; 179 protected static final int DAY_OF_MONTH = 3; 180 protected static final int MONTH = 4; 181 protected static final int DAY_OF_WEEK = 5; 182 protected static final int YEAR = 6; 183 protected static final int ALL_SPEC_INT = 99; protected static final int NO_SPEC_INT = 98; protected static final Integer ALL_SPEC = new Integer (ALL_SPEC_INT); 186 protected static final Integer NO_SPEC = new Integer (NO_SPEC_INT); 187 188 protected static Map monthMap = new HashMap (20); 189 protected static Map dayMap = new HashMap (60); 190 static { 191 monthMap.put("JAN", new Integer (0)); 192 monthMap.put("FEB", new Integer (1)); 193 monthMap.put("MAR", new Integer (2)); 194 monthMap.put("APR", new Integer (3)); 195 monthMap.put("MAY", new Integer (4)); 196 monthMap.put("JUN", new Integer (5)); 197 monthMap.put("JUL", new Integer (6)); 198 monthMap.put("AUG", new Integer (7)); 199 monthMap.put("SEP", new Integer (8)); 200 monthMap.put("OCT", new Integer (9)); 201 monthMap.put("NOV", new Integer (10)); 202 monthMap.put("DEC", new Integer (11)); 203 204 dayMap.put("SUN", new Integer (1)); 205 dayMap.put("MON", new Integer (2)); 206 dayMap.put("TUE", new Integer (3)); 207 dayMap.put("WED", new Integer (4)); 208 dayMap.put("THU", new Integer (5)); 209 dayMap.put("FRI", new Integer (6)); 210 dayMap.put("SAT", new Integer (7)); 211 } 212 213 private String cronExpression = null; 214 private TimeZone timeZone = null; 215 protected transient TreeSet seconds; 216 protected transient TreeSet minutes; 217 protected transient TreeSet hours; 218 protected transient TreeSet daysOfMonth; 219 protected transient TreeSet months; 220 protected transient TreeSet daysOfWeek; 221 protected transient TreeSet years; 222 223 protected transient boolean lastdayOfWeek = false; 224 protected transient int nthdayOfWeek = 0; 225 protected transient boolean lastdayOfMonth = false; 226 protected transient boolean nearestWeekday = false; 227 protected transient boolean expressionParsed = false; 228 229 239 public CronExpression(String cronExpression) throws ParseException { 240 if (cronExpression == null) { 241 throw new IllegalArgumentException ("cronExpression cannot be null"); 242 } 243 244 this.cronExpression = cronExpression; 245 246 buildExpression(cronExpression.toUpperCase(Locale.US)); 247 } 248 249 258 public boolean isSatisfiedBy(Date date) { 259 Calendar testDateCal = Calendar.getInstance(); 260 testDateCal.setTime(date); 261 testDateCal.set(Calendar.MILLISECOND, 0); 262 Date originalDate = testDateCal.getTime(); 263 264 testDateCal.add(Calendar.SECOND, -1); 265 266 Date timeAfter = getTimeAfter(testDateCal.getTime()); 267 268 return ((timeAfter != null) && (timeAfter.equals(originalDate))); 269 } 270 271 279 public Date getNextValidTimeAfter(Date date) { 280 return getTimeAfter(date); 281 } 282 283 291 public Date getNextInvalidTimeAfter(Date date) { 292 long difference = 1000; 293 294 Calendar adjustCal = Calendar.getInstance(); 296 adjustCal.setTime(date); 297 adjustCal.set(Calendar.MILLISECOND, 0); 298 Date lastDate = adjustCal.getTime(); 299 300 Date newDate = null; 301 302 304 while (difference == 1000) { 308 newDate = getTimeAfter(lastDate); 309 310 difference = newDate.getTime() - lastDate.getTime(); 311 312 if (difference == 1000) { 313 lastDate = newDate; 314 } 315 } 316 317 return new Date (lastDate.getTime() + 1000); 318 } 319 320 324 public TimeZone getTimeZone() { 325 if (timeZone == null) { 326 timeZone = TimeZone.getDefault(); 327 } 328 329 return timeZone; 330 } 331 332 336 public void setTimeZone(TimeZone timeZone) { 337 this.timeZone = timeZone; 338 } 339 340 345 public String toString() { 346 return cronExpression; 347 } 348 349 357 public static boolean isValidExpression(String cronExpression) { 358 359 try { 360 new CronExpression(cronExpression); 361 } catch (ParseException pe) { 362 return false; 363 } 364 365 return true; 366 } 367 368 374 protected void buildExpression(String expression) throws ParseException { 375 expressionParsed = true; 376 377 try { 378 379 if (seconds == null) { 380 seconds = new TreeSet (); 381 } 382 if (minutes == null) { 383 minutes = new TreeSet (); 384 } 385 if (hours == null) { 386 hours = new TreeSet (); 387 } 388 if (daysOfMonth == null) { 389 daysOfMonth = new TreeSet (); 390 } 391 if (months == null) { 392 months = new TreeSet (); 393 } 394 if (daysOfWeek == null) { 395 daysOfWeek = new TreeSet (); 396 } 397 if (years == null) { 398 years = new TreeSet (); 399 } 400 401 int exprOn = SECOND; 402 403 StringTokenizer exprsTok = new StringTokenizer (expression, " \t", 404 false); 405 406 while (exprsTok.hasMoreTokens() && exprOn <= YEAR) { 407 String expr = exprsTok.nextToken().trim(); 408 StringTokenizer vTok = new StringTokenizer (expr, ","); 409 while (vTok.hasMoreTokens()) { 410 String v = vTok.nextToken(); 411 storeExpressionVals(0, v, exprOn); 412 } 413 414 exprOn++; 415 } 416 417 if (exprOn <= DAY_OF_WEEK) { 418 throw new ParseException ("Unexpected end of expression.", 419 expression.length()); 420 } 421 422 if (exprOn <= YEAR) { 423 storeExpressionVals(0, "*", YEAR); 424 } 425 426 } catch (ParseException pe) { 427 throw pe; 428 } catch (Exception e) { 429 throw new ParseException ("Illegal cron expression format (" 430 + e.toString() + ")", 0); 431 } 432 } 433 434 protected int storeExpressionVals(int pos, String s, int type) 435 throws ParseException { 436 437 int incr = 0; 438 int i = skipWhiteSpace(pos, s); 439 if (i >= s.length()) { 440 return i; 441 } 442 char c = s.charAt(i); 443 if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW"))) { 444 String sub = s.substring(i, i + 3); 445 int sval = -1; 446 int eval = -1; 447 if (type == MONTH) { 448 sval = getMonthNumber(sub) + 1; 449 if (sval < 0) { 450 throw new ParseException ("Invalid Month value: '" + sub + "'", i); 451 } 452 if (s.length() > i + 3) { 453 c = s.charAt(i + 3); 454 if (c == '-') { 455 i += 4; 456 sub = s.substring(i, i + 3); 457 eval = getMonthNumber(sub) + 1; 458 if (eval < 0) { 459 throw new ParseException ("Invalid Month value: '" + sub + "'", i); 460 } 461 } 462 } 463 } else if (type == DAY_OF_WEEK) { 464 sval = getDayOfWeekNumber(sub); 465 if (sval < 0) { 466 throw new ParseException ("Invalid Day-of-Week value: '" 467 + sub + "'", i); 468 } 469 if (s.length() > i + 3) { 470 c = s.charAt(i + 3); 471 if (c == '-') { 472 i += 4; 473 sub = s.substring(i, i + 3); 474 eval = getDayOfWeekNumber(sub); 475 if (eval < 0) { 476 throw new ParseException ( 477 "Invalid Day-of-Week value: '" + sub 478 + "'", i); 479 } 480 if (sval > eval) { 481 throw new ParseException ( 482 "Invalid Day-of-Week sequence: " + sval 483 + " > " + eval, i); 484 } 485 } else if (c == '#') { 486 try { 487 i += 4; 488 nthdayOfWeek = Integer.parseInt(s.substring(i)); 489 if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { 490 throw new Exception (); 491 } 492 } catch (Exception e) { 493 throw new ParseException ( 494 "A numeric value between 1 and 5 must follow the '#' option", 495 i); 496 } 497 } else if (c == 'L') { 498 lastdayOfWeek = true; 499 i++; 500 } 501 } 502 503 } else { 504 throw new ParseException ( 505 "Illegal characters for this position: '" + sub + "'", 506 i); 507 } 508 if (eval != -1) { 509 incr = 1; 510 } 511 addToSet(sval, eval, incr, type); 512 return (i + 3); 513 } 514 515 if (c == '?') { 516 i++; 517 if ((i + 1) < s.length() 518 && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) { 519 throw new ParseException ("Illegal character after '?': " 520 + s.charAt(i), i); 521 } 522 if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) { 523 throw new ParseException ( 524 "'?' can only be specfied for Day-of-Month or Day-of-Week.", 525 i); 526 } 527 if (type == DAY_OF_WEEK && !lastdayOfMonth) { 528 int val = ((Integer ) daysOfMonth.last()).intValue(); 529 if (val == NO_SPEC_INT) { 530 throw new ParseException ( 531 "'?' can only be specfied for Day-of-Month -OR- Day-of-Week.", 532 i); 533 } 534 } 535 536 addToSet(NO_SPEC_INT, -1, 0, type); 537 return i; 538 } 539 540 if (c == '*' || c == '/') { 541 if (c == '*' && (i + 1) >= s.length()) { 542 addToSet(ALL_SPEC_INT, -1, incr, type); 543 return i + 1; 544 } else if (c == '/' 545 && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s 546 .charAt(i + 1) == '\t')) { 547 throw new ParseException ("'/' must be followed by an integer.", i); 548 } else if (c == '*') { 549 i++; 550 } 551 c = s.charAt(i); 552 if (c == '/') { i++; 554 if (i >= s.length()) { 555 throw new ParseException ("Unexpected end of string.", i); 556 } 557 558 incr = getNumericValue(s, i); 559 560 i++; 561 if (incr > 10) { 562 i++; 563 } 564 if (incr > 59 && (type == SECOND || type == MINUTE)) { 565 throw new ParseException ("Increment > 60 : " + incr, i); 566 } else if (incr > 23 && (type == HOUR)) { 567 throw new ParseException ("Increment > 24 : " + incr, i); 568 } else if (incr > 31 && (type == DAY_OF_MONTH)) { 569 throw new ParseException ("Increment > 31 : " + incr, i); 570 } else if (incr > 7 && (type == DAY_OF_WEEK)) { 571 throw new ParseException ("Increment > 7 : " + incr, i); 572 } else if (incr > 12 && (type == MONTH)) { 573 throw new ParseException ("Increment > 12 : " + incr, i); 574 } 575 } else { 576 incr = 1; 577 } 578 579 addToSet(ALL_SPEC_INT, -1, incr, type); 580 return i; 581 } else if (c == 'L') { 582 i++; 583 if (type == DAY_OF_MONTH) { 584 lastdayOfMonth = true; 585 } 586 if (type == DAY_OF_WEEK) { 587 addToSet(7, 7, 0, type); 588 } 589 if(type == DAY_OF_MONTH && s.length() > i) { 590 c = s.charAt(i); 591 if(c == 'W') { 592 nearestWeekday = true; 593 i++; 594 } 595 } 596 return i; 597 } else if (c >= '0' && c <= '9') { 598 int val = Integer.parseInt(String.valueOf(c)); 599 i++; 600 if (i >= s.length()) { 601 addToSet(val, -1, -1, type); 602 } else { 603 c = s.charAt(i); 604 if (c >= '0' && c <= '9') { 605 ValueSet vs = getValue(val, s, i); 606 val = vs.value; 607 i = vs.pos; 608 } 609 i = checkNext(i, s, val, type); 610 return i; 611 } 612 } else { 613 throw new ParseException ("Unexpected character: " + c, i); 614 } 615 616 return i; 617 } 618 619 protected int checkNext(int pos, String s, int val, int type) 620 throws ParseException { 621 622 int end = -1; 623 int i = pos; 624 625 if (i >= s.length()) { 626 addToSet(val, end, -1, type); 627 return i; 628 } 629 630 char c = s.charAt(pos); 631 632 if (c == 'L') { 633 if (type == DAY_OF_WEEK) { 634 lastdayOfWeek = true; 635 } else { 636 throw new ParseException ("'L' option is not valid here. (pos=" + i + ")", i); 637 } 638 TreeSet set = getSet(type); 639 set.add(new Integer (val)); 640 i++; 641 return i; 642 } 643 644 if (c == 'W') { 645 if (type == DAY_OF_MONTH) { 646 nearestWeekday = true; 647 } else { 648 throw new ParseException ("'W' option is not valid here. (pos=" + i + ")", i); 649 } 650 TreeSet set = getSet(type); 651 set.add(new Integer (val)); 652 i++; 653 return i; 654 } 655 656 if (c == '#') { 657 if (type != DAY_OF_WEEK) { 658 throw new ParseException ("'#' option is not valid here. (pos=" + i + ")", i); 659 } 660 i++; 661 try { 662 nthdayOfWeek = Integer.parseInt(s.substring(i)); 663 if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { 664 throw new Exception (); 665 } 666 } catch (Exception e) { 667 throw new ParseException ( 668 "A numeric value between 1 and 5 must follow the '#' option", 669 i); 670 } 671 672 TreeSet set = getSet(type); 673 set.add(new Integer (val)); 674 i++; 675 return i; 676 } 677 678 if (c == '-') { 679 i++; 680 c = s.charAt(i); 681 int v = Integer.parseInt(String.valueOf(c)); 682 end = v; 683 i++; 684 if (i >= s.length()) { 685 addToSet(val, end, 1, type); 686 return i; 687 } 688 c = s.charAt(i); 689 if (c >= '0' && c <= '9') { 690 ValueSet vs = getValue(v, s, i); 691 int v1 = vs.value; 692 end = v1; 693 i = vs.pos; 694 } 695 if (i < s.length() && ((c = s.charAt(i)) == '/')) { 696 i++; 697 c = s.charAt(i); 698 int v2 = Integer.parseInt(String.valueOf(c)); 699 i++; 700 if (i >= s.length()) { 701 addToSet(val, end, v2, type); 702 return i; 703 } 704 c = s.charAt(i); 705 if (c >= '0' && c <= '9') { 706 ValueSet vs = getValue(v2, s, i); 707 int v3 = vs.value; 708 addToSet(val, end, v3, type); 709 i = vs.pos; 710 return i; 711 } else { 712 addToSet(val, end, v2, type); 713 return i; 714 } 715 } else { 716 addToSet(val, end, 1, type); 717 return i; 718 } 719 } 720 721 if (c == '/') { 722 i++; 723 c = s.charAt(i); 724 int v2 = Integer.parseInt(String.valueOf(c)); 725 i++; 726 if (i >= s.length()) { 727 addToSet(val, end, v2, type); 728 return i; 729 } 730 c = s.charAt(i); 731 if (c >= '0' && c <= '9') { 732 ValueSet vs = getValue(v2, s, i); 733 int v3 = vs.value; 734 addToSet(val, end, v3, type); 735 i = vs.pos; 736 return i; 737 } else { 738 throw new ParseException ("Unexpected character '" + c + "' after '/'", i); 739 } 740 } 741 742 addToSet(val, end, 0, type); 743 i++; 744 return i; 745 } 746 747 public String getCronExpression() { 748 return cronExpression; 749 } 750 751 public String getExpressionSummary() { 752 StringBuffer buf = new StringBuffer (); 753 754 buf.append("seconds: "); 755 buf.append(getExpressionSetSummary(seconds)); 756 buf.append("\n"); 757 buf.append("minutes: "); 758 buf.append(getExpressionSetSummary(minutes)); 759 buf.append("\n"); 760 buf.append("hours: "); 761 buf.append(getExpressionSetSummary(hours)); 762 buf.append("\n"); 763 buf.append("daysOfMonth: "); 764 buf.append(getExpressionSetSummary(daysOfMonth)); 765 buf.append("\n"); 766 buf.append("months: "); 767 buf.append(getExpressionSetSummary(months)); 768 buf.append("\n"); 769 buf.append("daysOfWeek: "); 770 buf.append(getExpressionSetSummary(daysOfWeek)); 771 buf.append("\n"); 772 buf.append("lastdayOfWeek: "); 773 buf.append(lastdayOfWeek); 774 buf.append("\n"); 775 buf.append("nearestWeekday: "); 776 buf.append(nearestWeekday); 777 buf.append("\n"); 778 buf.append("NthDayOfWeek: "); 779 buf.append(nthdayOfWeek); 780 buf.append("\n"); 781 buf.append("lastdayOfMonth: "); 782 buf.append(lastdayOfMonth); 783 buf.append("\n"); 784 buf.append("years: "); 785 buf.append(getExpressionSetSummary(years)); 786 buf.append("\n"); 787 788 return buf.toString(); 789 } 790 791 protected String getExpressionSetSummary(java.util.Set set) { 792 793 if (set.contains(NO_SPEC)) { 794 return "?"; 795 } 796 if (set.contains(ALL_SPEC)) { 797 return "*"; 798 } 799 800 StringBuffer buf = new StringBuffer (); 801 802 Iterator itr = set.iterator(); 803 boolean first = true; 804 while (itr.hasNext()) { 805 Integer iVal = (Integer ) itr.next(); 806 String val = iVal.toString(); 807 if (!first) { 808 buf.append(","); 809 } 810 buf.append(val); 811 first = false; 812 } 813 814 return buf.toString(); 815 } 816 817 protected String getExpressionSetSummary(java.util.ArrayList list) { 818 819 if (list.contains(NO_SPEC)) { 820 return "?"; 821 } 822 if (list.contains(ALL_SPEC)) { 823 return "*"; 824 } 825 826 StringBuffer buf = new StringBuffer (); 827 828 Iterator itr = list.iterator(); 829 boolean first = true; 830 while (itr.hasNext()) { 831 Integer iVal = (Integer ) itr.next(); 832 String val = iVal.toString(); 833 if (!first) { 834 buf.append(","); 835 } 836 buf.append(val); 837 first = false; 838 } 839 840 return buf.toString(); 841 } 842 843 protected int skipWhiteSpace(int i, String s) { 844 for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) { 845 ; 846 } 847 848 return i; 849 } 850 851 protected int findNextWhiteSpace(int i, String s) { 852 for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) { 853 ; 854 } 855 856 return i; 857 } 858 859 protected void addToSet(int val, int end, int incr, int type) 860 throws ParseException { 861 862 TreeSet set = getSet(type); 863 864 if (type == SECOND || type == MINUTE) { 865 if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) { 866 throw new ParseException ( 867 "Minute and Second values must be between 0 and 59", 868 -1); 869 } 870 } else if (type == HOUR) { 871 if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) { 872 throw new ParseException ( 873 "Hour values must be between 0 and 23", -1); 874 } 875 } else if (type == DAY_OF_MONTH) { 876 if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) 877 && (val != NO_SPEC_INT)) { 878 throw new ParseException ( 879 "Day of month values must be between 1 and 31", -1); 880 } 881 } else if (type == MONTH) { 882 if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) { 883 throw new ParseException ( 884 "Month values must be between 1 and 12", -1); 885 } 886 } else if (type == DAY_OF_WEEK) { 887 if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) 888 && (val != NO_SPEC_INT)) { 889 throw new ParseException ( 890 "Day-of-Week values must be between 1 and 7", -1); 891 } 892 } 893 894 if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) { 895 if (val != -1) { 896 set.add(new Integer (val)); 897 } else { 898 set.add(NO_SPEC); 899 } 900 901 return; 902 } 903 904 int startAt = val; 905 int stopAt = end; 906 907 if (val == ALL_SPEC_INT && incr <= 0) { 908 incr = 1; 909 set.add(ALL_SPEC); } 911 912 if (type == SECOND || type == MINUTE) { 913 if (stopAt == -1) { 914 stopAt = 59; 915 } 916 if (startAt == -1 || startAt == ALL_SPEC_INT) { 917 startAt = 0; 918 } 919 } else if (type == HOUR) { 920 if (stopAt == -1) { 921 stopAt = 23; 922 } 923 if (startAt == -1 || startAt == ALL_SPEC_INT) { 924 startAt = 0; 925 } 926 } else if (type == DAY_OF_MONTH) { 927 if (stopAt == -1) { 928 stopAt = 31; 929 } 930 if (startAt == -1 || startAt == ALL_SPEC_INT) { 931 startAt = 1; 932 } 933 } else if (type == MONTH) { 934 if (stopAt == -1) { 935 stopAt = 12; 936 } 937 if (startAt == -1 || startAt == ALL_SPEC_INT) { 938 startAt = 1; 939 } 940 } else if (type == DAY_OF_WEEK) { 941 if (stopAt == -1) { 942 stopAt = 7; 943 } 944 if (startAt == -1 || startAt == ALL_SPEC_INT) { 945 startAt = 1; 946 } 947 } else if (type == YEAR) { 948 if (stopAt == -1) { 949 stopAt = 2099; 950 } 951 if (startAt == -1 || startAt == ALL_SPEC_INT) { 952 startAt = 1970; 953 } 954 } 955 956 for (int i = startAt; i <= stopAt; i += incr) { 957 set.add(new Integer (i)); 958 } 959 } 960 961 protected TreeSet getSet(int type) { 962 switch (type) { 963 case SECOND: 964 return seconds; 965 case MINUTE: 966 return minutes; 967 case HOUR: 968 return hours; 969 case DAY_OF_MONTH: 970 return daysOfMonth; 971 case MONTH: 972 return months; 973 case DAY_OF_WEEK: 974 return daysOfWeek; 975 case YEAR: 976 return years; 977 default: 978 return null; 979 } 980 } 981 982 protected ValueSet getValue(int v, String s, int i) { 983 char c = s.charAt(i); 984 String s1 = String.valueOf(v); 985 while (c >= '0' && c <= '9') { 986 s1 += c; 987 i++; 988 if (i >= s.length()) { 989 break; 990 } 991 c = s.charAt(i); 992 } 993 ValueSet val = new ValueSet(); 994 995 val.pos = (i < s.length()) ? i : i + 1; 996 val.value = Integer.parseInt(s1); 997 return val; 998 } 999 1000 protected int getNumericValue(String s, int i) { 1001 int endOfVal = findNextWhiteSpace(i, s); 1002 String val = s.substring(i, endOfVal); 1003 return Integer.parseInt(val); 1004 } 1005 1006 protected int getMonthNumber(String s) { 1007 Integer integer = (Integer ) monthMap.get(s); 1008 1009 if (integer == null) { 1010 return -1; 1011 } 1012 1013 return integer.intValue(); 1014 } 1015 1016 protected int getDayOfWeekNumber(String s) { 1017 Integer integer = (Integer ) dayMap.get(s); 1018 1019 if (integer == null) { 1020 return -1; 1021 } 1022 1023 return integer.intValue(); 1024 } 1025 1026 1032 protected Date getTimeAfter(Date afterTime) { 1033 1034 Calendar cl = Calendar.getInstance(getTimeZone()); 1035 1036 afterTime = new Date (afterTime.getTime() + 1000); 1039 cl.setTime(afterTime); 1041 cl.set(Calendar.MILLISECOND, 0); 1042 1043 boolean gotOne = false; 1044 while (!gotOne) { 1046 1047 if(cl.get(Calendar.YEAR) > 2999) return null; 1050 1051 SortedSet st = null; 1052 int t = 0; 1053 1054 int sec = cl.get(Calendar.SECOND); 1055 int min = cl.get(Calendar.MINUTE); 1056 1057 st = seconds.tailSet(new Integer (sec)); 1059 if (st != null && st.size() != 0) { 1060 sec = ((Integer ) st.first()).intValue(); 1061 } else { 1062 sec = ((Integer ) seconds.first()).intValue(); 1063 min++; 1064 cl.set(Calendar.MINUTE, min); 1065 } 1066 cl.set(Calendar.SECOND, sec); 1067 1068 min = cl.get(Calendar.MINUTE); 1069 int hr = cl.get(Calendar.HOUR_OF_DAY); 1070 t = -1; 1071 1072 st = minutes.tailSet(new Integer (min)); 1074 if (st != null && st.size() != 0) { 1075 t = min; 1076 min = ((Integer ) st.first()).intValue(); 1077 } else { 1078 min = ((Integer ) minutes.first()).intValue(); 1079 hr++; 1080 } 1081 if (min != t) { 1082 cl.set(Calendar.SECOND, 0); 1083 cl.set(Calendar.MINUTE, min); 1084 setCalendarHour(cl, hr); 1085 continue; 1086 } 1087 cl.set(Calendar.MINUTE, min); 1088 1089 hr = cl.get(Calendar.HOUR_OF_DAY); 1090 int day = cl.get(Calendar.DAY_OF_MONTH); 1091 t = -1; 1092 1093 st = hours.tailSet(new Integer (hr)); 1095 if (st != null && st.size() != 0) { 1096 t = hr; 1097 hr = ((Integer ) st.first()).intValue(); 1098 } else { 1099 hr = ((Integer ) hours.first()).intValue(); 1100 day++; 1101 } 1102 if (hr != t) { 1103 cl.set(Calendar.SECOND, 0); 1104 cl.set(Calendar.MINUTE, 0); 1105 cl.set(Calendar.DAY_OF_MONTH, day); 1106 setCalendarHour(cl, hr); 1107 continue; 1108 } 1109 cl.set(Calendar.HOUR_OF_DAY, hr); 1110 1111 day = cl.get(Calendar.DAY_OF_MONTH); 1112 int mon = cl.get(Calendar.MONTH) + 1; 1113 t = -1; 1116 int tmon = mon; 1117 1118 boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC); 1120 boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC); 1121 if (dayOfMSpec && !dayOfWSpec) { st = daysOfMonth.tailSet(new Integer (day)); 1123 if (lastdayOfMonth) { 1124 if(!nearestWeekday) { 1125 t = day; 1126 day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); 1127 } else { 1128 t = day; 1129 day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); 1130 1131 java.util.Calendar tcal = java.util.Calendar.getInstance(); 1132 tcal.set(Calendar.SECOND, 0); 1133 tcal.set(Calendar.MINUTE, 0); 1134 tcal.set(Calendar.HOUR_OF_DAY, 0); 1135 tcal.set(Calendar.DAY_OF_MONTH, day); 1136 tcal.set(Calendar.MONTH, mon - 1); 1137 tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); 1138 1139 int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); 1140 int dow = tcal.get(Calendar.DAY_OF_WEEK); 1141 1142 if(dow == Calendar.SATURDAY && day == 1) { 1143 day += 2; 1144 } else if(dow == Calendar.SATURDAY) { 1145 day -= 1; 1146 } else if(dow == Calendar.SUNDAY && day == ldom) { 1147 day -= 2; 1148 } else if(dow == Calendar.SUNDAY) { 1149 day += 1; 1150 } 1151 1152 tcal.set(Calendar.SECOND, sec); 1153 tcal.set(Calendar.MINUTE, min); 1154 tcal.set(Calendar.HOUR_OF_DAY, hr); 1155 tcal.set(Calendar.DAY_OF_MONTH, day); 1156 tcal.set(Calendar.MONTH, mon - 1); 1157 Date nTime = tcal.getTime(); 1158 if(nTime.before(afterTime)) { 1159 day = 1; 1160 mon++; 1161 } 1162 } 1163 } else if(nearestWeekday) { 1164 t = day; 1165 day = ((Integer ) daysOfMonth.first()).intValue(); 1166 1167 java.util.Calendar tcal = java.util.Calendar.getInstance(); 1168 tcal.set(Calendar.SECOND, 0); 1169 tcal.set(Calendar.MINUTE, 0); 1170 tcal.set(Calendar.HOUR_OF_DAY, 0); 1171 tcal.set(Calendar.DAY_OF_MONTH, day); 1172 tcal.set(Calendar.MONTH, mon - 1); 1173 tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); 1174 1175 int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); 1176 int dow = tcal.get(Calendar.DAY_OF_WEEK); 1177 1178 if(dow == Calendar.SATURDAY && day == 1) { 1179 day += 2; 1180 } else if(dow == Calendar.SATURDAY) { 1181 day -= 1; 1182 } else if(dow == Calendar.SUNDAY && day == ldom) { 1183 day -= 2; 1184 } else if(dow == Calendar.SUNDAY) { 1185 day += 1; 1186 } 1187 1188 1189 tcal.set(Calendar.SECOND, sec); 1190 tcal.set(Calendar.MINUTE, min); 1191 tcal.set(Calendar.HOUR_OF_DAY, hr); 1192 tcal.set(Calendar.DAY_OF_MONTH, day); 1193 tcal.set(Calendar.MONTH, mon - 1); 1194 Date nTime = tcal.getTime(); 1195 if(nTime.before(afterTime)) { 1196 day = ((Integer ) daysOfMonth.first()).intValue();; 1197 mon++; 1198 } 1199 } else if (st != null && st.size() != 0) { 1200 t = day; 1201 day = ((Integer ) st.first()).intValue(); 1202 } else { 1203 day = ((Integer ) daysOfMonth.first()).intValue(); 1204 mon++; 1205 } 1206 1207 if (day != t || mon != tmon) { 1208 cl.set(Calendar.SECOND, 0); 1209 cl.set(Calendar.MINUTE, 0); 1210 cl.set(Calendar.HOUR_OF_DAY, 0); 1211 cl.set(Calendar.DAY_OF_MONTH, day); 1212 cl.set(Calendar.MONTH, mon - 1); 1213 continue; 1216 } 1217 } else if (dayOfWSpec && !dayOfMSpec) { if (lastdayOfWeek) { int dow = ((Integer ) daysOfWeek.first()).intValue(); int cDow = cl.get(Calendar.DAY_OF_WEEK); int daysToAdd = 0; 1224 if (cDow < dow) { 1225 daysToAdd = dow - cDow; 1226 } 1227 if (cDow > dow) { 1228 daysToAdd = dow + (7 - cDow); 1229 } 1230 1231 int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); 1232 1233 if (day + daysToAdd > lDay) { cl.set(Calendar.SECOND, 0); 1236 cl.set(Calendar.MINUTE, 0); 1237 cl.set(Calendar.HOUR_OF_DAY, 0); 1238 cl.set(Calendar.DAY_OF_MONTH, 1); 1239 cl.set(Calendar.MONTH, mon); 1240 continue; 1242 } 1243 1244 while ((day + daysToAdd + 7) <= lDay) { 1246 daysToAdd += 7; 1247 } 1248 1249 day += daysToAdd; 1250 1251 if (daysToAdd > 0) { 1252 cl.set(Calendar.SECOND, 0); 1253 cl.set(Calendar.MINUTE, 0); 1254 cl.set(Calendar.HOUR_OF_DAY, 0); 1255 cl.set(Calendar.DAY_OF_MONTH, day); 1256 cl.set(Calendar.MONTH, mon - 1); 1257 continue; 1259 } 1260 1261 } else if (nthdayOfWeek != 0) { 1262 int dow = ((Integer ) daysOfWeek.first()).intValue(); int cDow = cl.get(Calendar.DAY_OF_WEEK); int daysToAdd = 0; 1267 if (cDow < dow) { 1268 daysToAdd = dow - cDow; 1269 } else if (cDow > dow) { 1270 daysToAdd = dow + (7 - cDow); 1271 } 1272 1273 boolean dayShifted = false; 1274 if (daysToAdd > 0) { 1275 dayShifted = true; 1276 } 1277 1278 day += daysToAdd; 1279 int weekOfMonth = day / 7; 1280 if (day % 7 > 0) { 1281 weekOfMonth++; 1282 } 1283 1284 daysToAdd = (nthdayOfWeek - weekOfMonth) * 7; 1285 day += daysToAdd; 1286 if (daysToAdd < 0 1287 || day > getLastDayOfMonth(mon, cl 1288 .get(Calendar.YEAR))) { 1289 cl.set(Calendar.SECOND, 0); 1290 cl.set(Calendar.MINUTE, 0); 1291 cl.set(Calendar.HOUR_OF_DAY, 0); 1292 cl.set(Calendar.DAY_OF_MONTH, 1); 1293 cl.set(Calendar.MONTH, mon); 1294 continue; 1296 } else if (daysToAdd > 0 || dayShifted) { 1297 cl.set(Calendar.SECOND, 0); 1298 cl.set(Calendar.MINUTE, 0); 1299 cl.set(Calendar.HOUR_OF_DAY, 0); 1300 cl.set(Calendar.DAY_OF_MONTH, day); 1301 cl.set(Calendar.MONTH, mon - 1); 1302 continue; 1304 } 1305 } else { 1306 int cDow = cl.get(Calendar.DAY_OF_WEEK); int dow = ((Integer ) daysOfWeek.first()).intValue(); st = daysOfWeek.tailSet(new Integer (cDow)); 1310 if (st != null && st.size() > 0) { 1311 dow = ((Integer ) st.first()).intValue(); 1312 } 1313 1314 int daysToAdd = 0; 1315 if (cDow < dow) { 1316 daysToAdd = dow - cDow; 1317 } 1318 if (cDow > dow) { 1319 daysToAdd = dow + (7 - cDow); 1320 } 1321 1322 int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); 1323 1324 if (day + daysToAdd > lDay) { cl.set(Calendar.SECOND, 0); 1327 cl.set(Calendar.MINUTE, 0); 1328 cl.set(Calendar.HOUR_OF_DAY, 0); 1329 cl.set(Calendar.DAY_OF_MONTH, 1); 1330 cl.set(Calendar.MONTH, mon); 1331 continue; 1333 } else if (daysToAdd > 0) { cl.set(Calendar.SECOND, 0); 1335 cl.set(Calendar.MINUTE, 0); 1336 cl.set(Calendar.HOUR_OF_DAY, 0); 1337 cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd); 1338 cl.set(Calendar.MONTH, mon - 1); 1339 continue; 1342 } 1343 } 1344 } else { throw new UnsupportedOperationException ( 1346 "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."); 1347 } 1349 cl.set(Calendar.DAY_OF_MONTH, day); 1350 1351 mon = cl.get(Calendar.MONTH) + 1; 1352 int year = cl.get(Calendar.YEAR); 1355 t = -1; 1356 1357 if (year > 2099) { 1360 return null; 1361 } 1362 1363 st = months.tailSet(new Integer (mon)); 1365 if (st != null && st.size() != 0) { 1366 t = mon; 1367 mon = ((Integer ) st.first()).intValue(); 1368 } else { 1369 mon = ((Integer ) months.first()).intValue(); 1370 year++; 1371 } 1372 if (mon != t) { 1373 cl.set(Calendar.SECOND, 0); 1374 cl.set(Calendar.MINUTE, 0); 1375 cl.set(Calendar.HOUR_OF_DAY, 0); 1376 cl.set(Calendar.DAY_OF_MONTH, 1); 1377 cl.set(Calendar.MONTH, mon - 1); 1378 cl.set(Calendar.YEAR, year); 1381 continue; 1382 } 1383 cl.set(Calendar.MONTH, mon - 1); 1384 1387 year = cl.get(Calendar.YEAR); 1388 t = -1; 1389 1390 st = years.tailSet(new Integer (year)); 1392 if (st != null && st.size() != 0) { 1393 t = year; 1394 year = ((Integer ) st.first()).intValue(); 1395 } else { 1396 return null; } 1398 1399 if (year != t) { 1400 cl.set(Calendar.SECOND, 0); 1401 cl.set(Calendar.MINUTE, 0); 1402 cl.set(Calendar.HOUR_OF_DAY, 0); 1403 cl.set(Calendar.DAY_OF_MONTH, 1); 1404 cl.set(Calendar.MONTH, 0); 1405 cl.set(Calendar.YEAR, year); 1408 continue; 1409 } 1410 cl.set(Calendar.YEAR, year); 1411 1412 gotOne = true; 1413 } 1415 return cl.getTime(); 1416 } 1417 1418 1425 protected void setCalendarHour(Calendar cal, int hour) { 1426 cal.set(java.util.Calendar.HOUR_OF_DAY, hour); 1427 if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) { 1428 cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1); 1429 } 1430 } 1431 1432 1436 protected Date getTimeBefore(Date endTime) { 1437 return null; 1439 } 1440 1441 1445 public Date getFinalFireTime() { 1446 return null; 1448 } 1449 1450 protected boolean isLeapYear(int year) { 1451 return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)); 1452 } 1453 1454 protected int getLastDayOfMonth(int monthNum, int year) { 1455 1456 switch (monthNum) { 1457 case 1: 1458 return 31; 1459 case 2: 1460 return (isLeapYear(year)) ? 29 : 28; 1461 case 3: 1462 return 31; 1463 case 4: 1464 return 30; 1465 case 5: 1466 return 31; 1467 case 6: 1468 return 30; 1469 case 7: 1470 return 31; 1471 case 8: 1472 return 31; 1473 case 9: 1474 return 30; 1475 case 10: 1476 return 31; 1477 case 11: 1478 return 30; 1479 case 12: 1480 return 31; 1481 default: 1482 throw new IllegalArgumentException ("Illegal month number: " 1483 + monthNum); 1484 } 1485 } 1486 1487 1488 private void readObject(java.io.ObjectInputStream stream) 1489 throws java.io.IOException , ClassNotFoundException { 1490 1491 stream.defaultReadObject(); 1492 try { 1493 buildExpression(cronExpression); 1494 } catch (Exception ignore) { 1495 } } 1497 1498 public Object clone() { 1499 CronExpression copy = null; 1500 try { 1501 copy = new CronExpression(getCronExpression()); 1502 copy.setTimeZone(getTimeZone()); 1503 } catch (ParseException ex) { throw new IncompatibleClassChangeError ("Not Cloneable."); 1505 } 1506 return copy; 1507 } 1508} 1509 1510class ValueSet { 1511 public int value; 1512 1513 public int pos; 1514} | Popular Tags |