Commits

Anonymous committed 0aa3431

Fixed a fairly obscure bug in the leap-year handling.

Comments (0)

Files changed (2)

src/core/java/com/opensymphony/oscache/util/FastCronParser.java

         boolean haveDOM = validDaysOfMonth != Long.MAX_VALUE;
         boolean haveDOW = validDaysOfWeek != Long.MAX_VALUE;
 
+        boolean skippedNonLeapYear = false;
+
         while (true) {
             boolean retry = false;
 
                 for (int i = month + 11; i > (month - 1); i--) {
                     int testMonth = (i % 12) + 1;
 
-                    int numDays = numberOfDaysInMonth(testMonth, year);
-
                     // Check if the month is valid
                     if (((1L << (testMonth - 1)) & validMonths) != 0) {
-                        if (testMonth > month) {
+                        if ((testMonth > month) || skippedNonLeapYear) {
                             year--;
                         }
 
                         // Check there are enough days in this month (catches non leap-years trying to match the 29th Feb)
+                        int numDays = numberOfDaysInMonth(testMonth, year);
+
                         if (!haveDOM || (numDays >= lookupMin[DAY_OF_MONTH])) {
-                            if (month != testMonth) {
+                            if ((month != testMonth) || skippedNonLeapYear) {
                                 // New DOM = min(maxDOM, prevDays);  ie, the highest valid value
                                 dayOfMonth = (numDays <= lookupMax[DAY_OF_MONTH]) ? numDays : lookupMax[DAY_OF_MONTH];
-
                                 hour = lookupMax[HOUR];
                                 minute = lookupMax[MINUTE];
+                                month = testMonth;
                             }
 
-                            month = testMonth;
                             found = true;
                             break;
                         }
                     }
                 }
 
+                skippedNonLeapYear = false;
+
                 if (!found) {
                     // The only time we drop out here is when we're searching for the 29th of February and no other date!
-                    year--;
+                    skippedNonLeapYear = true;
                     continue;
                 }
             }

src/core/test/com/opensymphony/oscache/util/TestFastCronParser.java

         cronCall("01/03/2003 12:00", "1 23 * * 0", "23/02/2003 23:01", false); // non-leap year
         cronCall("01/03/2004 12:00", "1 23 * * 0", "29/02/2004 23:01", false); // leap year
         cronCall("01/03/2003 12:00", "* * 29 2 *", "29/02/2000 23:59", false); // Find the previous leap-day
+        cronCall("01/02/2003 12:00", "* * 29 2 *", "29/02/2000 23:59", false); // Find the previous leap-day
+        cronCall("01/02/2004 12:00", "* * 29 2 *", "29/02/2000 23:59", false); // Find the previous leap-day
 
         // Interval and range tests
         cronCall("20/12/2003 10:00", "* */4 * * *", "20/12/2003 08:59", false);
     */
     public void testPerformance() {
         if (true) {
-            return; // Comment out this line to benchmark
+            //            return; // Comment out this line to benchmark
         }
 
         SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm");