updated date pathauto addressfield honeypot features modules

This commit is contained in:
Bachir Soussi Chiadmi
2015-10-12 12:03:12 +02:00
parent 0ba0c21bb9
commit eb699f528d
109 changed files with 5363 additions and 2372 deletions

View File

@@ -15,9 +15,11 @@
.container-inline-date > .form-item {
display: inline-block;
margin-right: 0.5em; /* LTR */
margin-bottom: 10px;
vertical-align: top;
}
fieldset.date-combo .container-inline-date > .form-item {
margin-bottom: 10px;
}
.container-inline-date .form-item .form-item {
float: left; /* LTR */
}
@@ -52,9 +54,11 @@
/* The exposed Views form doesn't need some of these styles */
.container-inline-date .date-padding {
padding: 10px;
float: left;
}
fieldset.date-combo .container-inline-date .date-padding {
padding: 10px;
}
.views-exposed-form .container-inline-date .date-padding {
padding: 0;
}
@@ -116,7 +120,7 @@ span.date-display-end {
}
/* Add space between the date and time portions of the date_select widget. */
.form-type-date-select .form-type-select[class$=hour] {
.form-type-date-select .form-type-select[class*=hour] {
margin-left: .75em; /* LTR */
}
@@ -173,6 +177,10 @@ div.date-calendar-day span.year {
padding: 2px;
}
.date-form-element-content-multiline {
padding: 10px;
border: 1px solid #CCC;
}
/* Admin styling */
.form-item.form-item-instance-widget-settings-input-format-custom,
.form-item.form-item-field-settings-enddate-required {

View File

@@ -10,112 +10,112 @@
*/
function _date_timezone_replacement($old) {
$replace = array(
'Brazil/Acre' => 'America/Rio_Branco',
'Brazil/DeNoronha' => 'America/Noronha',
'Brazil/East' => 'America/Recife',
'Brazil/West' => 'America/Manaus',
'Canada/Atlantic' => 'America/Halifax',
'Canada/Central' => 'America/Winnipeg',
'Canada/East-Saskatchewan' => 'America/Regina',
'Canada/Eastern' => 'America/Toronto',
'Canada/Mountain' => 'America/Edmonton',
'Canada/Newfoundland' => 'America/St_Johns',
'Canada/Pacific' => 'America/Vancouver',
'Canada/Saskatchewan' => 'America/Regina',
'Canada/Yukon' => 'America/Whitehorse',
'CET' => 'Europe/Berlin',
'Chile/Continental' => 'America/Santiago',
'Chile/EasterIsland' => 'Pacific/Easter',
'CST6CDT' => 'America/Chicago',
'Cuba' => 'America/Havana',
'EET' => 'Europe/Bucharest',
'Egypt' => 'Africa/Cairo',
'Eire' => 'Europe/Belfast',
'EST' => 'America/New_York',
'EST5EDT' => 'America/New_York',
'GB' => 'Europe/London',
'GB-Eire' => 'Europe/Belfast',
'Etc/GMT' => 'UTC',
'Etc/GMT+0' => 'UTC',
'Etc/GMT+1' => 'UTC',
'Etc/GMT+10' => 'UTC',
'Etc/GMT+11' => 'UTC',
'Etc/GMT+12' => 'UTC',
'Etc/GMT+2' => 'UTC',
'Etc/GMT+3' => 'UTC',
'Etc/GMT+4' => 'UTC',
'Etc/GMT+5' => 'UTC',
'Etc/GMT+6' => 'UTC',
'Etc/GMT+7' => 'UTC',
'Etc/GMT+8' => 'UTC',
'Etc/GMT+9' => 'UTC',
'Etc/GMT-0' => 'UTC',
'Etc/GMT-1' => 'UTC',
'Etc/GMT-10' => 'UTC',
'Etc/GMT-11' => 'UTC',
'Etc/GMT-12' => 'UTC',
'Etc/GMT-13' => 'UTC',
'Etc/GMT-14' => 'UTC',
'Etc/GMT-2' => 'UTC',
'Etc/GMT-3' => 'UTC',
'Etc/GMT-4' => 'UTC',
'Etc/GMT-5' => 'UTC',
'Etc/GMT-6' => 'UTC',
'Etc/GMT-7' => 'UTC',
'Etc/GMT-8' => 'UTC',
'Etc/GMT-9' => 'UTC',
'Etc/GMT0' => 'UTC',
'Etc/Greenwich' => 'UTC',
'Etc/UCT' => 'UTC',
'Etc/Universal' => 'UTC',
'Etc/UTC' => 'UTC',
'Etc/Zulu' => 'UTC',
'Factory' => 'UTC',
'GMT' => 'UTC',
'GMT+0' => 'UTC',
'GMT-0' => 'UTC',
'GMT0' => 'UTC',
'Hongkong' => 'Asia/Hong_Kong',
'HST' => 'Pacific/Honolulu',
'Iceland' => 'Atlantic/Reykjavik',
'Iran' => 'Asia/Tehran',
'Israel' => 'Asia/Tel_Aviv',
'Jamaica' => 'America/Jamaica',
'Japan' => 'Asia/Tokyo',
'Kwajalein' => 'Pacific/Kwajalein',
'Libya' => 'Africa/Tunis',
'MET' => 'Europe/Budapest',
'Mexico/BajaNorte' => 'America/Tijuana',
'Mexico/BajaSur' => 'America/Mazatlan',
'Mexico/General' => 'America/Mexico_City',
'MST' => 'America/Boise',
'MST7MDT' => 'America/Boise',
'Navajo' => 'America/Phoenix',
'NZ' => 'Pacific/Auckland',
'NZ-CHAT' => 'Pacific/Chatham',
'Poland' => 'Europe/Warsaw',
'Portugal' => 'Europe/Lisbon',
'PRC' => 'Asia/Chongqing',
'PST8PDT' => 'America/Los_Angeles',
'ROC' => 'Asia/Taipei',
'ROK' => 'Asia/Seoul',
'Singapore' => 'Asia/Singapore',
'Turkey' => 'Europe/Istanbul',
'US/Alaska' => 'America/Anchorage',
'US/Aleutian' => 'America/Adak',
'US/Arizona' => 'America/Phoenix',
'US/Central' => 'America/Chicago',
'US/East-Indiana' => 'America/Indianapolis',
'US/Eastern' => 'America/New_York',
'US/Hawaii' => 'Pacific/Honolulu',
'US/Indiana-Starke' => 'America/Indiana/Knox',
'US/Michigan' => 'America/Detroit',
'US/Mountain' => 'America/Boise',
'US/Pacific' => 'America/Los_Angeles',
'US/Pacific-New' => 'America/Los_Angeles',
'US/Samoa' => 'Pacific/Samoa',
'W-SU' => 'Europe/Moscow',
'WET' => 'Europe/Paris',
'Brazil/Acre' => 'America/Rio_Branco',
'Brazil/DeNoronha' => 'America/Noronha',
'Brazil/East' => 'America/Recife',
'Brazil/West' => 'America/Manaus',
'Canada/Atlantic' => 'America/Halifax',
'Canada/Central' => 'America/Winnipeg',
'Canada/East-Saskatchewan' => 'America/Regina',
'Canada/Eastern' => 'America/Toronto',
'Canada/Mountain' => 'America/Edmonton',
'Canada/Newfoundland' => 'America/St_Johns',
'Canada/Pacific' => 'America/Vancouver',
'Canada/Saskatchewan' => 'America/Regina',
'Canada/Yukon' => 'America/Whitehorse',
'CET' => 'Europe/Berlin',
'Chile/Continental' => 'America/Santiago',
'Chile/EasterIsland' => 'Pacific/Easter',
'CST6CDT' => 'America/Chicago',
'Cuba' => 'America/Havana',
'EET' => 'Europe/Bucharest',
'Egypt' => 'Africa/Cairo',
'Eire' => 'Europe/Belfast',
'EST' => 'America/New_York',
'EST5EDT' => 'America/New_York',
'GB' => 'Europe/London',
'GB-Eire' => 'Europe/Belfast',
'Etc/GMT' => 'UTC',
'Etc/GMT+0' => 'UTC',
'Etc/GMT+1' => 'UTC',
'Etc/GMT+10' => 'UTC',
'Etc/GMT+11' => 'UTC',
'Etc/GMT+12' => 'UTC',
'Etc/GMT+2' => 'UTC',
'Etc/GMT+3' => 'UTC',
'Etc/GMT+4' => 'UTC',
'Etc/GMT+5' => 'UTC',
'Etc/GMT+6' => 'UTC',
'Etc/GMT+7' => 'UTC',
'Etc/GMT+8' => 'UTC',
'Etc/GMT+9' => 'UTC',
'Etc/GMT-0' => 'UTC',
'Etc/GMT-1' => 'UTC',
'Etc/GMT-10' => 'UTC',
'Etc/GMT-11' => 'UTC',
'Etc/GMT-12' => 'UTC',
'Etc/GMT-13' => 'UTC',
'Etc/GMT-14' => 'UTC',
'Etc/GMT-2' => 'UTC',
'Etc/GMT-3' => 'UTC',
'Etc/GMT-4' => 'UTC',
'Etc/GMT-5' => 'UTC',
'Etc/GMT-6' => 'UTC',
'Etc/GMT-7' => 'UTC',
'Etc/GMT-8' => 'UTC',
'Etc/GMT-9' => 'UTC',
'Etc/GMT0' => 'UTC',
'Etc/Greenwich' => 'UTC',
'Etc/UCT' => 'UTC',
'Etc/Universal' => 'UTC',
'Etc/UTC' => 'UTC',
'Etc/Zulu' => 'UTC',
'Factory' => 'UTC',
'GMT' => 'UTC',
'GMT+0' => 'UTC',
'GMT-0' => 'UTC',
'GMT0' => 'UTC',
'Hongkong' => 'Asia/Hong_Kong',
'HST' => 'Pacific/Honolulu',
'Iceland' => 'Atlantic/Reykjavik',
'Iran' => 'Asia/Tehran',
'Israel' => 'Asia/Tel_Aviv',
'Jamaica' => 'America/Jamaica',
'Japan' => 'Asia/Tokyo',
'Kwajalein' => 'Pacific/Kwajalein',
'Libya' => 'Africa/Tunis',
'MET' => 'Europe/Budapest',
'Mexico/BajaNorte' => 'America/Tijuana',
'Mexico/BajaSur' => 'America/Mazatlan',
'Mexico/General' => 'America/Mexico_City',
'MST' => 'America/Boise',
'MST7MDT' => 'America/Boise',
'Navajo' => 'America/Phoenix',
'NZ' => 'Pacific/Auckland',
'NZ-CHAT' => 'Pacific/Chatham',
'Poland' => 'Europe/Warsaw',
'Portugal' => 'Europe/Lisbon',
'PRC' => 'Asia/Chongqing',
'PST8PDT' => 'America/Los_Angeles',
'ROC' => 'Asia/Taipei',
'ROK' => 'Asia/Seoul',
'Singapore' => 'Asia/Singapore',
'Turkey' => 'Europe/Istanbul',
'US/Alaska' => 'America/Anchorage',
'US/Aleutian' => 'America/Adak',
'US/Arizona' => 'America/Phoenix',
'US/Central' => 'America/Chicago',
'US/East-Indiana' => 'America/Indianapolis',
'US/Eastern' => 'America/New_York',
'US/Hawaii' => 'Pacific/Honolulu',
'US/Indiana-Starke' => 'America/Indiana/Knox',
'US/Michigan' => 'America/Detroit',
'US/Mountain' => 'America/Boise',
'US/Pacific' => 'America/Los_Angeles',
'US/Pacific-New' => 'America/Los_Angeles',
'US/Samoa' => 'Pacific/Samoa',
'W-SU' => 'Europe/Moscow',
'WET' => 'Europe/Paris',
);
if (array_key_exists($old, $replace)) {
return $replace[$old];

View File

@@ -9,9 +9,9 @@ stylesheets[all][] = date.css
files[] = date_api.module
files[] = date_api_sql.inc
; Information added by Drupal.org packaging script on 2014-07-29
version = "7.x-2.8"
; Information added by Drupal.org packaging script on 2015-09-08
version = "7.x-2.9"
core = "7.x"
project = "date"
datestamp = "1406653438"
datestamp = "1441727353"

View File

@@ -96,7 +96,7 @@ function date_api_uninstall() {
'date_php_min_year',
'date_db_tz_support',
'date_api_use_iso8601',
);
);
foreach ($variables as $variable) {
variable_del($variable);
}
@@ -118,8 +118,9 @@ function date_api_update_last_removed() {
}
/**
* Move old date format data to new date format tables, and delete the old
* tables. Insert only values that don't already exist in the new tables, in
* Move old date format to new date format tables,and delete the old tables.
*
* Insert only values that don't already exist in the new tables, in
* case new version of those custom values have already been created.
*/
function date_api_update_7000() {

View File

@@ -59,16 +59,16 @@ function date_help($path, $arg) {
}
if (module_exists('date_tools')) {
$output .= '<h3>Date Tools</h3>' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
$output .= '<h3>Date Tools</h3>' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field.', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
}
else {
$output .= '<h3>Date Tools</h3>' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field. ');
$output .= '<h3>Date Tools</h3>' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field.');
}
$output .= '<h2>More Information</h2><p>' . t('Complete documentation for the Date and Date API modules is available at <a href="@link">http://drupal.org/node/92460</a>.', array('@link' => 'http://drupal.org/node/262062')) . '</p>';
return $output;
break;
}
}
@@ -101,7 +101,7 @@ function date_api_status() {
$value = variable_get('date_format_medium');
if (isset($value)) {
$now = date_now();
$success_messages[] = $t('The medium date format type has been set to to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at <a href="@regional_date_time">Date and time</a> settings.', array('@value' => $now->format($value), '@regional_date_time' => url('admin/config/regional/date-time')));
$success_messages[] = $t('The medium date format type has been set to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at <a href="@regional_date_time">Date and time</a> settings.', array('@value' => $now->format($value), '@regional_date_time' => url('admin/config/regional/date-time')));
}
else {
$error_messages[] = $t('The Date API requires that you set up the <a href="@regional_date_time">system date formats</a> to function correctly.', array('@regional_date_time' => url('admin/config/regional/date-time')));
@@ -143,7 +143,15 @@ function date_api_menu() {
class DateObject extends DateTime {
public $granularity = array();
public $errors = array();
protected static $allgranularity = array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone');
protected static $allgranularity = array(
'year',
'month',
'day',
'hour',
'minute',
'second',
'timezone'
);
private $serializedTime;
private $serializedTimezone;
@@ -402,7 +410,7 @@ class DateObject extends DateTime {
* A single date part.
*/
public function removeGranularity($g) {
if ($key = array_search($g, $this->granularity)) {
if (($key = array_search($g, $this->granularity)) !== FALSE) {
unset($this->granularity[$key]);
}
}
@@ -458,23 +466,35 @@ class DateObject extends DateTime {
$true = $this->hasGranularity() && (!$granularity || $flexible || $this->hasGranularity($granularity));
if (!$true && $granularity) {
foreach ((array) $granularity as $part) {
if (!$this->hasGranularity($part) && in_array($part, array('second', 'minute', 'hour', 'day', 'month', 'year'))) {
if (!$this->hasGranularity($part) && in_array($part, array(
'second',
'minute',
'hour',
'day',
'month',
'year')
)) {
switch ($part) {
case 'second':
$this->errors[$part] = t('The second is missing.');
break;
case 'minute':
$this->errors[$part] = t('The minute is missing.');
break;
case 'hour':
$this->errors[$part] = t('The hour is missing.');
break;
case 'day':
$this->errors[$part] = t('The day is missing.');
break;
case 'month':
$this->errors[$part] = t('The month is missing.');
break;
case 'year':
$this->errors[$part] = t('The year is missing.');
break;
@@ -537,7 +557,14 @@ class DateObject extends DateTime {
$temp = date_parse($time);
// Special case for 'now'.
if ($time == 'now') {
$this->granularity = array('year', 'month', 'day', 'hour', 'minute', 'second');
$this->granularity = array(
'year',
'month',
'day',
'hour',
'minute',
'second',
);
}
else {
// This PHP date_parse() method currently doesn't have resolution down to
@@ -600,7 +627,14 @@ class DateObject extends DateTime {
return FALSE;
}
$this->granularity = array();
$final_date = array('hour' => 0, 'minute' => 0, 'second' => 0, 'month' => 1, 'day' => 1, 'year' => 0);
$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) {
@@ -609,21 +643,25 @@ class DateObject extends DateTime {
$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_key_exists($value, $array_month_long) ? $array_month_long[$value] : -1;
$this->addGranularity('month');
break;
case 'M':
$array_month = array_flip(date_month_names_abbr());
$final_date['month'] = array_key_exists($value, $array_month) ? $array_month[$value] : -1;
$this->addGranularity('month');
break;
case 'Y':
$final_date['year'] = $value;
$this->addGranularity('year');
@@ -631,16 +669,19 @@ class DateObject extends DateTime {
$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':
@@ -648,14 +689,17 @@ class DateObject extends DateTime {
$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');
@@ -665,7 +709,7 @@ class DateObject extends DateTime {
$this->addGranularity('minute');
$this->addGranularity('second');
return $this;
break;
}
}
if (isset($ampm) && $ampm == 'pm' && $final_date['hour'] < 12) {
@@ -758,10 +802,24 @@ class DateObject extends DateTime {
// date or we will get date slippage, i.e. a value of 2011-00-00 will get
// interpreted as November of 2010 by PHP.
if ($full) {
$arr += array('year' => 0, 'month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0);
$arr += array(
'year' => 0,
'month' => 1,
'day' => 1,
'hour' => 0,
'minute' => 0,
'second' => 0,
);
}
else {
$arr += array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
$arr += array(
'year' => '',
'month' => '',
'day' => '',
'hour' => '',
'minute' => '',
'second' => '',
);
}
$datetime = '';
if ($arr['year'] !== '') {
@@ -839,28 +897,27 @@ class DateObject extends DateTime {
case 'year':
$fallback = $now->format('Y');
return !is_int($value) || empty($value) || $value < variable_get('date_min_year', 1) || $value > variable_get('date_max_year', 4000) ? $fallback : $value;
break;
case 'month':
$fallback = $default == 'first' ? 1 : $now->format('n');
return !is_int($value) || empty($value) || $value <= 0 || $value > 12 ? $fallback : $value;
break;
case 'day':
$fallback = $default == 'first' ? 1 : $now->format('j');
$max_day = isset($year) && isset($month) ? date_days_in_month($year, $month) : 31;
return !is_int($value) || empty($value) || $value <= 0 || $value > $max_day ? $fallback : $value;
break;
case 'hour':
$fallback = $default == 'first' ? 0 : $now->format('G');
return !is_int($value) || $value < 0 || $value > 23 ? $fallback : $value;
break;
case 'minute':
$fallback = $default == 'first' ? 0 : $now->format('i');
return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
break;
case 'second':
$fallback = $default == 'first' ? 0 : $now->format('s');
return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
break;
}
}
@@ -898,18 +955,23 @@ class DateObject extends DateTime {
case 'year':
$errors['year'] = t('The year is invalid.');
break;
case 'month':
$errors['month'] = t('The month is invalid.');
break;
case 'day':
$errors['day'] = t('The day is invalid.');
break;
case 'hour':
$errors['hour'] = t('The hour is invalid.');
break;
case 'minute':
$errors['minute'] = t('The minute is invalid.');
break;
case 'second':
$errors['second'] = t('The second is invalid.');
break;
@@ -929,7 +991,7 @@ class DateObject extends DateTime {
* The stop date.
* @param string $measure
* (optional) A granularity date part. Defaults to 'seconds'.
* @param boolean $absolute
* @param bool $absolute
* (optional) Indicate whether the absolute value of the difference should
* be returned or if the sign should be retained. Defaults to TRUE.
*/
@@ -955,10 +1017,13 @@ class DateObject extends DateTime {
// The easy cases first.
case 'seconds':
return $diff;
case 'minutes':
return $diff / 60;
case 'hours':
return $diff / 3600;
case 'years':
return $year_diff;
@@ -1013,7 +1078,7 @@ class DateObject extends DateTime {
$sign = ($year_diff < 0) ? -1 : 1;
for ($i = 1; $i <= abs($year_diff); $i++) {
date_modify($date1, (($sign > 0) ? '+': '-').'1 year');
date_modify($date1, (($sign > 0) ? '+' : '-') . '1 year');
$week_diff += (date_iso_weeks_in_year($date1) * $sign);
}
return $week_diff;
@@ -1060,10 +1125,13 @@ function date_type_format($type) {
switch ($type) {
case DATE_ISO:
return DATE_FORMAT_ISO;
case DATE_UNIX:
return DATE_FORMAT_UNIX;
case DATE_DATETIME:
return DATE_FORMAT_DATETIME;
case DATE_ICAL:
return DATE_FORMAT_ICAL;
}
@@ -1119,7 +1187,7 @@ function date_month_names($required = FALSE) {
}
/**
* Constructs a translated array of month name abbreviations
* Constructs a translated array of month name abbreviations.
*
* @param bool $required
* (optional) If FALSE, the returned array will include a blank value.
@@ -1211,9 +1279,11 @@ function date_week_days_abbr($required = FALSE, $refresh = TRUE, $length = 3) {
case 1:
$context = 'day_abbr1';
break;
case 2:
$context = 'day_abbr2';
break;
default:
$context = '';
break;
@@ -1248,10 +1318,10 @@ function date_week_days_ordered($weekdays) {
/**
* Constructs an array of years.
*
* @param int $min
* The minimum year in the array.
* @param int $max
* The maximum year in the array.
* @param int $start
* The start year in the array.
* @param int $end
* The end year in the array.
* @param bool $required
* (optional) If FALSE, the returned array will include a blank value.
* Defaults to FALSE.
@@ -1259,16 +1329,16 @@ function date_week_days_ordered($weekdays) {
* @return array
* An array of years in the selected range.
*/
function date_years($min = 0, $max = 0, $required = FALSE) {
function date_years($start = 0, $end = 0, $required = FALSE) {
// Ensure $min and $max are valid values.
if (empty($min)) {
$min = intval(date('Y', REQUEST_TIME) - 3);
if (empty($start)) {
$start = intval(date('Y', REQUEST_TIME) - 3);
}
if (empty($max)) {
$max = intval(date('Y', REQUEST_TIME) + 3);
if (empty($end)) {
$end = intval(date('Y', REQUEST_TIME) + 3);
}
$none = array(0 => '');
return !$required ? $none + drupal_map_assoc(range($min, $max)) : drupal_map_assoc(range($min, $max));
return !$required ? $none + drupal_map_assoc(range($start, $end)) : drupal_map_assoc(range($start, $end));
}
/**
@@ -1474,7 +1544,14 @@ function date_granularity_names() {
* An array of date parts.
*/
function date_granularity_sorted($granularity) {
return array_intersect(array('year', 'month', 'day', 'hour', 'minute', 'second'), $granularity);
return array_intersect(array(
'year',
'month',
'day',
'hour',
'minute',
'second',
), $granularity);
}
/**
@@ -1492,14 +1569,19 @@ function date_granularity_array_from_precision($precision) {
switch ($precision) {
case 'year':
return array_slice($granularity_array, -6, 1);
case 'month':
return array_slice($granularity_array, -6, 2);
case 'day':
return array_slice($granularity_array, -6, 3);
case 'hour':
return array_slice($granularity_array, -6, 4);
case 'minute':
return array_slice($granularity_array, -6, 5);
default:
return $granularity_array;
}
@@ -1533,14 +1615,19 @@ function date_granularity_format($granularity) {
switch ($granularity) {
case 'year':
return substr($format, 0, 1);
case 'month':
return substr($format, 0, 3);
case 'day':
return substr($format, 0, 5);
case 'hour';
return substr($format, 0, 7);
case 'minute':
return substr($format, 0, 9);
default:
return $format;
}
@@ -1657,40 +1744,51 @@ function date_format_date($date, $type = 'medium', $format = '', $langcode = NUL
case 'l':
$datestring .= t($date->format('l'), array(), array('context' => '', 'langcode' => $langcode));
break;
case 'D':
$datestring .= t($date->format('D'), array(), array('context' => '', 'langcode' => $langcode));
break;
case 'F':
$datestring .= t($date->format('F'), array(), array('context' => 'Long month name', 'langcode' => $langcode));
break;
case 'M':
$datestring .= t($date->format('M'), array(), array('langcode' => $langcode));
break;
case 'A':
case 'a':
$datestring .= t($date->format($c), array(), array('context' => 'ampm', 'langcode' => $langcode));
break;
// The timezone name translations can use t().
case 'e':
case 'T':
$datestring .= t($date->format($c));
break;
// Remaining date parts need no translation.
case 'O':
$datestring .= sprintf('%s%02d%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
break;
case 'P':
$datestring .= sprintf('%s%02d:%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
break;
case 'Z':
$datestring .= date_offset_get($date);
break;
case '\\':
$datestring .= $format[++$i];
break;
case 'r':
$datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', $langcode);
$datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', 'en');
break;
default:
if (strpos('BdcgGhHiIjLmnNosStTuUwWYyz', $c) !== FALSE) {
$datestring .= $date->format($c);
@@ -1739,8 +1837,8 @@ function date_format_interval($date, $granularity = 2, $display_ago = TRUE) {
* (optional) Optionally force time to a specific timezone, defaults to user
* timezone, if set, otherwise site timezone. Defaults to NULL.
*
* @param boolean $reset [optional]
* Static cache reset
* @param bool $reset
* (optional) Static cache reset.
*
* @return object
* The current time as a date object.
@@ -1831,7 +1929,7 @@ function date_days_in_month($year, $month) {
* @param mixed $date
* (optional) The current date object, or a date string. Defaults to NULL.
*
* @return integer
* @return int
* The number of days in the year.
*/
function date_days_in_year($date = NULL) {
@@ -1860,7 +1958,7 @@ function date_days_in_year($date = NULL) {
* @param mixed $date
* (optional) The current date object, or a date string. Defaults to NULL.
*
* @return integer
* @return int
* The number of ISO weeks in a year.
*/
function date_iso_weeks_in_year($date = NULL) {
@@ -1952,7 +2050,7 @@ function date_week_range($week, $year) {
// Move forwards to the last day of the week.
$max_date = clone($min_date);
date_modify($max_date, '+7 days');
date_modify($max_date, '+6 days');
if (date_format($min_date, 'Y') != $year) {
$min_date = new DateObject($year . '-01-01 00:00:00');
@@ -1986,7 +2084,7 @@ function date_iso_week_range($week, $year) {
// Move forwards to the last day of the week.
$max_date = clone($min_date);
date_modify($max_date, '+7 days');
date_modify($max_date, '+6 days');
return array($min_date, $max_date);
}
@@ -2094,7 +2192,8 @@ function date_has_time($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
return (bool) count(array_intersect($granularity, array('hour', 'minute', 'second')));
$options = array('hour', 'minute', 'second');
return (bool) count(array_intersect($granularity, $options));
}
/**
@@ -2110,7 +2209,8 @@ function date_has_date($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
return (bool) count(array_intersect($granularity, array('year', 'month', 'day')));
$options = array('year', 'month', 'day');
return (bool) count(array_intersect($granularity, $options));
}
/**
@@ -2128,8 +2228,10 @@ function date_part_format($part, $format) {
switch ($part) {
case 'date':
return date_limit_format($format, array('year', 'month', 'day'));
case 'time':
return date_limit_format($format, array('hour', 'minute', 'second'));
default:
return date_limit_format($format, array($part));
}
@@ -2157,7 +2259,7 @@ function date_limit_format($format, $granularity) {
$drupal_static_fast['formats'] = &drupal_static(__FUNCTION__);
}
$formats = &$drupal_static_fast['formats'];
$format_granularity_cid = $format .'|'. implode(',', $granularity);
$format_granularity_cid = $format . '|' . implode(',', $granularity);
if (isset($formats[$format_granularity_cid])) {
return $formats[$format_granularity_cid];
}
@@ -2191,21 +2293,27 @@ function date_limit_format($format, $granularity) {
case 'year':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[Yy])';
break;
case 'day':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[l|D|d|dS|j|jS|N|w|W|z]{1,2})';
break;
case 'month':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[FMmn])';
break;
case 'hour':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[HhGg])';
break;
case 'minute':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[i])';
break;
case 'second':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[s])';
break;
case 'timezone':
$regex[] = '([\-/\.,:]?\s?(?<!\\\\)[TOZPe])';
break;
@@ -2278,25 +2386,30 @@ function date_format_order($format) {
case 'j':
$order[] = 'day';
break;
case 'F':
case 'M':
case 'm':
case 'n':
$order[] = 'month';
break;
case 'Y':
case 'y':
$order[] = 'year';
break;
case 'g':
case 'G':
case 'h':
case 'H':
$order[] = 'hour';
break;
case 'i':
$order[] = 'minute';
break;
case 's':
$order[] = 'second';
break;
@@ -2315,7 +2428,16 @@ function date_format_order($format) {
* A reduced set of granularitiy elements.
*/
function date_nongranularity($granularity) {
return array_diff(array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone'), (array) $granularity);
$options = array(
'year',
'month',
'day',
'hour',
'minute',
'second',
'timezone',
);
return array_diff($options, (array) $granularity);
}
/**
@@ -2335,7 +2457,11 @@ function date_api_theme($existing, $type, $theme, $path) {
'path' => "$path/theme",
);
return array(
'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
'date_nav_title' => $base + array(
'variables' => array(
'granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL
),
),
'date_timezone' => $base + array('render element' => 'element'),
'date_select' => $base + array('render element' => 'element'),
'date_text' => $base + array('render element' => 'element'),
@@ -2355,7 +2481,11 @@ function date_api_theme($existing, $type, $theme, $path) {
'date_part_label_time' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
'date_time_ago' => $base + array('variables' => array('start_date' => NULL, 'end_date' => NULL, 'interval' => NULL)),
'date_time_ago' => $base + array(
'variables' => array(
'start_date' => NULL, 'end_date' => NULL, 'interval' => NULL
),
),
);
}
@@ -2375,9 +2505,11 @@ function date_get_timezone($handling, $timezone = '') {
case 'date':
$timezone = !empty($timezone) ? $timezone : date_default_timezone();
break;
case 'utc':
$timezone = 'UTC';
break;
default:
$timezone = date_default_timezone();
}
@@ -2404,6 +2536,7 @@ function date_get_timezone_db($handling, $timezone = NULL) {
// These handling modes all convert to UTC before storing in the DB.
$timezone = 'UTC';
break;
case ('date'):
if ($timezone == NULL) {
// This shouldn't happen, since it's meaning is undefined. But we need
@@ -2411,6 +2544,7 @@ function date_get_timezone_db($handling, $timezone = NULL) {
$timezone = date_default_timezone();
}
break;
case ('none'):
default:
$timezone = date_default_timezone();
@@ -2465,12 +2599,12 @@ function date_order() {
* TRUE if the date range is valid, FALSE otherwise.
*/
function date_range_valid($string) {
$matches = preg_match('@^(\-[0-9]+|[0-9]{4}):([\+|\-][0-9]+|[0-9]{4})$@', $string);
$matches = preg_match('@^([\+\-][0-9]+|[0-9]{4}):([\+\-][0-9]+|[0-9]{4})$@', $string);
return $matches < 1 ? FALSE : TRUE;
}
/**
* Splits a string like -3:+3 or 2001:2010 into an array of min and max years.
* Splits a string like -3:+3 or 2001:2010 into an array of start and end years.
*
* Center the range around the current year, if any, but expand it far
* enough so it will pick up the year value in the field in case
@@ -2482,45 +2616,44 @@ function date_range_valid($string) {
* (optional) A date object. Defaults to NULL.
*
* @return array
* A numerically indexed array, containing a minimum and maximum year.
* A numerically indexed array, containing a start and end year.
*/
function date_range_years($string, $date = NULL) {
$this_year = date_format(date_now(), 'Y');
list($min_year, $max_year) = explode(':', $string);
list($start_year, $end_year) = explode(':', $string);
// Valid patterns would be -5:+5, 0:+1, 2008:2010.
$plus_pattern = '@[\+|\-][0-9]{1,4}@';
$plus_pattern = '@[\+\-][0-9]{1,4}@';
$year_pattern = '@^[0-9]{4}@';
if (!preg_match($year_pattern, $min_year, $matches)) {
if (preg_match($plus_pattern, $min_year, $matches)) {
$min_year = $this_year + $matches[0];
if (!preg_match($year_pattern, $start_year, $matches)) {
if (preg_match($plus_pattern, $start_year, $matches)) {
$start_year = $this_year + $matches[0];
}
else {
$min_year = $this_year;
$start_year = $this_year;
}
}
if (!preg_match($year_pattern, $max_year, $matches)) {
if (preg_match($plus_pattern, $max_year, $matches)) {
$max_year = $this_year + $matches[0];
if (!preg_match($year_pattern, $end_year, $matches)) {
if (preg_match($plus_pattern, $end_year, $matches)) {
$end_year = $this_year + $matches[0];
}
else {
$max_year = $this_year;
$end_year = $this_year;
}
}
// We expect the $min year to be less than the $max year.
// Some custom values for -99:+99 might not obey that.
if ($min_year > $max_year) {
$temp = $max_year;
$max_year = $min_year;
$min_year = $temp;
}
// If there is a current value, stretch the range to include it.
$value_year = is_object($date) ? $date->format('Y') : '';
if (!empty($value_year)) {
$min_year = min($value_year, $min_year);
$max_year = max($value_year, $max_year);
if ($start_year <= $end_year) {
$start_year = min($value_year, $start_year);
$end_year = max($value_year, $end_year);
}
else {
$start_year = max($value_year, $start_year);
$end_year = min($value_year, $end_year);
}
}
return array($min_year, $max_year);
return array($start_year, $end_year);
}
/**
@@ -2680,6 +2813,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23 && in_array($min2, array($max_minutes, 59)) && in_array($sec2, array($max_seconds, 59)))
|| ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0 && $sec1 == 0 && $sec2 == 0);
break;
case 'minute':
$min_match = $time1 == '00:00:00'
|| ($hour1 == 0 && $min1 == 0);
@@ -2687,6 +2821,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23 && in_array($min2, array($max_minutes, 59)))
|| ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0);
break;
case 'hour':
$min_match = $time1 == '00:00:00'
|| ($hour1 == 0);
@@ -2694,6 +2829,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23)
|| ($hour1 == 0 && $hour2 == 0);
break;
default:
$min_match = TRUE;
$max_match = FALSE;
@@ -2754,15 +2890,21 @@ function date_is_date($date) {
}
/**
* This function will replace ISO values that have the pattern 9999-00-00T00:00:00
* with a pattern like 9999-01-01T00:00:00, to match the behavior of non-ISO
* dates and ensure that date objects created from this value contain a valid month
* and day. Without this fix, the ISO date '2020-00-00T00:00:00' would be created as
* Replace specific ISO values using patterns.
*
* Function will replace ISO values that have the pattern 9999-00-00T00:00:00
* with a pattern like 9999-01-01T00:00:00, to match the behavior of non-ISO dates
* and ensure that date objects created from this value contain a valid month
* and day.
* Without this fix, the ISO date '2020-00-00T00:00:00' would be created as
* November 30, 2019 (the previous day in the previous month).
*
* @param string $iso_string
* An ISO string that needs to be made into a complete, valid date.
*
* @return mixed|string
* replaced value, or incoming value.
*
* @TODO Expand on this to work with all sorts of partial ISO dates.
*/
function date_make_iso_valid($iso_string) {

View File

@@ -116,15 +116,19 @@ function date_default_date($element) {
case 16:
$format = 'Y-m-d H:i';
break;
case 13:
$format = 'Y-m-d H';
break;
case 10:
$format = 'Y-m-d';
break;
case 7:
$format = 'Y-m';
break;
case 4:
$format = 'Y';
break;
@@ -170,7 +174,7 @@ function date_year_range_element_process($element, &$form_state, $form) {
$element['#attached']['js'][] = drupal_get_path('module', 'date_api') . '/date_year_range.js';
$context = array(
'form' => $form,
'form' => $form,
);
drupal_alter('date_year_range_process', $element, $form_state, $context);
@@ -256,7 +260,7 @@ function date_timezone_element_process($element, &$form_state, $form) {
}
$context = array(
'form' => $form,
'form' => $form,
);
drupal_alter('date_timezone_process', $element, $form_state, $context);
@@ -264,7 +268,7 @@ function date_timezone_element_process($element, &$form_state, $form) {
}
/**
* Validation for timezone input
* Validation for timezone input.
*
* Move the timezone value from the nested field back to the original field.
*/
@@ -307,7 +311,6 @@ function date_text_element_value_callback($element, $input = FALSE, &$form_state
*
* The exact parts displayed in the field are those in #date_granularity.
* The display of each part comes from #date_format.
*
*/
function date_text_element_process($element, &$form_state, $form) {
if (date_hidden_element($element)) {
@@ -323,9 +326,18 @@ function date_text_element_process($element, &$form_state, $form) {
$now = date_example_date();
$element['date']['#title'] = t('Date');
$element['date']['#title_display'] = 'invisible';
$element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_format_date(date_example_date(), 'custom', $element['#date_format'])));
$element['date']['#description'] = ' ' . t('Format: @date', array(
'@date' => date_format_date(date_example_date(), 'custom', $element['#date_format']
)));
$element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
// Make changes if instance is set to be rendered as a regular field.
if (!empty($element['#instance']['widget']['settings']['no_fieldset']) && $element['#field']['cardinality'] == 1) {
$element['date']['#title'] = check_plain($element['#instance']['label']);
$element['date']['#title_display'] = $element['#title_display'];
$element['date']['#required'] = $element['#required'];
}
// Keep the system from creating an error message for the sub-element.
// We'll set our own message on the parent element.
// $element['date']['#required'] = $element['#required'];
@@ -341,7 +353,7 @@ function date_text_element_process($element, &$form_state, $form) {
}
$context = array(
'form' => $form,
'form' => $form,
);
drupal_alter('date_text_process', $element, $form_state, $context);
@@ -349,12 +361,11 @@ function date_text_element_process($element, &$form_state, $form) {
}
/**
* Validation for text input.
* Validation for text input.
*
* When used as a Views widget, the validation step always gets triggered,
* even with no form submission. Before form submission $element['#value']
* contains a string, after submission it contains an array.
*
*/
function date_text_validate($element, &$form_state) {
if (date_hidden_element($element)) {
@@ -367,6 +378,11 @@ function date_text_validate($element, &$form_state) {
$input_exists = NULL;
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
// Trim extra spacing off user input of text fields.
if (isset($input['date'])) {
$input['date'] = trim($input['date']);
}
drupal_alter('date_text_pre_validate', $element, $form_state, $input);
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
@@ -421,7 +437,14 @@ function date_text_input_date($element, $input) {
* Element value callback for date_select element.
*/
function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
$return = array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
$return = array(
'year' => '',
'month' => '',
'day' => '',
'hour' => '',
'minute' => '',
'second' => '',
);
$date = NULL;
if ($input !== FALSE) {
$return = $input;
@@ -431,7 +454,14 @@ function date_select_element_value_callback($element, $input = FALSE, &$form_sta
$date = date_default_date($element);
}
$granularity = date_format_order($element['#date_format']);
$formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
$formats = array(
'year' => 'Y',
'month' => 'n',
'day' => 'j',
'hour' => 'H',
'minute' => 'i',
'second' => 's',
);
foreach ($granularity as $field) {
if ($field != 'timezone') {
$return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
@@ -449,7 +479,6 @@ function date_select_element_value_callback($element, $input = FALSE, &$form_sta
*
* The exact parts displayed in the field are those in #date_granularity.
* The display of each part comes from ['#date_settings']['format'].
*
*/
function date_select_element_process($element, &$form_state, $form) {
if (date_hidden_element($element)) {
@@ -473,7 +502,14 @@ function date_select_element_process($element, &$form_state, $form) {
// Store a hidden value for all date parts not in the current display.
$granularity = date_format_order($element['#date_format']);
$formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
$formats = array(
'year' => 'Y',
'month' => 'n',
'day' => 'j',
'hour' => 'H',
'minute' => 'i',
'second' => 's',
);
foreach (date_nongranularity($granularity) as $field) {
if ($field != 'timezone') {
$element[$field] = array(
@@ -490,7 +526,7 @@ function date_select_element_process($element, &$form_state, $form) {
}
$context = array(
'form' => $form,
'form' => $form,
);
drupal_alter('date_select_process', $element, $form_state, $context);
@@ -521,7 +557,7 @@ function date_parts_element($element, $date, $format) {
$sub_element = array('#granularity' => $granularity);
$order = array_flip($granularity);
$hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
$hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g' : 'G';
$month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
$count = 0;
$increment = min(intval($element['#date_increment']), 1);
@@ -539,26 +575,29 @@ function date_parts_element($element, $date, $format) {
switch ($field) {
case 'year':
$range = date_range_years($element['#date_year_range'], $date);
$min_year = $range[0];
$max_year = $range[1];
$start_year = $range[0];
$end_year = $range[1];
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('Y') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
$sub_element[$field]['#options'] = drupal_map_assoc(date_years($start_year, $end_year, $part_required));
}
break;
case 'month':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('n') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = $month_function($part_required);
}
break;
case 'day':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('j') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
}
break;
case 'hour':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format($hours_format) : '';
if ($part_type == 'select') {
@@ -566,6 +605,7 @@ function date_parts_element($element, $date, $format) {
}
$sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
break;
case 'minute':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('i') : '';
if ($part_type == 'select') {
@@ -573,6 +613,7 @@ function date_parts_element($element, $date, $format) {
}
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
break;
case 'second':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('s') : '';
if ($part_type == 'select') {

View File

@@ -181,6 +181,7 @@ function date_ical_parse($icaldatafolded = array()) {
$parent[array_pop($parents)][] = array_pop($subgroups);
}
break;
// Add the timezones in with their index their TZID.
case 'VTIMEZONE':
$subgroup = end($subgroups);
@@ -196,6 +197,7 @@ function date_ical_parse($icaldatafolded = array()) {
array_pop($subgroups);
array_pop($parents);
break;
// Do some fun stuff with durations and all_day events and then append
// to parent.
case 'VEVENT':
@@ -222,9 +224,9 @@ function date_ical_parse($icaldatafolded = array()) {
// assumes the end date is inclusive.
if (!empty($subgroup['DTEND']) && (!empty($subgroup['DTEND']['all_day']))) {
// Make the end date one day earlier.
$date = new DateObject ($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
$date = new DateObject($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
date_modify($date, '-1 day');
$subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
$subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
}
// If a start datetime is defined AND there is no definition for
// the end datetime THEN make the end datetime equal the start
@@ -239,7 +241,7 @@ function date_ical_parse($icaldatafolded = array()) {
if (!empty($subgroup['DTSTART']['all_day'])) {
$subgroup['all_day'] = TRUE;
}
// Add this element to the parent as an array under the
// Add this element to the parent as an array under the.
prev($subgroups);
$parent = &$subgroups[key($subgroups)];
@@ -264,12 +266,13 @@ function date_ical_parse($icaldatafolded = array()) {
$field = !empty($matches[2]) ? $matches[2] : '';
$data = !empty($matches[3]) ? $matches[3] : '';
$parse_result = '';
switch ($name) {
// Keep blank lines out of the results.
case '':
break;
// Lots of properties have date values that must be parsed out.
// Lots of properties have date values that must be parsed out.
case 'CREATED':
case 'LAST-MODIFIED':
case 'DTSTART':
@@ -317,9 +320,9 @@ function date_ical_parse($icaldatafolded = array()) {
$parse_result = date_ical_parse_location($field, $data);
break;
// For all other properties, just store the property and the value.
// This can be expanded on in the future if other properties should
// be given special treatment.
// For all other properties, just store the property and the value.
// This can be expanded on in the future if other properties should
// be given special treatment.
default:
$parse_result = $data;
break;
@@ -360,7 +363,7 @@ function date_ical_parse($icaldatafolded = array()) {
* has no timezone; the ical specs say no timezone
* conversion should be done if no timezone info is
* supplied
* @todo
* @todo
* Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
* period may include a duration, or a date and a duration, or two dates, so
* would have to be split into parts and run through date_ical_parse_date()
@@ -401,6 +404,7 @@ function date_ical_parse_date($field, $data) {
// Date.
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
break;
case 'DATE-TIME':
preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
// Date.
@@ -519,12 +523,12 @@ function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
$data = $items['DATA'];
preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
$items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
$items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
$items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
$items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
$items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
$items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
$items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
$items['month'] = isset($duration[2]) ? str_replace('M', '', $duration[2]) : '';
$items['week'] = isset($duration[3]) ? str_replace('W', '', $duration[3]) : '';
$items['day'] = isset($duration[4]) ? str_replace('D', '', $duration[4]) : '';
$items['hour'] = isset($duration[6]) ? str_replace('H', '', $duration[6]) : '';
$items['minute'] = isset($duration[7]) ? str_replace('M', '', $duration[7]) : '';
$items['second'] = isset($duration[8]) ? str_replace('S', '', $duration[8]) : '';
$start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
$timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone');
if (empty($timezone)) {
@@ -542,7 +546,7 @@ function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
'tz' => $timezone,
);
);
$duration = date_format($date2, 'U') - date_format($date, 'U');
$subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
}
@@ -631,7 +635,6 @@ function date_ical_date($ical_date, $to_tz = FALSE) {
*
* @return string
* Escaped text
*
*/
function date_ical_escape_text($text) {
$text = drupal_html_to_text($text);
@@ -693,14 +696,14 @@ function date_ical_escape_text($text) {
* )
*/
function date_api_ical_build_rrule($form_values) {
$RRULE = '';
$rrule = '';
if (empty($form_values) || !is_array($form_values)) {
return $RRULE;
return $rrule;
}
// Grab the RRULE data and put them into iCal RRULE format.
$RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
$RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
$rrule .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
$rrule .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
// Unset the empty 'All' values.
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
@@ -713,14 +716,14 @@ function date_api_ical_build_rrule($form_values) {
unset($form_values['BYMONTHDAY']['']);
}
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
$RRULE .= ';BYDAY=' . $BYDAY;
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $byday = implode(",", $form_values['BYDAY'])) {
$rrule .= ';BYDAY=' . $byday;
}
if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
$RRULE .= ';BYMONTH=' . $BYMONTH;
if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $bymonth = implode(",", $form_values['BYMONTH'])) {
$rrule .= ';BYMONTH=' . $bymonth;
}
if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
$RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $bymonthday = implode(",", $form_values['BYMONTHDAY'])) {
$rrule .= ';BYMONTHDAY=' . $bymonthday;
}
// The UNTIL date is supposed to always be expressed in UTC.
// The input date values may already have been converted to a date object on a
@@ -731,8 +734,17 @@ function date_api_ical_build_rrule($form_values) {
if (!is_object($form_values['UNTIL']['datetime'])) {
// If this is a date without time, give it time.
if (strlen($form_values['UNTIL']['datetime']) < 11) {
$granularity_options = drupal_map_assoc(array(
'year',
'month',
'day',
'hour',
'minute',
'second',
));
$form_values['UNTIL']['datetime'] .= ' 23:59:59';
$form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
$form_values['UNTIL']['granularity'] = serialize($granularity_options);
$form_values['UNTIL']['all_day'] = FALSE;
}
$until = date_ical_date($form_values['UNTIL'], 'UTC');
@@ -740,21 +752,21 @@ function date_api_ical_build_rrule($form_values) {
else {
$until = $form_values['UNTIL']['datetime'];
}
$RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
$rrule .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
}
// Our form doesn't allow a value for COUNT, but it may be needed by
// modules using the API, so add it to the rule.
if (array_key_exists('COUNT', $form_values)) {
$RRULE .= ';COUNT=' . $form_values['COUNT'];
$rrule .= ';COUNT=' . $form_values['COUNT'];
}
// iCal rules presume the week starts on Monday unless otherwise specified,
// so we'll specify it.
if (array_key_exists('WKST', $form_values)) {
$RRULE .= ';WKST=' . $form_values['WKST'];
$rrule .= ';WKST=' . $form_values['WKST'];
}
else {
$RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
$rrule .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
}
// Exceptions dates go last, on their own line.
@@ -765,7 +777,7 @@ function date_api_ical_build_rrule($form_values) {
foreach ($form_values['EXDATE'] as $value) {
if (!empty($value['datetime'])) {
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z' : '';
if (!empty($ex_date)) {
$ex_dates[] = $ex_date;
}
@@ -773,11 +785,11 @@ function date_api_ical_build_rrule($form_values) {
}
if (!empty($ex_dates)) {
sort($ex_dates);
$RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
$rrule .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
}
}
elseif (!empty($form_values['EXDATE'])) {
$RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
$rrule .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
}
// Exceptions dates go last, on their own line.
@@ -785,19 +797,19 @@ function date_api_ical_build_rrule($form_values) {
$ex_dates = array();
foreach ($form_values['RDATE'] as $value) {
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z' : '';
if (!empty($ex_date)) {
$ex_dates[] = $ex_date;
}
}
if (!empty($ex_dates)) {
sort($ex_dates);
$RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
$rrule .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
}
}
elseif (!empty($form_values['RDATE'])) {
$RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
$rrule .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
}
return $RRULE;
return $rrule;
}

View File

@@ -23,13 +23,14 @@ function date_sql_concat($array) {
switch (Database::getConnection()->databaseType()) {
case 'mysql':
return "CONCAT(" . implode(",", $array) . ")";
case 'pgsql':
return implode(" || ", $array);
}
}
/**
* Helper function to do cross-database NULL replacements
* Helper function to do cross-database NULL replacements.
*
* @param array $array
* An array of values to test for NULL values.
@@ -61,6 +62,7 @@ function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
switch ($side) {
case 'r':
return "RPAD($str, $size, '$pad')";
default:
return "LPAD($str, $size, '$pad')";
}
@@ -69,6 +71,7 @@ function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
/**
* A class to manipulate date SQL.
*/
// @codingStandardsIgnoreStart
class date_sql_handler {
var $db_type = NULL;
var $date_type = DATE_DATETIME;
@@ -86,7 +89,7 @@ class date_sql_handler {
/**
* The object constuctor.
*/
function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
public function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
$this->db_type = Database::getConnection()->databaseType();
$this->date_type = $date_type;
$this->db_timezone = 'UTC';
@@ -97,7 +100,7 @@ class date_sql_handler {
/**
* See if the db has timezone name support.
*/
function db_tz_support($reset = FALSE) {
public function db_tz_support($reset = FALSE) {
$has_support = variable_get('date_db_tz_support', -1);
if ($has_support == -1 || $reset) {
$has_support = FALSE;
@@ -108,6 +111,7 @@ class date_sql_handler {
$has_support = TRUE;
}
break;
case 'pgsql':
$test = db_query("SELECT '2008-02-15 12:00:00 UTC' AT TIME ZONE 'US/Central'")->fetchField();
if ($test == '2008-02-15 06:00:00') {
@@ -136,7 +140,7 @@ class date_sql_handler {
* set a fixed offset, not a timezone, so any value other than
* '+00:00' should be used with caution.
*/
function set_db_timezone($offset = '+00:00') {
public function set_db_timezone($offset = '+00:00') {
static $already_set = FALSE;
$type = Database::getConnection()->databaseType();
if (!$already_set) {
@@ -144,9 +148,11 @@ class date_sql_handler {
case 'mysql':
db_query("SET @@session.time_zone = '$offset'");
break;
case 'pgsql':
db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
break;
case 'sqlsrv':
// Issue #1201342, This is the wrong way to set the timezone, this
// still needs to be fixed. In the meantime, commenting this out makes
@@ -161,7 +167,7 @@ class date_sql_handler {
/**
* Return timezone offset for the date being processed.
*/
function get_offset($comp_date = NULL) {
public function get_offset($comp_date = NULL) {
if (!empty($this->db_timezone) && !empty($this->local_timezone)) {
if ($this->db_timezone != $this->local_timezone) {
if (empty($comp_date)) {
@@ -199,47 +205,57 @@ class date_sql_handler {
case DATE_UNIX:
$field = "FROM_UNIXTIME($field)";
break;
case DATE_ISO:
$field = "STR_TO_DATE($field, '%Y-%m-%dT%T')";
break;
case DATE_DATETIME:
break;
}
break;
case 'pgsql':
switch ($this->date_type) {
case DATE_UNIX:
$field = "$field::ABSTIME";
break;
case DATE_ISO:
$field = "TO_DATE($field, 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS')";
break;
case DATE_DATETIME:
break;
}
break;
case 'sqlite':
switch ($this->date_type) {
case DATE_UNIX:
$field = "datetime($field, 'unixepoch')";
break;
case DATE_ISO:
case DATE_DATETIME:
$field = "datetime($field)";
break;
}
break;
case 'sqlsrv':
switch ($this->date_type) {
case DATE_UNIX:
$field = "DATEADD(s, $field, '19700101 00:00:00:000')";
break;
case DATE_ISO:
case DATE_DATETIME:
$field = "CAST($field as smalldatetime)";
break;
}
break;
break;
}
// Adjust the resulting value to the right timezone/offset.
@@ -254,10 +270,13 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "ADDTIME($field, SEC_TO_TIME($offset))";
case 'pgsql':
return "($field + INTERVAL '$offset SECONDS')";;
return "($field + INTERVAL '$offset SECONDS')";
case 'sqlite':
return "datetime($field, '$offset seconds')";
case 'sqlsrv':
return "DATEADD(second, $offset, $field)";
}
@@ -285,6 +304,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "DATE_ADD($field, INTERVAL $count $granularity)";
case 'SUB':
return "DATE_SUB($field, INTERVAL $count $granularity)";
}
@@ -294,6 +314,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "($field + INTERVAL '$count $granularity')";
case 'SUB':
return "($field - INTERVAL '$count $granularity')";
}
@@ -302,6 +323,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "datetime($field, '+$count $granularity')";
case 'SUB':
return "datetime($field, '-$count $granularity')";
}
@@ -352,6 +374,7 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "CONVERT_TZ($field, $db_zone, $localzone)";
case 'pgsql':
// WITH TIME ZONE assumes the date is using the system
// timezone, which should have been set to UTC.
@@ -395,6 +418,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "DATE_FORMAT($field, '$format')";
case 'pgsql':
$replace = array(
'Y' => 'YYYY',
@@ -421,6 +445,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "TO_CHAR($field, '$format')";
case 'sqlite':
$replace = array(
// 4 digit year number.
@@ -460,6 +485,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "strftime('$format', $field)";
case 'sqlsrv':
$replace = array(
// 4 digit year number.
@@ -528,18 +554,25 @@ class date_sql_handler {
switch (strtoupper($extract_type)) {
case 'DATE':
return $field;
case 'YEAR':
return "EXTRACT(YEAR FROM($field))";
case 'MONTH':
return "EXTRACT(MONTH FROM($field))";
case 'DAY':
return "EXTRACT(DAY FROM($field))";
case 'HOUR':
return "EXTRACT(HOUR FROM($field))";
case 'MINUTE':
return "EXTRACT(MINUTE FROM($field))";
case 'SECOND':
return "EXTRACT(SECOND FROM($field))";
// ISO week number for date.
case 'WEEK':
switch ($this->db_type) {
@@ -547,6 +580,7 @@ class date_sql_handler {
// WEEK using arg 3 in MySQl should return the same value as
// Postgres EXTRACT.
return "WEEK($field, 3)";
case 'pgsql':
return "EXTRACT(WEEK FROM($field))";
}
@@ -556,6 +590,7 @@ class date_sql_handler {
// MySQL returns 1 for Sunday through 7 for Saturday, PHP date
// functions and Postgres use 0 for Sunday and 6 for Saturday.
return "INTEGER(DAYOFWEEK($field) - 1)";
case 'pgsql':
return "EXTRACT(DOW FROM($field))";
}
@@ -563,6 +598,7 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "DAYOFYEAR($field)";
case 'pgsql':
return "EXTRACT(DOY FROM($field))";
}
@@ -775,8 +811,7 @@ class date_sql_handler {
}
/**
* Create a complete datetime value out of an
* incomplete array of selected values.
* Create a complete date/time value out of an incomplete array of values.
*
* For example, array('year' => 2008, 'month' => 05) will fill
* in the day, hour, minute and second with the earliest possible
@@ -795,9 +830,11 @@ class date_sql_handler {
case 'empty_min':
case 'min':
return date_format($dates[0], 'Y-m-d H:i:s');
case 'empty_max':
case 'max':
return date_format($dates[1], 'Y-m-d H:i:s');
default:
return;
}
@@ -840,7 +877,7 @@ class date_sql_handler {
}
/**
* A function to test the validity of various date parts
* A function to test the validity of various date parts.
*/
function part_is_valid($value, $type) {
if (!preg_match('/^[0-9]*$/', $value)) {
@@ -856,16 +893,19 @@ class date_sql_handler {
return FALSE;
}
break;
case 'month':
if ($value < 0 || $value > 12) {
return FALSE;
}
break;
case 'day':
if ($value < 0 || $value > 31) {
return FALSE;
}
break;
case 'week':
if ($value < 0 || $value > 53) {
return FALSE;
@@ -890,26 +930,36 @@ class date_sql_handler {
$formats['display'] = 'Y';
$formats['sql'] = 'Y';
break;
case 'month':
$formats['display'] = date_limit_format($short, array('year', 'month'));
$formats['sql'] = 'Y-m';
break;
case 'day':
$formats['display'] = date_limit_format($short, array('year', 'month', 'day'));
$args = array('year', 'month', 'day');
$formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d';
break;
case 'hour':
$formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour'));
$args = array('year', 'month', 'day', 'hour');
$formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH';
break;
case 'minute':
$formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour', 'minute'));
$args = array('year', 'month', 'day', 'hour', 'minute');
$formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH:i';
break;
case 'second':
$formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour', 'minute', 'second'));
$args = array('year', 'month', 'day', 'hour', 'minute', 'second');
$formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH:i:s';
break;
case 'week':
$formats['display'] = 'F j Y (W)';
$formats['sql'] = 'Y-\WW';
@@ -927,7 +977,7 @@ class date_sql_handler {
'#type' => 'radios',
'#default_value' => $granularity,
'#options' => $this->date_parts(),
);
);
return $form;
}
@@ -1030,7 +1080,6 @@ class date_sql_handler {
$direction = $results[1];
$count = $results[2];
$item = $results[3];
$replace = array(
'now' => '@',
'+' => 'P',
@@ -1051,14 +1100,27 @@ class date_sql_handler {
'second' => 'S',
' ' => '',
' ' => '',
);
$prefix = in_array($item, array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second')) ? 'T' : '';
return $prefix . strtr($direction, $replace) . $count . strtr($item, $replace);
);
$args = array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second');
if (in_array($item, $args)) {
$prefix = 'T';
}
else {
$prefix = '';
}
$return = $prefix;
$return .= strtr($direction, $replace);
$return .= $count;
$return .= strtr($item, $replace);
return $return;
}
/**
* Use the parsed values from the ISO argument to determine the
* granularity of this period.
* Granularity arguments handler.
*
* Use the parsed values from the ISO argument
* to determine the granularity of this period.
*/
function arg_granularity($arg) {
$granularity = '';
@@ -1137,8 +1199,9 @@ class date_sql_handler {
}
return array($min_date, $max_date);
}
// Intercept invalid info and fall back to the current date.
// Intercept invalid info and fall back to the current date.
$now = date_now();
return array($now, $now);
}
}
// @codingStandardsIgnoreEnd

View File

@@ -206,24 +206,31 @@ function theme_date_time_ago($variables) {
$now = date_format(date_now(), DATE_FORMAT_UNIX);
$start = date_format($start_date, DATE_FORMAT_UNIX);
// will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
// Will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence).
$time_diff = $now - $start;
// Uses the same options used by Views format_interval.
switch ($display) {
case 'raw time ago':
return format_interval($time_diff, $interval);
case 'time ago':
return t('%time ago', array('%time' => format_interval($time_diff, $interval)));
case 'raw time hence':
return format_interval(-$time_diff, $interval);
case 'time hence':
return t('%time hence', array('%time' => format_interval(-$time_diff, $interval)));
case 'raw time span':
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
case 'inverse time span':
return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
case 'time span':
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), $interval)));
}
}