protected function parse($date, $tz, $format) { $array = date_format_patterns(); foreach ($array as $key => $value) { $patterns[] = "`(^|[^\\\\\\\\])" . $key . "`"; // the letter with no preceding '\' $repl1[] = '${1}(.)'; // a single character $repl2[] = '${1}(' . $value . ')'; // the } $patterns[] = "`\\\\\\\\([" . implode(array_keys($array)) . "])`"; $repl1[] = '${1}'; $repl2[] = '${1}'; $format_regexp = preg_quote($format); // extract letters $regex1 = preg_replace($patterns, $repl1, $format_regexp, 1); $regex1 = str_replace('A', '(.)', $regex1); $regex1 = str_replace('a', '(.)', $regex1); preg_match('`^' . $regex1 . '$`', stripslashes($format), $letters); array_shift($letters); // extract values $regex2 = preg_replace($patterns, $repl2, $format_regexp, 1); $regex2 = str_replace('A', '(AM|PM)', $regex2); $regex2 = str_replace('a', '(am|pm)', $regex2); preg_match('`^' . $regex2 . '$`', $date, $values); array_shift($values); // if we did not find all the values for the patterns in the format, abort if (count($letters) != count($values)) { return FALSE; } $this->granularity = array(); $final_date = array('hour' => 0, 'minute' => 0, 'second' => 0, 'month' => 1, 'day' => 1, 'year' => 0); foreach ($letters as $i => $letter) { $value = $values[$i]; switch ($letter) { case 'd': case 'j': $final_date['day'] = intval($value); $this->addGranularity('day'); break; case 'n': case 'm': $final_date['month'] = intval($value); $this->addGranularity('month'); break; case 'F': $array_month_long = array_flip(date_month_names()); $final_date['month'] = $array_month_long[$value]; $this->addGranularity('month'); break; case 'M': $array_month = array_flip(date_month_names_abbr()); $final_date['month'] = $array_month[$value]; $this->addGranularity('month'); break; case 'Y': $final_date['year'] = $value; $this->addGranularity('year'); if (strlen($value) < 4) { $this->errors['year'] = t('The year is invalid. Please check that entry includes four digits.'); } break; case 'y': $year = $value; // if no century, we add the current one ("06" => "2006") $final_date['year'] = str_pad($year, 4, substr(date("Y"), 0, 2), STR_PAD_LEFT); $this->addGranularity('year'); break; case 'a': case 'A': $ampm = strtolower($value); break; case 'g': case 'h': case 'G': case 'H': $final_date['hour'] = intval($value); $this->addGranularity('hour'); break; case 'i': $final_date['minute'] = intval($value); $this->addGranularity('minute'); break; case 's': $final_date['second'] = intval($value); $this->addGranularity('second'); break; case 'U': parent::__construct($value, $tz ? $tz : new DateTimeZone("UTC")); $this->addGranularity('year'); $this->addGranularity('month'); $this->addGranularity('day'); $this->addGranularity('hour'); $this->addGranularity('minute'); $this->addGranularity('second'); return $this; break; } } if (isset($ampm) && $ampm == 'pm' && $final_date['hour'] < 12) { $final_date['hour'] += 12; } elseif (isset($ampm) && $ampm == 'am' && $final_date['hour'] == 12) { $final_date['hour'] -= 12; } // Blank becomes current time, given TZ. parent::__construct('', $tz ? $tz : new DateTimeZone("UTC")); if ($tz) { $this->addGranularity('timezone'); } // SetDate expects an integer value for the year, results can // be unexpected if we feed it something like '0100' or '0000'; $final_date['year'] = intval($final_date['year']); $this->errors += $this->arrayErrors($final_date); $granularity = drupal_map_assoc($this->granularity); // If the input value is '0000-00-00', PHP's date class will later incorrectly convert // it to something like '-0001-11-30' if we do setDate() here. If we don't do // setDate() here, it will default to the current date and we will lose any way to // tell that there was no date in the orignal input values. So set a flag we can use // later to tell that this date object was created using only time and that the date // values are artifical. if (empty($final_date['year']) && empty($final_date['month']) && empty($final_date['day'])) { $this->timeOnly = TRUE; } elseif (empty($this->errors)) { // setDate() expects a valid year, month, and day. // Set some defaults for dates that don't use this to // keep PHP from interpreting it as the last day of // the previous month or last month of the previous year. if (empty($granularity['month'])) { $final_date['month'] = 1; } if (empty($granularity['day'])) { $final_date['day'] = 1; } $this->setDate($final_date['year'], $final_date['month'], $final_date['day']); } if (!isset($final_date['hour']) && !isset($final_date['minute']) && !isset($final_date['second'])) { $this->dateOnly = TRUE; } elseif (empty($this->errors)) { $this->setTime($final_date['hour'], $final_date['minute'], $final_date['second']); } return $this; }
/** * Custom repeat rule theme function for dates. * * @see date_repeat_rrule_description(). */ function ringstedtheme_repeat_rrule_description($rrule, $format = 'd.M') { // Empty or invalid value. if (empty($rrule) || !strstr($rrule, 'RRULE')) { return; } module_load_include('inc', 'date_api', 'date_api_ical'); module_load_include('inc', 'date_repeat', 'date_repeat_calc'); $parts = date_repeat_split_rrule($rrule); $rrule = $parts[0]; if ($rrule['FREQ'] == 'NONE') { return; } // Make sure there will be an empty description for any unused parts. $description = array('!interval' => '', '!byday' => '', '!bymonth' => '', '!count' => '', '!until' => '', '!except' => '', '!additional' => '', '!week_starts_on' => ''); $interval = date_repeat_interval_options(); switch ($rrule['FREQ']) { case 'WEEKLY': if (isset($rrule['BYDAY'])) { $description['!interval'] = format_plural($rrule['INTERVAL'], '', 'every @count weeks') . ' '; } else { $description['!interval'] = format_plural($rrule['INTERVAL'], 'every week', 'every @count weeks') . ' '; } break; case 'MONTHLY': $description['!interval'] = format_plural($rrule['INTERVAL'], 'every month', 'every @count months') . ' '; break; case 'YEARLY': $description['!interval'] = format_plural($rrule['INTERVAL'], 'every year', 'every @count years') . ' '; break; default: $description['!interval'] = format_plural($rrule['INTERVAL'], 'every day', 'every @count days') . ' '; break; } if (!empty($rrule['BYDAY'])) { $days = date_repeat_dow_day_options(); $counts = date_repeat_dow_count_options(); $results = array(); $first_day = $rrule['BYDAY'][0]; foreach ($rrule['BYDAY'] as $byday) { // Get the numeric part of the BYDAY option, i.e. +3 from +3MO. $day = substr($byday, -2); $count = str_replace($day, '', $byday); if (!empty($count)) { // See if there is a 'pretty' option for this count, i.e. +1 => First. $order = array_key_exists($count, $counts) ? strtolower($counts[$count]) : $count; $results[] = trim(t('!repeats_every_interval on the !date_order !day_of_week', array('!repeats_every_interval ' => '', '!date_order' => $order, '!day_of_week' => strtolower($days[$day])))); } else { if ($first_day === $byday) { $results[] = trim(t('!repeats_every_interval every !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => strtolower($days[$day])))); } else { $results[] = trim(t('!repeats_every_interval !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => strtolower($days[$day])))); } } } $days_count = count($rrule['BYDAY']); if ($days_count > 2) { $last_day = array_pop($results); $description['!byday'] = implode(' , ', $results); $description['!byday'] .= ' ' . t('and') . ' ' . $last_day; } else { $description['!byday'] = implode(' ' . t('and') . ' ', $results); } } if (!empty($rrule['BYMONTH'])) { if (sizeof($rrule['BYMONTH']) < 12) { $results = array(); $months = date_month_names(); foreach ($rrule['BYMONTH'] as $month) { $results[] = $months[$month]; } if (!empty($rrule['BYMONTHDAY'])) { $description['!bymonth'] = trim(t('!repeats_every_interval on the !month_days of !month_names', array('!repeats_every_interval ' => '', '!month_days' => implode(', ', $rrule['BYMONTHDAY']), '!month_names' => implode(', ', $results)))); } else { $description['!bymonth'] = trim(t('!repeats_every_interval on !month_names', array('!repeats_every_interval ' => '', '!month_names' => implode(', ', $results)))); } } } if ($rrule['INTERVAL'] < 1) { $rrule['INTERVAL'] = 1; } if (!empty($rrule['COUNT'])) { $description['!count'] = trim(t('!repeats_every_interval !count times', array('!repeats_every_interval ' => '', '!count' => $rrule['COUNT']))); } if (!empty($rrule['UNTIL'])) { $until = date_ical_date($rrule['UNTIL'], 'UTC'); date_timezone_set($until, date_default_timezone_object()); $description['!until'] = trim(t('!repeats_every_interval until !until_date', array('!repeats_every_interval ' => '', '!until_date' => strtolower(date_format_date($until, 'custom', $format))))); } if (!empty($rrule['WKST'])) { $day_names = date_repeat_dow_day_options(); $description['!week_starts_on'] = trim(t('!repeats_every_interval where the week start on !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => $day_names[trim($rrule['WKST'])]))); } return preg_replace('/\\s*\\./', '.', t('Repeats !interval !bymonth !byday !count !until !except. !additional', $description)); }