public function testModifyDatePHP52() { $modify = 'first Monday of +1 Month'; $date = new DateTime('2014-01-30'); $date2 = new DateTime('2014-01-30'); $date3 = _eventorganiser_php52_modify($date2, $modify); $expected = new DateTime('2014-02-03'); $this->assertEquals($expected, $date3); }
/** * This is a private function - handles the generation of occurrence dates from the schedule data * @access private * @ignore * * @param array $event_data - Array containing the event's schedule data * @return array $event_data - Array containing the event's schedule data including 'occurrences', an array of DateTimes */ function _eventorganiser_generate_occurrences($event_data = array()) { $event_defaults = array('start' => '', 'end' => '', 'all_day' => 0, 'schedule' => 'once', 'schedule_meta' => '', 'frequency' => 1, 'schedule_last' => '', 'number_occurrences' => 0, 'exclude' => array(), 'include' => array()); extract(wp_parse_args($event_data, $event_defaults)); $occurrences = array(); //occurrences array $exclude = array_filter((array) $exclude); $include = array_filter((array) $include); $exclude = array_udiff($exclude, $include, '_eventorganiser_compare_datetime'); $include = array_udiff($include, $exclude, '_eventorganiser_compare_datetime'); //White list schedule if (!in_array($schedule, array('once', 'daily', 'weekly', 'monthly', 'yearly', 'custom'))) { return new WP_Error('eo_error', __('Schedule not recognised.', 'eventorganiser')); } //Ensure event frequency is a positive integer. Else set to 1. $frequency = max(absint($frequency), 1); $all_day = (int) $all_day; $number_occurrences = absint($number_occurrences); //Check dates are supplied and are valid if (!$start instanceof DateTime) { return new WP_Error('eo_error', __('Start date not provided.', 'eventorganiser')); } if (!$end instanceof DateTime) { $end = clone $start; } //If use 'number_occurrences' to limit recurring event, set dummy 'schedule_last' date. if (!$schedule_last instanceof DateTime && $number_occurrences && in_array($schedule, array('daily', 'weekly', 'monthly', 'yearly'))) { //Set dummy "last occurrance" date. $schedule_last = clone $start; } else { $number_occurrences = 0; } if ('once' == $schedule || !$schedule_last instanceof DateTime) { $schedule_last = clone $start; } //Check dates are in chronological order if ($end < $start) { return new WP_Error('eo_error', __('Start date occurs after end date.', 'eventorganiser')); } if ($schedule_last < $start) { return new WP_Error('eo_error', __('Schedule end date is before is before the start date.', 'eventorganiser')); } //Now set timezones $timezone = eo_get_blog_timezone(); $start->setTimezone($timezone); $end->setTimezone($timezone); $schedule_last->setTimezone($timezone); $H = intval($start->format('H')); $i = intval($start->format('i')); $start_days = array(); $workaround = ''; $icaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); $weekdays = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); $ical2day = array('SU' => 'Sunday', 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday'); //Set up schedule switch ($schedule) { case 'once': case 'custom': $frequency = 1; $schedule_meta = ''; $schedule_start = clone $start; $schedule_last = clone $start; $start_days[] = clone $start; $workaround = 'once'; //Not strictly a workaround. break; case 'daily': $interval = "+" . $frequency . "day"; $start_days[] = clone $start; break; case 'weekly': $schedule_meta = $schedule_meta ? array_filter($schedule_meta) : array(); if (!empty($schedule_meta) && is_array($schedule_meta)) { foreach ($schedule_meta as $day) { $start_day = clone $start; $start_day->modify($ical2day[$day]); $start_days[] = $start_day; } } else { $schedule_meta = array($icaldays[$start->format('w')]); $start_days[] = clone $start; } $interval = "+" . $frequency . "week"; break; case 'monthly': $start_days[] = clone $start; $rule_value = explode('=', $schedule_meta, 2); $rule = $rule_value[0]; $values = !empty($rule_value[1]) ? explode(',', $rule_value[1]) : array(); //Should only be one value, but may support more in future $values = array_filter($values); if ($rule == 'BYMONTHDAY') { $date = (int) $start_days[0]->format('d'); $interval = "+" . $frequency . "month"; if ($date >= 29) { $workaround = 'short months'; } //This case deals with 29/30/31 of month $schedule_meta = 'BYMONTHDAY=' . $date; } else { if (empty($values)) { $date = (int) $start_days[0]->format('d'); $n = ceil($date / 7); // nth weekday of month. $day_num = intval($start_days[0]->format('w')); //0 (Sun) - 6(Sat) } else { //expect e.g. array( 2MO ) preg_match('/^(-?\\d{1,2})([a-zA-Z]{2})/', $values[0], $matches); $n = (int) $matches[1]; $day_num = array_search($matches[2], $icaldays); //(Sun) - 6(Sat) } if ($n == 5) { $n = -1; } //If 5th, interpret it as last. $ordinal = array('1' => "first", '2' => "second", '3' => "third", '4' => "fourth", '-1' => "last"); if (!isset($ordinal[$n])) { return new WP_Error('eo_error', __('Invalid monthly schedule (invalid ordinal)', 'eventorganiser')); } $ical_day = $icaldays[$day_num]; //ical day from day_num (SU - SA) $day = $weekdays[$day_num]; //Full day name from day_num (Sunday -Monday) $schedule_meta = 'BYDAY=' . $n . $ical_day; //E.g. BYDAY=2MO $interval = $ordinal[$n] . ' ' . $day . ' of +' . $frequency . ' month'; //E.g. second monday of +1 month //Work around for PHP <5.3 if (!function_exists('date_diff')) { $workaround = 'php5.2'; } } break; case 'yearly': $start_days[] = clone $start; if ('29-02' == $start_days[0]->format('d-m')) { $workaround = 'leap year'; } $interval = "+" . $frequency . "year"; break; } //End $schedule switch //Now we have setup and validated the schedules - loop through and generate occurrences foreach ($start_days as $index => $start_day) { $current = clone $start_day; $occurrence_n = 0; switch ($workaround) { //Not really a workaround. Just add the occurrence and finish. case 'once': $current->setTime($H, $i); $occurrences[] = clone $current; break; //Loops for monthly events that require php5.3 functionality //Loops for monthly events that require php5.3 functionality case 'php5.2': while ($current <= $schedule_last || $occurrence_n < $number_occurrences) { $current->setTime($H, $i); $occurrences[] = clone $current; $current = _eventorganiser_php52_modify($current, $interval); $occurrence_n++; } break; //Loops for monthly events on the 29th/30th/31st //Loops for monthly events on the 29th/30th/31st case 'short months': $day_int = intval($start_day->format('d')); //Set the first month $current_month = clone $start_day; $current_month = date_create($current_month->format('Y-m-1')); while ($current_month <= $schedule_last || $occurrence_n < $number_occurrences) { $month_int = intval($current_month->format('m')); $year_int = intval($current_month->format('Y')); if (checkdate($month_int, $day_int, $year_int)) { $current = new DateTime($day_int . '-' . $month_int . '-' . $year_int, $timezone); $current->setTime($H, $i); $occurrences[] = clone $current; $occurrence_n++; } $current_month->modify($interval); } break; //To be used for yearly events occuring on Feb 29 //To be used for yearly events occuring on Feb 29 case 'leap year': $current_year = clone $current; $current_year->modify('-1 day'); while ($current_year <= $schedule_last || $occurrence_n < $number_occurrences) { $is_leap_year = (int) $current_year->format('L'); if ($is_leap_year) { $current = clone $current_year; $current->modify('+1 day'); $current->setTime($H, $i); $occurrences[] = clone $current; $occurrence_n++; } $current_year->modify($interval); } break; default: while ($current <= $schedule_last || $occurrence_n < $number_occurrences) { $current->setTime($H, $i); $occurrences[] = clone $current; $current->modify($interval); $occurrence_n++; } break; } //End 'workaround' switch; } //Now schedule meta is set up and occurrences are generated. if ($number_occurrences > 0) { //If recurrence is limited by #occurrences. Do that here. sort($occurrences); $occurrences = array_slice($occurrences, 0, $number_occurrences); } //Add inclusions, removes exceptions and duplicates if (defined('WP_DEBUG') && WP_DEBUG) { //Make sure 'included' dates doesn't appear in generate date $include = array_udiff($include, $occurrences, '_eventorganiser_compare_datetime'); } $occurrences = array_merge($occurrences, $include); $occurrences = array_udiff($occurrences, $exclude, '_eventorganiser_compare_datetime'); $occurrences = _eventorganiser_remove_duplicates($occurrences); //Sort occurrences sort($occurrences); if (empty($occurrences) || !$occurrences[0] || !$occurrences[0] instanceof DateTime) { return new WP_Error('eo_error', __('Event does not contain any dates.', 'eventorganiser')); } $schedule_start = clone $occurrences[0]; $schedule_last = clone end($occurrences); $_event_data = array('start' => $start, 'end' => $end, 'all_day' => $all_day, 'schedule' => $schedule, 'schedule_meta' => $schedule_meta, 'frequency' => $frequency, 'schedule_start' => $schedule_start, 'schedule_last' => $schedule_last, 'exclude' => $exclude, 'include' => $include, 'occurrences' => $occurrences); /** * Filters the event schedule after its dates has been generated by a given schedule. * * The filtered array is an array of occurrences generated from a * schedule which may include: * * * **start** (DateTime) - when the event starts * * **end** (DateTime) - when the event ends * * **all_day** (Bool) - If the event is all day or no * * **all_day** (Bool) - If the event is all day or not * * **schedule** (String) - One of once|weekl|daily|monthly|yearly|custom * * **schedule_meta** (Array|String) - See documentation for `eo_insert_event()` * * **frequency** (int) - The frequency of which the event repeats * * **schedule_last** (DateTime) - date of last occurrence of event * * **number_occurrences** (int) - number of times the event should repeat (if `schedule_last` is not specified). * * **exclude** (array) - Array of DateTime objects to exclude from the schedule * * **include** (array) - Array of DateTime objects to include in the schedule * * **occurrences** (array) - Array of DateTime objects generated from the above schedule. * * @param array The event schedule with generated occurrences. * @param array The original event schedule (without occurrences). */ $_event_data = apply_filters('eventorganiser_generate_occurrences', $_event_data, $event_data); return $_event_data; }
public function testModifyDatePHP52() { $modify = 'first Monday of +1 Month'; $expected = new DateTime('2014-02-03'); $date = new DateTime('2014-01-30'); $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify)); //Check multiple months $modify = 'LaSt FrIdAY oF +5 MoNtH'; $expected = new DateTime('2014-06-27'); $date = new DateTime('2014-01-30'); $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify)); //Check without a + $modify = 'LaSt FrIdAY oF 2 MoNtH'; $expected = new DateTime('2014-03-28'); $date = new DateTime('2014-01-30'); $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify)); //Check wit a - $modify = 'third wednesday of -1 month'; $expected = new DateTime('2013-12-18'); $date = new DateTime('2014-01-30'); $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify)); }