date_api.module in Date 6
Same filename and directory in other branches
This module will make the date API available to other modules. Designed to provide a light but flexible assortment of functions and constants, with more functionality in additional files that are not loaded unless other modules specifically include them.
File
date_api.moduleView source
<?php
/**
* @file
* This module will make the date API available to other modules.
* Designed to provide a light but flexible assortment of functions
* and constants, with more functionality in additional files that
* are not loaded unless other modules specifically include them.
*/
/**
* Set up some constants.
*
* Includes standard date types, format strings, strict regex strings for ISO
* and DATETIME formats (seconds are optional).
*
* The loose regex will find any variety of ISO date and time, with or
* without time, with or without dashes and colons separating the elements,
* and with either a 'T' or a space separating date and time.
*/
define('DATE_ISO', 'date');
define('DATE_UNIX', 'datestamp');
define('DATE_DATETIME', 'datetime');
define('DATE_ARRAY', 'array');
define('DATE_OBJECT', 'object');
define('DATE_ICAL', 'ical');
define('DATE_FORMAT_ISO', "Y-m-d\\TH:i:s");
define('DATE_FORMAT_UNIX', "U");
define('DATE_FORMAT_DATETIME', "Y-m-d H:i:s");
define('DATE_FORMAT_ICAL', "Ymd\\THis");
define('DATE_REGEX_ISO', '/(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):?(\\d{2})?/');
define('DATE_REGEX_DATETIME', '/(\\d{4})-(\\d{2})-(\\d{2})\\s(\\d{2}):(\\d{2}):?(\\d{2})?/');
define('DATE_REGEX_LOOSE', '/(\\d{4})-?(\\d{2})-?(\\d{2})([T\\s]?(\\d{2}):?(\\d{2}):?(\\d{2})?(\\.\\d+)?(Z|[\\+\\-]\\d{2}:?\\d{2})?)?/');
define('DATE_REGEX_ICAL_DATE', '/(\\d{4})(\\d{2})(\\d{2})/');
define('DATE_REGEX_ICAL_DATETIME', '/(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})(Z)?/');
/**
* Implementation of hook_init().
*/
function date_api_init() {
drupal_add_css(drupal_get_path('module', 'date_api') . '/date.css');
}
/**
* Helper function for getting the format string for a date type.
*/
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;
}
}
/**
* An untranslated array of month names
*
* Needed for css, translation functions, strtotime(), and other places
* that use the English versions of these words.
*
* @return
* an array of month names
*/
function date_month_names_untranslated() {
static $month_names;
if (empty($month_names)) {
$month_names = array(
1 => 'January',
2 => 'February',
3 => 'March',
4 => 'April',
5 => 'May',
6 => 'June',
7 => 'July',
8 => 'August',
9 => 'September',
10 => 'October',
11 => 'November',
12 => 'December',
);
}
return $month_names;
}
/**
* A translated array of month names
*
* @param $required
* If not required, will include a blank value at the beginning of the list.
* @return
* an array of month names
*/
function date_month_names($required = FALSE) {
static $month_names;
if (empty($month_names)) {
$month_names = array();
foreach (date_month_names_untranslated() as $key => $month) {
$month_names[$key] = t($month);
}
}
$none = array(
'' => '',
);
return !$required ? $none + $month_names : $month_names;
}
/**
* A translated array of month name abbreviations
*
* @param $required
* If not required, will include a blank value at the beginning of the list.
* @return
* an array of month abbreviations
*/
function date_month_names_abbr($required = FALSE) {
static $month_names;
if (empty($month_names)) {
$month_names = array();
foreach (date_month_names_untranslated() as $key => $month) {
$month_names[$key] = t(substr($month, 0, 3));
}
}
$none = array(
'' => '',
);
return !$required ? $none + $month_names : $month_names;
}
/**
* An untranslated array of week days
*
* Needed for css, translation functions, strtotime(), and other places
* that use the English versions of these words.
*
* @return
* an array of week day names
*/
function date_week_days_untranslated($refresh = TRUE) {
static $weekdays;
if ($refresh || empty($weekdays)) {
$weekdays = array(
0 => 'Sunday',
1 => 'Monday',
2 => 'Tuesday',
3 => 'Wednesday',
4 => 'Thursday',
5 => 'Friday',
6 => 'Saturday',
);
}
return $weekdays;
}
/**
* A translated array of week days
*
* @param $required
* If not required, will include a blank value at the beginning of the array.
* @return
* an array of week day names
*/
function date_week_days($required = FALSE, $refresh = TRUE) {
static $weekdays;
if ($refresh || empty($weekdays)) {
$weekdays = array();
foreach (date_week_days_untranslated($refresh) as $key => $day) {
$weekdays[$key] = t($day);
}
}
$none = array(
'' => '',
);
return !$required ? $none + $weekdays : $weekdays;
}
/**
* An translated array of week day abbreviations.
*
* @param $required
* If not required, will include a blank value at the beginning of the array.
* @return
* an array of week day abbreviations
*/
function date_week_days_abbr($required = FALSE, $refresh = TRUE, $length = 3) {
if ($refresh || empty($weekdays)) {
$weekdays = array();
foreach (date_week_days($refresh) as $key => $day) {
$weekdays[$key] = substr($day, 0, $length);
}
}
$none = array(
'' => '',
);
return !$required ? $none + $weekdays : $weekdays;
}
/**
* Order weekdays
* Correct weekdays array so first day in array matches the first day of
* the week. Use to create things like calendar headers.
*
* @param array $weekdays
* @return array
*/
function date_week_days_ordered($weekdays) {
if (variable_get('date_first_day', 1) > 0) {
for ($i = 1; $i <= variable_get('date_first_day', 1); $i++) {
$last = array_shift($weekdays);
array_push($weekdays, $last);
}
}
return $weekdays;
}
/**
* An array of years.
*
* @param int $min
* the minimum year in the array
* @param int $max
* the maximum year in the array
* @param $required
* If not required, will include a blank value at the beginning of the array.
* @return
* an array of years in the selected range
*/
function date_years($min = 0, $max = 0, $required = FALSE) {
// Have to be sure $min and $max are valid values;
if (empty($min)) {
$min = intval(date('Y', time()) - 3);
}
if (empty($max)) {
$max = intval(date('Y', time()) + 3);
}
$none = array(
0 => '',
);
return !$required ? $none + drupal_map_assoc(range($min, $max)) : drupal_map_assoc(range($min, $max));
}
/**
* An array of days.
*
* @param $required
* If not required, returned array will include a blank value.
* @param integer $month (optional)
* @param integer $year (optional)
* @return
* an array of days for the selected month.
*/
function date_days($required = FALSE, $month = NULL, $year = NULL) {
// If we have a month and year, find the right last day of the month.
if (!empty($month) && !empty($year)) {
$date = date_make_date($year . '-' . $month . '-01 00:00:00', 'UTC');
$max = date_format('t', $date);
}
// If there is no month and year given, default to 31.
if (empty($max)) {
$max = 31;
}
$none = array(
0 => '',
);
return !$required ? $none + drupal_map_assoc(range(1, $max)) : drupal_map_assoc(range(1, $max));
}
/**
* An array of hours.
*
* @param string $format
* @param $required
* If not required, returned array will include a blank value.
* @return
* an array of hours in the selected format.
*/
function date_hours($format = 'H', $required = FALSE) {
$hours = array();
if ($format == 'h' || $format == 'g') {
$min = 1;
$max = 12;
}
else {
$min = 0;
$max = 23;
}
for ($i = $min; $i <= $max; $i++) {
$hours[$i] = $i < 10 && $format == 'H' || $format == 'h' ? "0{$i}" : $i;
}
$none = array(
'' => '',
);
return !$required ? $none + $hours : $hours;
}
/**
* An array of minutes.
*
* @param string $format
* @param $required
* If not required, returned array will include a blank value.
* @return
* an array of minutes in the selected format.
*/
function date_minutes($format = 'i', $required = FALSE, $increment = 1) {
$minutes = array();
// Have to be sure $increment has a value so we don't loop endlessly;
if (empty($increment)) {
$increment = 1;
}
for ($i = 0; $i < 60; $i += $increment) {
$minutes[$i] = $i < 10 && $format == 'i' ? "0{$i}" : $i;
}
$none = array(
'' => '',
);
return !$required ? $none + $minutes : $minutes;
}
/**
* An array of seconds.
*
* @param string $format
* @param $required
* If not required, returned array will include a blank value.
* @return array an array of seconds in the selected format.
*/
function date_seconds($format = 's', $required = FALSE, $increment = 1) {
$seconds = array();
// Have to be sure $increment has a value so we don't loop endlessly;
if (empty($increment)) {
$increment = 1;
}
for ($i = 0; $i < 60; $i += $increment) {
$seconds[$i] = $i < 10 && $format == 's' ? "0{$i}" : $i;
}
$none = array(
'' => '',
);
return !$required ? $none + $seconds : $seconds;
}
/**
* An array of am and pm options.
* @param $required
* If not required, returned array will include a blank value.
* @return array an array of am pm options.
*/
function date_ampm($required = FALSE) {
$none = array(
'' => '',
);
$ampm = array(
'am' => t('am'),
'pm' => t('pm'),
);
return !$required ? $none + $ampm : $ampm;
}
/**
* An array of short date formats.
*
* @return array an array of short date format strings.
*/
function date_short_formats() {
return array(
'Y-m-d H:i',
'm/d/Y - H:i',
'd/m/Y - H:i',
'Y/m/d - H:i',
'd.m.Y - H:i',
'm/d/Y - g:ia',
'd/m/Y - g:ia',
'Y/m/d - g:ia',
'M j Y - H:i',
'j M Y - H:i',
'Y M j - H:i',
'M j Y - g:ia',
'j M Y - g:ia',
'Y M j - g:ia',
);
}
/**
* An array of medium date formats.
*
* @return array an array of medium date format strings.
*/
function date_medium_formats() {
return array(
'D, Y-m-d H:i',
'D, m/d/Y - H:i',
'D, d/m/Y - H:i',
'D, Y/m/d - H:i',
'F j, Y - H:i',
'j F, Y - H:i',
'Y, F j - H:i',
'D, m/d/Y - g:ia',
'D, d/m/Y - g:ia',
'D, Y/m/d - g:ia',
'F j, Y - g:ia',
'j F Y - g:ia',
'Y, F j - g:ia',
'j. F Y - G:i',
);
}
/**
* An array of long date formats.
*
* @return array an array of long date format strings.
*/
function date_long_formats() {
return array(
'l, F j, Y - H:i',
'l, j F, Y - H:i',
'l, Y, F j - H:i',
'l, F j, Y - g:ia',
'l, j F Y - g:ia',
'l, Y, F j - g:ia',
'l, j. F Y - G:i',
);
}
/**
* Array of regex replacement strings for date format elements.
* Used to allow input in custom formats. Based on work done for
* the Date module by Yves Chedemois (yched).
*
* @return array of date() format letters and their regex equivalents.
*/
function date_format_patterns() {
return array(
'd' => '\\d{2}',
'j' => '\\d{1,2}',
'N' => '\\d',
'S' => '\\w{2}',
'w' => '\\d',
'z' => '\\d{1,3}',
'W' => '\\d{1,2}',
'm' => '\\d{2}',
'n' => '\\d{1,2}',
't' => '\\d{2}',
'L' => '\\d',
'o' => '\\d{4}',
'Y' => '\\d{4}',
'y' => '\\d{2}',
'B' => '\\d{3}',
'g' => '\\d{1,2}',
'G' => '\\d{1,2}',
'h' => '\\d{2}',
'H' => '\\d{2}',
'i' => '\\d{2}',
's' => '\\d{2}',
'e' => '\\w*',
'I' => '\\d',
'T' => '\\w*',
'U' => '\\d*',
'z' => '[+-]?\\d*',
'O' => '[+-]?\\d{4}',
//Using S instead of w and 3 as well as 4 to pick up non-ASCII chars like German umlaute
'D' => '\\S{3,4}',
'l' => '\\S*',
'M' => '\\S{3,4}',
'F' => '\\S*',
'P' => '[+-]?\\d{2}\\:\\d{2}',
'c' => '(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})([+-]?\\d{2}\\:\\d{2})',
'r' => '(\\w{3}), (\\d{2})\\s(\\w{3})\\s(\\d{2,4})\\s(\\d{2}):(\\d{2}):(\\d{2})([+-]?\\d{4})?',
);
}
/**
* Array of granularity options and their labels
*
* @return array
*/
function date_granularity_names() {
return array(
'year' => t('Year'),
'month' => t('Month'),
'day' => t('Day'),
'hour' => t('Hour'),
'minute' => t('Minute'),
'second' => t('Second'),
);
}
/**
* A translated array of timezone names.
* Cache the untranslated array, make the translated array a static variable.
*
* @param $required
* If not required, returned array will include a blank value.
* @return
* an array of timezone names
*/
function date_timezone_names($required = FALSE, $refresh = FALSE) {
static $zonenames;
if (empty($zonenames)) {
$zonenames = array();
$cached = cache_get('date_timezone_identifiers_list');
if ($refresh || !($data = $cached->data)) {
$data = timezone_identifiers_list();
}
foreach ($data as $delta => $zone) {
// Because many time zones exist in PHP only for backward
// compatibility reasons and should not be used, the list is
// filtered by a regular expression.
if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) {
$zonenames[$zone] = t($zone);
}
else {
unset($data[$delta]);
}
}
if (!empty($data)) {
cache_set('date_timezone_identifiers_list', $data);
}
}
$none = array(
'' => '',
);
return !$required ? $none + $zonenames : $zonenames;
}
/**
* An array of timezone abbreviations that the system allows.
* Cache an array of just the abbreviation names because the
* whole timezone_abbreviations_list is huge so we don't want
* to get it more than necessary.
*
* @return array
*/
function date_timezone_abbr($refresh = FALSE) {
$cached = cache_get('date_timezone_abbreviations');
$data = isset($cached->data) ? $cached->data : array();
if (empty($data) || $refresh) {
$data = array_keys(timezone_abbreviations_list());
cache_set('date_timezone_abbreviations', $data);
}
return $data;
}
/**
* A version of the t() function for date parts that need translation.
*
* Run this over results of functions which do no translation of
* month and day names, like date() and date_format().
*
* @param string $string
* @return translated value of the string
*/
function date_t($string) {
static $replace;
if (empty($replace)) {
$replace = array();
// Translate the whole name first, then look for abbreviations.
foreach (date_month_names_untranslated() as $month) {
$replace[$month] = t($month);
$replace[substr($month, 0, 3)] = t(substr($month, 0, 3));
}
foreach (date_week_days_untranslated() as $day) {
$replace[$day] = t($day);
$replace[substr($day, 0, 3)] = t(substr($day, 0, 3));
}
}
return strtr($string, $replace);
}
/**
* An override for interval formatting that adds past and future context
*
* @param DateTime $date
* @param integer $granularity
* @return formatted string
*/
function date_format_interval($date, $granularity = 2) {
$interval = time() - date_format($date, 'U');
if ($interval > 0) {
return t('!time ago', array(
'!time' => format_interval($interval, $granularity),
));
}
else {
return format_interval(abs($interval), $granularity);
}
}
/**
* Reworked from Drupal's format_date function to handle pre-1970 and
* post-2038 dates and accept a date object instead of a timestamp as input.
*
* Translates formatted date results, unlike PHP function date_format().
*
* @param $oject
* A date object, could be created by date_make_date().
* @param $type
* The format to use. Can be "small", "medium" or "large" for the preconfigured
* date formats. If "custom" is specified, then $format is required as well.
* @param $format
* A PHP date format string as required by date(). A backslash should be used
* before a character to avoid interpreting the character as part of a date
* format.
* @return
* A translated date string in the requested format.
*/
function date_format_date($object, $type = 'medium', $format = '') {
if (empty($object)) {
return '';
}
switch ($type) {
case 'small':
$format = variable_get('date_format_short', 'm/d/Y - H:i');
break;
case 'large':
$format = variable_get('date_format_long', 'l, F j, Y - H:i');
break;
case 'custom':
$format = $format;
break;
case 'medium':
default:
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
}
return date_t(date_format($object, $format));
}
/**
* A date object for the current time.
*
* @param $timezone
* Optional method to force time to a specific timezone,
* defaults to user timezone, if set, otherwise site timezone.
* @return object date
*/
function date_now($timezone = NULL) {
return date_make_date('now', $timezone);
}
/**
* Convert a date of any type or an array of date parts into a valid date
* object.
* @param $date
* A date in any format or the string 'now'.
* @param $timezone
* Optional, the name of the timezone this date is in, defaults
* to the user timezone, if set, otherwise the site timezone.
* Accepts either a timezone name or a timezone object as input.
* @param $type
* The type of date provided, could be
* DATE_ARRAY, DATE_UNIX, DATE_DATETIME, DATE_ISO, or DATE_OBJECT.
*/
function date_make_date($date, $timezone = NULL, $type = DATE_DATETIME) {
// Make sure some value is set for the date and timezone even if the
// site timezone is not yet set up to avoid fatal installation
// errors.
if (empty($timezone)) {
$timezone = date_default_timezone_name();
}
if (!date_is_valid($date, $type) || empty($date)) {
$date = 'now';
}
if (!empty($timezone) && !empty($date)) {
if (!is_object($timezone)) {
$timezone = timezone_open($timezone);
}
if ($date == 'now') {
return date_create('now', $timezone);
}
elseif ($datetime = date_convert($date, $type, DATE_DATETIME)) {
if ($type == DATE_UNIX && timezone_name_get($timezone) != 'UTC') {
$date = date_create($datetime, timezone_open('UTC'));
date_timezone_set($date, $timezone);
return $date;
}
else {
return date_create($datetime, $timezone);
}
}
}
return NULL;
}
/**
* Return a timezone name to use as a default.
*
* @return a timezone name
* Identify the default timezone for a user, if available, otherwise the site.
* Must return a value even if no timezone info has been set up.
*/
function date_default_timezone_name($check_user = TRUE) {
global $user;
if ($check_user && variable_get('configurable_timezones', 1) && !empty($user->timezone_name)) {
return $user->timezone_name;
}
else {
$default = variable_get('date_default_timezone_name', '');
return empty($default) ? 'UTC' : $default;
}
}
/**
* A timezone object for the default timezone.
*
* @return a timezone name
* Identify the default timezone for a user, if available, otherwise the site.
*/
function date_default_timezone($check_user = TRUE) {
$timezone = date_default_timezone_name($check_user);
return timezone_open(date_default_timezone_name($check_user));
}
/**
* Identify the number of days in a month for a date.
*
* @param mixed $date
* @return integer
*/
function date_days_in_month($date = NULL, $type = DATE_OBJECT) {
if (empty($date)) {
$date = date_now();
$type = DATE_OBJECT;
}
$date = date_convert($date, $type, DATE_OBJECT);
if (is_object($date)) {
return date_format($date, 't');
}
return NULL;
}
/**
* Identify the number of days in a year for a date.
*
* @param mixed $date
* @param string $type
* @return integer
*/
function date_days_in_year($date = NULL, $type = DATE_OBJECT) {
if (empty($date)) {
$date = date_now();
$type = DATE_OBJECT;
}
$date = date_convert($date, $type, DATE_OBJECT);
if (is_object($date)) {
if (date_format($date, 'L')) {
return 366;
}
else {
return 365;
}
}
return NULL;
}
/**
* Identify the number of ISO weeks in a year for a date.
*
* December 28 is always in the last ISO week of the year.
*
* @param mixed $date
* @param string $type
* @return integer
*/
function date_iso_weeks_in_year($date = NULL, $type = DATE_OBJECT) {
if (empty($date)) {
$date = date_now();
$type = DATE_OBJECT;
}
$date = date_convert($date, $type, DATE_OBJECT);
if (is_object($date)) {
date_date_set($date, date_format($date, 'Y'), 12, 28);
return date_format($date, 'W');
}
return NULL;
}
/**
* Returns day of week for a given date (0 = Sunday).
*
* @param mixed $date
* a date, default is current local day
* @param string $type
* The type of date, DATE_ISO, DATE_DATETIME, or DATE_UNIX
* @return
* the number of the day in the week
*/
function date_day_of_week($date = NULL, $type = DATE_OBJECT) {
if (empty($date)) {
$date = date_now();
$type = DATE_OBJECT;
}
$date = date_convert($date, $type, DATE_OBJECT);
if (is_object($date)) {
return date_format($date, 'w');
}
return NULL;
}
/**
* Returns translated name of the day of week for a given date.
*
* @param mixed $date
* a date, default is current local day
* @param string $type
* The type of date, DATE_ISO, DATE_DATETIME, or DATE_UNIX
* @param string $abbr
* Whether to return the abbreviated name for that day
* @return
* the name of the day in the week for that date
*/
function date_day_of_week_name($date = NULL, $abbr = TRUE, $type = DATE_DATETIME) {
$dow = date_day_of_week($date, $type);
$days = $abbr ? date_week_days_abbr() : date_week_days();
return $days[$dow];
}
/**
* Compute difference between two days using a given measure.
*
* @param mixed $date1
* the starting date
* @param mixed $date2
* the ending date
* @param string $measure
* 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'
* @param string $type
* the type of dates provided:
* DATE_OBJECT, DATE_DATETIME, DATE_ISO, DATE_UNIX, DATE_ARRAY
*/
function date_difference($date1_in, $date2_in, $measure = 'seconds', $type = DATE_OBJECT) {
// Create cloned objects or original dates will be impacted by
// the date_modify() operations done in this code.
$date1 = drupal_clone(date_convert($date1_in, $type, DATE_OBJECT));
$date2 = drupal_clone(date_convert($date2_in, $type, DATE_OBJECT));
if (is_object($date1) && is_object($date2)) {
$diff = date_format($date2, 'U') - date_format($date1, 'U');
if ($diff == 0) {
return 0;
}
elseif ($diff < 0) {
// Make sure $date1 is the smaller date.
$temp = $date2;
$date2 = $date1;
$date1 = $temp;
$diff = date_format($date2, 'U') - date_format($date1, 'U');
}
$year_diff = intval(date_format($date2, 'Y') - date_format($date1, 'Y'));
switch ($measure) {
// The easy cases first.
case 'seconds':
return $diff;
case 'minutes':
return $diff * 60;
case 'hours':
return $diff * 24 * 60;
case 'years':
return $year_diff;
case 'months':
$format = 'n';
$item1 = date_format($date1, $format);
$item2 = date_format($date2, $format);
if ($year_diff == 0) {
return intval($item2 - $item1);
}
else {
$item_diff = 12 - $item1;
$item_diff += intval(($year_diff - 1) * 12);
return $item_diff + $item2;
}
break;
case 'days':
$format = 'z';
$item1 = date_format($date1, $format);
$item2 = date_format($date2, $format);
if ($year_diff == 0) {
return intval($item2 - $item1);
}
else {
$item_diff = date_days_in_year($date1) - $item1;
for ($i = 1; $i < $year_diff; $i++) {
date_modify($date1, '+1 year');
$item_diff += date_days_in_year($date1);
}
return $item_diff + $item2;
}
break;
case 'weeks':
$week_diff = date_format($date2, 'W') - date_format($date1, 'W');
$year_diff = date_format($date2, 'o') - date_format($date1, 'o');
for ($i = 1; $i <= $year_diff; $i++) {
date_modify($date1, '+1 year');
$week_diff += date_iso_weeks_in_year($date1);
}
return $week_diff;
}
}
return NULL;
}
/**
* Start and end dates for a calendar week, adjusted to use the
* chosen first day of week for this site.
*/
function date_week_range($week, $year) {
$min_date = date_make_date($view->year . '-01-01 00:00:00', date_default_timezone_name());
date_timezone_set($min_date, date_default_timezone());
// move to the right week
date_modify($min_date, '+' . strval(7 * ($week - 1)) . ' days');
// move backwards to the first day of the week
$first_day = variable_get('date_first_day', 0);
$day_wday = date_format($min_date, 'w');
date_modify($min_date, '-' . strval((7 + $day_wday - $first_day) % 7) . ' days');
// move forwards to the last day of the week
$max_date = drupal_clone($min_date);
date_modify($max_date, '+7 days');
if (date_format($min_date, 'Y') != $year) {
$min_date = date_make_date($year . '-01-01 00:00:00', date_default_timezone());
}
return array(
$min_date,
$max_date,
);
}
/**
* The number of calendar weeks in a year.
*
* PHP week functions return the ISO week, not the calendar week.
*
* @param int $year
* @return int number of calendar weeks in selected year.
*/
function date_weeks_in_year($year) {
$date = date_make_date($year + 1 . '-01-01 12:00:00', 'UTC');
date_modify($date, '-1 day');
return date_week(date_format($date, 'Y-m-d'));
}
/**
* The calendar week number for a date.
*
* PHP week functions return the ISO week, not the calendar week.
*
* @param string $date, in the format Y-m-d
* @return int calendar week number.
*/
function date_week($date) {
$parts = explode('-', $date);
$date = date_make_date($date . ' 12:00:00', 'UTC');
$year_date = date_make_date($parts[0] . '-01-01 12:00:00', 'UTC');
$week = intval(date_format($date, 'W'));
$year_week = intval(date_format($year_date, 'W'));
$date_year = intval(date_format($date, 'o'));
// remove the leap week if it's present
if ($date_year > intval($parts[0])) {
$last_date = drupal_clone($date);
date_modify($last_date, '-7 days');
$week = date_format($last_date, 'W') + 1;
}
else {
if ($date_year < intval($parts[0])) {
$week = 0;
}
}
if ($year_week != 1) {
$week++;
}
// convert to ISO-8601 day number, to match weeks calculated above
$iso_first_day = 1 + (variable_get('date_first_day', 0) + 6) % 7;
// if it's before the starting day, it's the previous week
if (intval(date_format($date, 'N')) < $iso_first_day) {
$week--;
}
// if the year starts before, it's an extra week at the beginning
if (intval(date_format($year_date, 'N')) < $iso_first_day) {
$week++;
}
return $week;
}
/**
* Date conversion helper function.
*
* A variety of ways to convert dates from one type to another.
* No timezone conversion is done in this operation!!
*
* Example: date_convert('2007-03-15 08:30', DATE_DATETIME, DATE_UNIX);
* returns unix value for the supplied date.
*
* @param mixed $date
* the date to convert
* @param string $from_type
* the type of date to convert from
* @param string $to_type
* the type of date to convert to
*/
function date_convert($date, $from_type, $to_type) {
if (empty($date) && !$date === 0) {
return NULL;
}
if (empty($from_type) || empty($to_type) || $from_type == $to_type) {
return $date;
}
switch ($from_type) {
case DATE_ARRAY:
if (!is_array($date)) {
return NULL;
}
$datetime = date_pad(intval($date['year']), 4) . '-' . date_pad(intval($date['month'])) . '-' . date_pad(intval($date['day'])) . ' ' . date_pad(intval($date['hour'])) . ':' . date_pad(intval($date['minute'])) . ':' . date_pad(intval($date['second']));
switch ($to_type) {
case DATE_ISO:
return str_replace(' ', 'T', $datetime);
case DATE_DATETIME:
return $datetime;
case DATE_ICAL:
$replace = array(
' ' => 'T',
'-' => '',
':' => '',
);
return strtr($datetime, $replace);
case DATE_OBJECT:
return date_create($datetime, timezone_open('UTC'));
case DATE_UNIX:
$obj = date_create($datetime, timezone_open('UTC'));
return date_format($obj, 'U');
}
break;
case DATE_OBJECT:
if (!is_object($date)) {
return NULL;
}
$obj = $date;
break;
case DATE_DATETIME:
case DATE_ISO:
if (!preg_match(DATE_REGEX_LOOSE, $date)) {
return NULL;
}
$date = str_replace('T', ' ', $date);
$obj = date_make_date(date_fuzzy_datetime($date), 'UTC');
break;
case DATE_ICAL:
if (!preg_match(DATE_REGEX_LOOSE, $date)) {
return NULL;
}
preg_match(DATE_REGEX_LOOSE, $date, $regs);
$datetime = date_pad($regs[1], 4) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]) . 'T' . date_pad($regs[5]) . ':' . date_pad($regs[6]) . ':' . date_pad($regs[7]);
$obj = date_create($datetime, timezone_open('UTC'));
case DATE_UNIX:
if (!is_numeric($date)) {
return NULL;
}
$obj = date_create("@{$date}", timezone_open('UTC'));
break;
}
switch ($to_type) {
case DATE_OBJECT:
return $obj;
case DATE_DATETIME:
return date_format($obj, DATE_FORMAT_DATETIME);
case DATE_ISO:
return date_format($obj, DATE_FORMAT_ISO);
case DATE_ICAL:
return date_format($obj, DATE_FORMAT_ICAL);
case DATE_UNIX:
return date_format($obj, 'U');
case DATE_ARRAY:
$date_array = date_array($obj);
// ISO dates may contain zero values for some date parts,
// make sure they don't get lost in the conversion.
if ($from_type == DATE_ISO) {
$date_array = array_merge($date_array, date_iso_array($date));
}
return $date_array;
default:
return NULL;
}
}
/**
* Create valid datetime value from incomplete ISO dates or arrays.
*/
function date_fuzzy_datetime($date) {
if (!is_array($date)) {
$date = date_iso_array($date);
}
if (empty($date['year'])) {
$date['year'] = date('Y');
}
if (empty($date['month'])) {
$date['month'] = 1;
}
if (empty($date['day'])) {
$date['day'] = 1;
}
$value = date_pad($date['year'], 4) . '-' . date_pad($date['month']) . '-' . date_pad($date['day']) . 'T' . date_pad($date['hour']) . ':' . date_pad($date['minute']) . ':' . date_pad($date['second']);
return $value;
}
/**
* Create an array of date parts from an ISO date.
*/
function date_iso_array($date) {
preg_match(DATE_REGEX_LOOSE, $date, $regs);
return array(
'year' => intval($regs[1]),
'month' => intval($regs[2]),
'day' => intval($regs[3]),
'hour' => intval($regs[5]),
'minute' => intval($regs[6]),
'second' => intval($regs[7]),
);
}
/**
* Create an array of values from a date object. Structured like the
* results of getdate() but not limited to the 32-bit signed range.
*
* @param object $obj
* @return array
*/
function date_array($obj) {
$year = intval(date_format($obj, 'Y'));
$dow = date_format($obj, 'w');
$days = date_week_days();
return array(
'second' => (int) date_format($obj, 's'),
'minute' => (int) date_format($obj, 'i'),
'hour' => date_format($obj, 'G'),
'day' => date_format($obj, 'j'),
'wday' => $dow,
'month' => date_format($obj, 'n'),
'year' => date_format($obj, 'Y'),
'yday' => date_format($obj, 'z'),
'weekday' => $days[$dow],
'month_name' => date_format($obj, 'F'),
0 => date_format($obj, 'U'),
);
}
/**
* Extract integer value of any date part from any type of date.
*
* Example:
* date_part_extract('2007-03-15 00:00', 'month', DATE_DATETIME)
* returns: 3
*
* @param mixed $date
* the date value to analyze.
* @param string $part
* the part of the date to extract, 'year', 'month', 'day', 'hour', 'minute', 'second'
* @param string $type
* the type of date supplied, DATE_ISO, DATE_UNIX, DATE_DATETIME, or DATE_OBJECT;
* @return integer
* the integer value of the requested date part.
*/
function date_part_extract($date, $part, $type = DATE_DATETIME) {
$formats = array(
'year' => 'Y',
'month' => 'n',
'day' => 'j',
'hour' => 'G',
'minute' => 'i',
'second' => 's',
);
$positions = array(
'year' => 0,
'month' => 5,
'day' => 8,
'hour' => 11,
'minute' => 14,
'second' => 17,
);
$ipositions = array(
'year' => 0,
'month' => 4,
'day' => 6,
'hour' => 9,
'minute' => 11,
'second' => 13,
);
switch ($type) {
case DATE_ARRAY:
return (int) $date[$part];
case DATE_DATETIME:
case DATE_ISO:
return (int) substr($date, $positions[$part], $part == 'year' ? 4 : 2);
case DATE_ICAL:
return (int) substr($date, $ipositions[$part], $part == 'year' ? 4 : 2);
case DATE_UNIX:
$date = date_create("@{$date}", timezone_open('UTC'));
return date_format($date, $formats[$part]);
case DATE_OBJECT:
return date_format($date, $formats[$part]);
}
}
/**
* Functions to test the validity of a date in various formats.
* Has special case for ISO dates and arrays which can be missing
* month and day and still be valid.
*
* @param $type
* could be DATE_ARRAY, DATE_UNIX, DATE_DATETIME, DATE_ISO, or DATE_OBJECT
*/
function date_is_valid($date, $type = DATE_DATETIME) {
if (empty($date)) {
return FALSE;
}
if ($type == DATE_OBJECT && !is_object($date)) {
return FALSE;
}
if (($type == DATE_ISO || $type == DATE_DATETIME) && !preg_match(DATE_REGEX_LOOSE, $date)) {
return FALSE;
}
if ($type == DATE_UNIX and !is_numeric($date)) {
return FALSE;
}
if ($type == DATE_ARRAY and !is_array($date)) {
return FALSE;
}
// If checkdate works, no need for further tests.
$year = date_part_extract($date, 'year', $type);
$month = date_part_extract($date, 'month', $type);
$day = date_part_extract($date, 'day', $type);
if (!checkdate($month, $day, $year)) {
// ISO dates and arrays can have empty date parts
if ($type == DATE_ISO || $type == DATE_ARRAY) {
if (variable_get('date_max_year', 4000) < $year || variable_get('date_min_year', 1) > $year || 12 < $month || 0 > $month || 31 < $day || 0 > $day) {
return FALSE;
}
}
elseif (variable_get('date_max_year', 4000) < $year || variable_get('date_min_year', 1) > $year || 12 < $month || 1 > $month || 31 < $day || 1 > $day) {
return FALSE;
}
}
return TRUE;
}
/**
* Helper function to left pad date parts with zeros.
* Provided because this is needed so often with dates.
*
* @param int $value
* the value to pad
* @param int $size
* total size expected, usually 2 or 4
* @return string the padded value
*/
function date_pad($value, $size = 2) {
return sprintf("%0" . $size . "d", $value);
}
/**
* Function to figure out if any time data is to be collected or displayed.
*
* @param granularity
* an array like ('year', 'month', 'day', 'hour', 'minute', 'second');
*/
function date_has_time($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
return sizeof(array_intersect($granularity, array(
'hour',
'minute',
'second',
))) > 0 ? TRUE : FALSE;
}
/**
* Recalculate a date so it only includes elements from a granularity
* array. Helps prevent errors when unwanted values round up and ensures
* that unwanted date part values don't get stored in the database.
*
* Example:
* date_limit_value('2007-05-15 04:45:59', array('year', 'month', 'day'))
* returns '2007-05-15 00:00:00'
*
* @param $date
* a date value
* @param $granularity
* an array of allowed date parts, like ('year', 'month', 'day', 'hour', 'minute', 'second');
* @param $type
* the type of date value provided,
* DATE_DATETIME, DATE_ISO, DATE_UNIX, or DATE_ARRAY
* @return
* the date with the unwanted parts reset to zeros (or ones if zeros are
* invalid for that date type).
*/
function date_limit_value($date, $granularity, $type = DATE_DATETIME) {
if (!date_is_valid($date, $type) || !($nongranularity = date_nongranularity($granularity))) {
return $date;
}
else {
$date = date_convert($date, $type, DATE_ARRAY);
foreach ($nongranularity as $level) {
switch ($level) {
case 'second':
$date['second'] = 0;
break;
case 'minute':
$date['minute'] = 0;
break;
case 'hour':
$date['hour'] = 0;
break;
case 'month':
$date['month'] = $type != DATE_ISO ? 1 : 0;
break;
case 'day':
$date['day'] = $type != DATE_ISO ? 1 : 0;
break;
}
}
return date_convert($date, DATE_ARRAY, $type);
}
}
/**
* Rewrite a format string so it only inludes elements from a
* specified granularity array.
*
* Example:
* date_limit_format('F j, Y - H:i', array('year', 'month', 'day'));
* returns 'F j, Y'
*
* @param $format
* a format string
* @param $granularity
* an array of allowed date parts, all others will be removed
* array('year', 'month', 'day', 'hour', 'minute', 'second');
* @return
* a format string with all other elements removed
*/
function date_limit_format($format, $granularity) {
// Strip out timezone formatting.
// Get rid of dash separating date and time if either is missing.
if (!date_has_time($granularity) || sizeof(array_intersect($granularity, array(
'year',
'month',
'day',
)) == 0)) {
$regex[] = '( -)';
}
if (!date_has_time($granularity)) {
$regex[] = '(a|A)';
}
// Create regular expressions to remove selected values from string.
foreach (date_nongranularity($granularity) as $element) {
switch ($element) {
case 'year':
$regex[] = '([\\-/\\.]?[Yy][\\-/\\.,]?)';
break;
case 'day':
$regex[] = '([\\-/\\.]?[lDdj][\\-/\\.,]?)';
break;
case 'month':
$regex[] = '([\\-/\\.]?[FMmn][\\-/\\.,]?)';
break;
case 'hour':
$regex[] = '([HhGg][:]?)';
break;
case 'minute':
$regex[] = '([:]?[i])';
break;
case 'second':
$regex[] = '([:]?[s])';
break;
case 'timezone':
$regex[] = '([OZPe])';
break;
}
}
// Remove selected values from string.
// Don't leave any trailing punctuation behind.
$format = trim(preg_replace($regex, array(), $format));
return preg_replace('([\\-/\\.,]$)', '', $format);
}
/**
* Convert a format to an ordered array of granularity parts.
*
* Example:
* date_format_order('m/d/Y H:i')
* returns
* array(
* 0 => 'month',
* 1 => 'day',
* 2 => 'year',
* 3 => 'hour',
* 4 => 'minute',
* );
*
* @param string $format
* @return array of ordered granularity elements in this format string
*/
function date_format_order($format) {
$order = array();
if (empty($format)) {
return $order;
}
$max = strlen($format);
for ($i = 0; $i <= $max; $i++) {
if (!isset($format[$i])) {
break;
}
$c = $format[$i];
switch ($c) {
case 'd':
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;
}
}
return $order;
}
/**
* An difference array of granularity elements that are NOT in the
* granularity array. Used by functions that strip unwanted
* granularity elements out of formats and values.
*
* @param $granularity
* an array like ('year', 'month', 'day', 'hour', 'minute', 'second');
*/
function date_nongranularity($granularity) {
return array_diff(array(
'year',
'month',
'day',
'hour',
'minute',
'second',
'timezone',
), (array) $granularity);
}
/**
* Implementation of hook_simpletest().
*/
function date_api_simpletest() {
$dir = drupal_get_path('module', 'date_api') . '/tests';
$tests = file_scan_directory($dir, '\\.test$');
return array_keys($tests);
}
/**
* Implementation of hook_elements().
*/
function date_api_elements() {
include_once drupal_get_path('module', 'date_api') . '/date_api_elements.inc';
return _date_api_elements();
}
function date_api_theme() {
$path = drupal_get_path('module', 'date_api');
$base = array(
'file' => 'theme.inc',
'path' => "{$path}/theme",
);
return array(
'date_nav' => $base + array(
'template' => 'date-nav',
'arguments' => array(
'view' => NULL,
),
),
'date_nav_title' => array(
'arguments' => array(
'type' => NULL,
'view' => NULL,
),
),
'date_timezone' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_select' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_text' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_select_element' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_textfield_element' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_date_part_hour_prefix' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_minsec_prefix' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_year' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_month' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_day' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_hour' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_minute' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_second' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_ampm' => array(
'arguments' => array(
'element' => NULL,
),
),
'date_part_label_timezone' => array(
'arguments' => array(
'element' => NULL,
),
),
);
}
/**
* Wrapper around date handler setting for timezone.
*/
function date_api_set_db_timezone($offset = '+00:00') {
include_once drupal_get_path('module', 'date_api') . '/date_api_sql.inc';
$handler = new date_sql_handler();
return $handler
->set_db_timezone($offset);
}
Functions
Name | Description |
---|---|
date_ampm | An array of am and pm options. |
date_api_elements | Implementation of hook_elements(). |
date_api_init | Implementation of hook_init(). |
date_api_set_db_timezone | Wrapper around date handler setting for timezone. |
date_api_simpletest | Implementation of hook_simpletest(). |
date_api_theme | |
date_array | Create an array of values from a date object. Structured like the results of getdate() but not limited to the 32-bit signed range. |
date_convert | Date conversion helper function. |
date_days | An array of days. |
date_days_in_month | Identify the number of days in a month for a date. |
date_days_in_year | Identify the number of days in a year for a date. |
date_day_of_week | Returns day of week for a given date (0 = Sunday). |
date_day_of_week_name | Returns translated name of the day of week for a given date. |
date_default_timezone | A timezone object for the default timezone. |
date_default_timezone_name | Return a timezone name to use as a default. |
date_difference | Compute difference between two days using a given measure. |
date_format_date | Reworked from Drupal's format_date function to handle pre-1970 and post-2038 dates and accept a date object instead of a timestamp as input. |
date_format_interval | An override for interval formatting that adds past and future context |
date_format_order | Convert a format to an ordered array of granularity parts. |
date_format_patterns | Array of regex replacement strings for date format elements. Used to allow input in custom formats. Based on work done for the Date module by Yves Chedemois (yched). |
date_fuzzy_datetime | Create valid datetime value from incomplete ISO dates or arrays. |
date_granularity_names | Array of granularity options and their labels |
date_has_time | Function to figure out if any time data is to be collected or displayed. |
date_hours | An array of hours. |
date_iso_array | Create an array of date parts from an ISO date. |
date_iso_weeks_in_year | Identify the number of ISO weeks in a year for a date. |
date_is_valid | Functions to test the validity of a date in various formats. Has special case for ISO dates and arrays which can be missing month and day and still be valid. |
date_limit_format | Rewrite a format string so it only inludes elements from a specified granularity array. |
date_limit_value | Recalculate a date so it only includes elements from a granularity array. Helps prevent errors when unwanted values round up and ensures that unwanted date part values don't get stored in the database. |
date_long_formats | An array of long date formats. |
date_make_date | Convert a date of any type or an array of date parts into a valid date object. |
date_medium_formats | An array of medium date formats. |
date_minutes | An array of minutes. |
date_month_names | A translated array of month names |
date_month_names_abbr | A translated array of month name abbreviations |
date_month_names_untranslated | An untranslated array of month names |
date_nongranularity | An difference array of granularity elements that are NOT in the granularity array. Used by functions that strip unwanted granularity elements out of formats and values. |
date_now | A date object for the current time. |
date_pad | Helper function to left pad date parts with zeros. Provided because this is needed so often with dates. |
date_part_extract | Extract integer value of any date part from any type of date. |
date_seconds | An array of seconds. |
date_short_formats | An array of short date formats. |
date_t | A version of the t() function for date parts that need translation. |
date_timezone_abbr | An array of timezone abbreviations that the system allows. Cache an array of just the abbreviation names because the whole timezone_abbreviations_list is huge so we don't want to get it more than necessary. |
date_timezone_names | A translated array of timezone names. Cache the untranslated array, make the translated array a static variable. |
date_type_format | Helper function for getting the format string for a date type. |
date_week | The calendar week number for a date. |
date_weeks_in_year | The number of calendar weeks in a year. |
date_week_days | A translated array of week days |
date_week_days_abbr | An translated array of week day abbreviations. |
date_week_days_ordered | Order weekdays Correct weekdays array so first day in array matches the first day of the week. Use to create things like calendar headers. |
date_week_days_untranslated | An untranslated array of week days |
date_week_range | Start and end dates for a calendar week, adjusted to use the chosen first day of week for this site. |
date_years | An array of years. |