/**
  * Gets a given occurence on a given day-of-week.
  *
  * @param int $curdate       The current timestamp of an occurence.
  * @param int $day_of_week   The index of a given day-of-week.
  * @param int $week_of_month The index of a given week-of-month.
  *
  * @return int The timestamp of the requested occurrence.
  */
 private function getNthDayOfWeek($curdate, $day_of_week, $week_of_month)
 {
     if ($week_of_month == -1) {
         // LAST WEEK
         $nextdate = Tribe__Date_Utils::get_last_day_of_week_in_month($curdate, $day_of_week);
         // If the date returned above is the same as the date we're starting from
         // move on to the next month by interval to consider.
         if ($curdate == $nextdate) {
             $curdate = mktime(0, 0, 0, date('n', $curdate) + $this->months_between, 1, date('Y', $curdate));
             $nextdate = Tribe__Date_Utils::get_last_day_of_week_in_month($curdate, $day_of_week);
         }
         return $nextdate;
     } else {
         // get the first occurrence of the requested day of the week from the requested $curdate's month
         $first_occurring_day_of_week = Tribe__Date_Utils::get_first_day_of_week_in_month($curdate, $day_of_week);
         // get that day of the week in the requested nth week
         $maybe_date = strtotime(date(Tribe__Events__Pro__Date_Series_Rules__Rules_Interface::DATE_FORMAT, $first_occurring_day_of_week) . ' + ' . ($week_of_month - 1) . ' weeks');
         // if $maybe_date equals or is before the $curdate, then try next month
         // (this should only be true if $week_of_month is 1)
         if (date(Tribe__Events__Pro__Date_Series_Rules__Rules_Interface::DATE_ONLY_FORMAT, $maybe_date) <= date(Tribe__Events__Pro__Date_Series_Rules__Rules_Interface::DATE_ONLY_FORMAT, $curdate)) {
             // get the first day of the next month according to $this->months_between
             $next_month = mktime(0, 0, 0, date('n', $curdate) + $this->months_between, 1, date('Y', $curdate));
             // Get the first occurrence of the requested day of the week from $next_month's month
             $first_occurring_day_of_week = Tribe__Date_Utils::get_first_day_of_week_in_month($next_month, $day_of_week);
             // Get that day of the week in the requested nth week
             $maybe_date = strtotime(date(Tribe__Events__Pro__Date_Series_Rules__Rules_Interface::DATE_FORMAT, $first_occurring_day_of_week) . ' + ' . ($week_of_month - 1) . ' weeks');
         }
         // if $maybe_date doesn't have the same month as $first_occurring_day_of_week, keep incrementing by $this->months_between
         // until they do, but don't infinitely loop past the 'recurrenceMaxMonthsAfter' setting
         $i = 0;
         while (date('n', $maybe_date) != date('n', $first_occurring_day_of_week) && $i <= tribe_get_option('recurrenceMaxMonthsAfter', 24)) {
             $next_month = mktime(0, 0, 0, date('n', $first_occurring_day_of_week) + $this->months_between, 1, date('Y', $first_occurring_day_of_week));
             $first_occurring_day_of_week = Tribe__Date_Utils::get_first_day_of_week_in_month($next_month, $day_of_week);
             $maybe_date = strtotime(date(Tribe__Events__Pro__Date_Series_Rules__Rules_Interface::DATE_FORMAT, $first_occurring_day_of_week) . ' + ' . ($week_of_month - 1) . ' weeks');
             $i += $this->months_between;
         }
         return $maybe_date;
     }
 }
 /**
  * Get the timestamp of the next upcoming Nth day of month.
  *
  * @param int       $curdate        The current occurrence's timestamp
  * @param int|array $days_of_week    Index(-es) of the possible day(s)-of-week the next instance may land on
  * @param int|array $weeks_of_month  Index(-es) of the possible week(s) of the month the next instance may land on
  * @param int|array $months_of_year  Index(-es) of the possible month(s) of the year the next instance may land on
  *
  * @return int|false The timestamp of the next occurrence on the nth day of the month or false
  */
 private function getNthDayOfMonth($curdate, $days_of_week, $weeks_of_month, $months_of_year)
 {
     // Cast to arrays for consistency
     $days_of_week = (array) $days_of_week;
     $weeks_of_month = (array) $weeks_of_month;
     $months_of_year = (array) $months_of_year;
     // Obtain the hour, minute and second of $curdate for later comparison
     $cur_hour = (int) date('G', $curdate);
     $cur_minute = (int) date('i', $curdate);
     $cur_second = (int) date('s', $curdate);
     // Sort and rotate the arrays to give us a sensible starting point
     $this->sort_and_rotate_int_array($days_of_week, (int) date('N', $curdate));
     $this->sort_and_rotate_int_array($months_of_year, (int) date('n', $curdate));
     sort($weeks_of_month);
     $weeks_of_month = array_map('intval', $weeks_of_month);
     // The next occurence must take place this year or the next applicable year
     $year = (int) date('Y', $curdate);
     $years = array($year, $year + $this->years_between);
     // Examine each possible year and month
     foreach ($years as $year) {
         foreach ($months_of_year as $month) {
             // If we are behind $curdate's month and year then keep advancing
             if ($year <= date('Y', $curdate) && $month < date('n', $curdate)) {
                 continue;
             }
             foreach ($weeks_of_month as $nth_week) {
                 foreach ($days_of_week as $day) {
                     // Determine the date of the first of these days (ie, the date of the first Tuesday this month)
                     $start_of_month = mktime(0, 0, 0, $month, 1, $year);
                     $first_date = Tribe__Date_Utils::get_first_day_of_week_in_month($start_of_month, $day);
                     $day_of_month = (int) date('j', $first_date);
                     // Add the relevant number of weeks
                     $week = $nth_week > 0 ? $nth_week : abs($nth_week);
                     $direction = $nth_week > 0 ? 1 : -1;
                     $day_of_month = date('j', Tribe__Date_Utils::get_weekday_timestamp($day, $week, $month, $year, $direction));
                     // Form a timestamp representing this day of the week in the appropriate week of the month
                     $timestamp = mktime($cur_hour, $cur_minute, $cur_second, $month, $day_of_month, $year);
                     // If we got a valid timestamp that is ahead of $curdate, we have a winner
                     if ($timestamp && $timestamp > $curdate) {
                         return $timestamp;
                     }
                 }
             }
         }
     }
     // No match?
     return false;
 }