date.inc in Date 5
Date/time API functions
this api uses timezones rather than offsets to avoid dst problems the date_timezone.inc api is used to compute the correct offset for a timezone, taking into account dst
Usage examples: create a new date object: $date = date_make_date();
set local value of 2006-05-04T10:24:00 US/Eastern date_set_date($date, '2006-05-04T10:24:00', 'US/Eastern', 'local', DATE_ISO);
display the local value using the format string 'm/d/Y H:i' print date_show_date($date, 'm/d/Y H:i', 'local');
display the db values of the date object: print date_show_value($date, 'db', DATE_UNIX); // the unix db value print date_show_value($date, 'db', DATE_ISO); // the iso db value
display the date object and all its parts: print_r($date);
File
date.incView source
<?php
/**
* @file
* Date/time API functions
*
* this api uses timezones rather than offsets to avoid dst problems
* the date_timezone.inc api is used to compute the correct offset for a timezone, taking into account dst
*
* Usage examples:
* create a new date object:
* $date = date_make_date();
*
* set local value of 2006-05-04T10:24:00 US/Eastern
* date_set_date($date, '2006-05-04T10:24:00', 'US/Eastern', 'local', DATE_ISO);
*
* display the local value using the format string 'm/d/Y H:i'
* print date_show_date($date, 'm/d/Y H:i', 'local');
*
* display the db values of the date object:
* print date_show_value($date, 'db', DATE_UNIX); // the unix db value
* print date_show_value($date, 'db', DATE_ISO); // the iso db value
*
* display the date object and all its parts:
* print_r($date);
*/
/**
* Date wrapper functions
*
* will use external library if available, otherwise native php date functions
* currently set up for adodb date library, could be extended to include other date libraries
*
* @param $array - array parameters are in the format created by getdate()
* prefix functions with @ to surpress ugly windows error messages for dates outside valid range
*/
function date_load_library() {
if (DATE_LIBRARY == 'ADODB' && !function_exists('adodb_date_test_date') && file_exists(DATE_LIBRARY_FILE)) {
include_once DATE_LIBRARY_FILE;
}
}
function date_getdate($timestamp) {
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return adodb_getdate($timestamp);
default:
return getdate($timestamp);
}
}
/**
* We need a gmgetdate function, which does not exist
* because the getdate function creates an array where date parts and timestamp don't match
* getdate date parts are timezone-adjusted to the server zone and timestamp is not
* we need an array where date parts match the timestamp.
* Check for empty timestamps to make sure empty values don't display as 1/1/1970.
*/
function date_gmgetdate($timestamp) {
if ($timestamp === FALSE) {
return '';
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
// Must use the private function to force it to GMT.
$array = _adodb_getdate($timestamp, FALSE, TRUE);
$array[0] = $timestamp;
return $array;
default:
// The date_adj_zone function corrects for timezone adjustment getdate will add.
$array = getdate(date_adj_zone($timestamp));
$array[0] = $timestamp;
return $array;
}
}
function date_date($format, $timestamp = FALSE) {
if ($timestamp === FALSE) {
return '';
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return @adodb_date($format, $timestamp);
default:
return date($format, $timestamp);
}
}
function date_gmdate($format, $timestamp = FALSE) {
if ($timestamp === FALSE) {
return '';
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return @adodb_gmdate($format, $timestamp);
default:
return @gmdate($format, $timestamp);
}
}
function date_mktime($array) {
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
$timestamp = @adodb_mktime(intval($array['hours']), intval($array['minutes']), intval($array['seconds']), max(intval($array['mon']), 1), max(intval($array['mday']), 1), intval($array['year']) > 0 ? intval($array['year']) : date('Y'));
return $timestamp;
default:
$timestamp = @mktime(intval($array['hours']), intval($array['minutes']), intval($array['seconds']), max(intval($array['mon']), 1), max(intval($array['mday']), 1), intval($array['year']) > 0 ? intval($array['year']) : date('Y'));
return $timestamp;
}
}
function date_gmmktime($array) {
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
$timestamp = @adodb_gmmktime(intval($array['hours']), intval($array['minutes']), intval($array['seconds']), max(intval($array['mon']), 1), max(intval($array['mday']), 1), intval($array['year']) > 0 ? intval($array['year']) : date('Y'));
return $timestamp;
default:
$timestamp = @gmmktime(intval($array['hours']), intval($array['minutes']), intval($array['seconds']), max(intval($array['mon']), 1), max(intval($array['mday']), 1), intval($array['year']) > 0 ? intval($array['year']) : date('Y'));
return $timestamp;
}
}
function date_strftime($format, $timestamp = FALSE) {
if (!$timestamp) {
return '';
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return @adodb_strftime($format, $timestamp);
default:
return @strftime($format, $timestamp);
}
}
function date_gmstrftime($format, $timestamp = FALSE) {
if (!$timestamp) {
return '';
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return @adodb_gmstrftime($format, $timestamp);
default:
return @gmstrftime($format, $timestamp);
}
}
/**
* These functions will remove server timezone adjustment from timestamps
* needed because some php date functions automatically adjust to server zone
* but the date object uses raw values for date parts and does manual timezone adj
* needed for ability to accomodate timezones other than server zone
*/
function date_adj_zone($timestamp) {
// No timezone adjustment for very old dates.
if ($timestamp < 86400) {
return $timestamp;
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return intval($timestamp - adodb_date('Z', $timestamp));
default:
return intval($timestamp - date('Z', $timestamp));
}
}
function date_gmadj_zone($timestamp) {
// No timezone adjustment for very old dates.
if ($timestamp < 86400) {
return $timestamp;
}
date_load_library();
switch (DATE_LIBRARY) {
case 'ADODB':
return intval($timestamp + adodb_date('Z', $timestamp));
default:
return intval($timestamp + date('Z', $timestamp));
}
}
/**
* Implementation of time() adjusted for the current site and user.
*
* @param $offset - optional method to force time to a specific offset
* @return integer timestamp
*/
function date_time($offset = NULL) {
global $user;
if ($offset) {
return time() - date("Z") + offset;
}
elseif (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
return time() - date("Z") + $user->timezone;
}
else {
return time() - date("Z") + variable_get('date_default_timezone', 0);
}
}
/**
* Function to create a date object
*
* All creation, manipulation, and display of the date is done using this date object
*
* @param $value - the date/time value to set
* @param $timezone - 'GMT', 'none', or timezone name - the timezone of this value
* @param $type - db or local, the part of the date object to set
* @param $format - DATE_UNIX or DATE_ISO, the format of the provided value
* @return - the date object
*/
function date_make_date($value = '', $timezone = 'GMT', $type = 'db', $format = DATE_ISO) {
$date = new StdClass();
$date->db = new StdClass();
$date->db->timestamp = NULL;
$date->db->iso = NULL;
$date->db->parts = NULL;
$date->local = new StdClass();
$date->local->timestamp = NULL;
$date->local->iso = NULL;
$date->local->parts = NULL;
$date->local->timezone = NULL;
$date->local->offset = NULL;
if (trim($value) == '') {
return $date;
}
// if initialized with a date, go ahead and set that date up
date_set_date($date, $value, $timezone, $type, $format);
return $date;
}
/**
* Function to set local and db date parts in the date object
*
* @param $date - the date object
* @param $value - the date/time value to set
* @param $timezone - 'GMT', 'none', or timezone name - the timezone of this value
* - the 'none' option will do no timezone conversions, dates will be stored exactly as entered
* @param $type - db or local, the part of the date object to set
* - if you supply a local value and timezone, the function will create the related db values
* @param $format - DATE_UNIX or DATE_ISO, the format of the provided value
* - if you supply a unix timestamp, the date object will also create an iso version of the date, and vice versa
* @param $reset - force a reset of the provided value even if it already exists
*/
function date_set_date(&$date, $value, $timezone = 'GMT', $type = 'db', $format = DATE_ISO, $reset = FALSE, $display_errors = FALSE) {
if (trim($value) == '') {
// make new blank date
$date = date_make_date();
return TRUE;
}
// Turn date-only ISO date into complete ISO date,
// i.e. 2007-10-01 becomes 2007-10-01T00:00:00.
if ($format == DATE_ISO && strlen($value) < 19) {
$value = substr($value . 'T00:00:00', 0, 19);
}
// store the starting value of the date object in case there are errors
$old_date = $date;
$error = array();
if (trim($value) === 'ERROR') {
$error[] = 'value';
}
if (!$error && $format == DATE_UNIX) {
$date->{$type}->timestamp = $value;
$parts = date_unix2array($value);
if ($parts === 'ERROR') {
$error[] = 'unix2array';
}
else {
$date->{$type}->parts = $parts;
}
$iso = date_unix2iso($value);
if ($iso === 'ERROR') {
$error[] = 'unix2iso';
}
else {
$date->{$type}->iso = $iso;
}
}
elseif (!$error && $format == DATE_ISO) {
$date->{$type}->iso = $value;
$parts = date_iso2array($value);
if ($parts === 'ERROR') {
$error[] = 'iso2array';
}
else {
$date->{$type}->parts = $parts;
}
$unix = date_iso2unix($value);
if ($unix === 'ERROR') {
$error[] = 'iso2unix';
}
else {
$date->{$type}->timestamp = $unix;
}
}
else {
$error[] = $format;
}
if (!$error && $type == 'local' && (!$date->db->iso || $reset)) {
if (!date_no_conversion($date) && !empty($timezone)) {
$date->local->timezone = $timezone;
// if the local value was submitted, go ahead and compute the db part of the date
date_convert_timezone($date, $date->local->timezone, 'GMT', 'db');
}
else {
$date->db = $date->local;
}
}
elseif (!$error && $type == 'db' && $date->local->iso && (!$date->local->iso || $reset)) {
if (!date_no_conversion($date) && !empty($timezone)) {
// compute local value if the db value was submitted
// and the local value has not been created and there is a local timezone
date_convert_timezone($date, 'GMT', $date->local->timezone, 'local');
}
else {
$date->local = $date->db;
}
}
if ($error) {
// if unable to set date to this value, revert to previous date settings and show error message
$date = $old_date;
if ($display_errors) {
drupal_set_message(t('Unable to set date. ') . implode(', ', $error));
}
return FALSE;
}
return TRUE;
}
/**
* Function to identify dates that must never have timezone conversion.
*
* @param object $date
* @return true or false
*/
function date_no_conversion($date) {
if (isset($date->local->parts['year']) && $date->local->parts['year'] < 1970) {
return TRUE;
}
elseif (isset($date->db->parts['year']) && $date->db->parts['year'] < 1970) {
return TRUE;
}
return FALSE;
}
/**
* Timezone conversion function
*
* @param $date - the date object
* @param $timezone_in - 'none', 'GMT', or timezone name in format 'US/Central'
* @param $timezone_out - 'none', 'GMT', or timezone name in format 'US/Central'
* @param $type - 'db' or 'local', the part of the date object to be created
*
*/
function date_convert_timezone(&$date, $timezone_in = 'GMT', $timezone_out = 'GMT', $type = 'db') {
$fromtype = $type == 'db' ? 'local' : 'db';
// skip timezone conversion if no timezone conversion was desired
// set the local and db parts of the date object to be the same and return
if ($timezone_in == 'none' || $timezone_out == 'none' || !isset($date->{$fromtype}->parts[0])) {
if (($date->local->iso || $date->local->iso == 0) && !$date->db->iso) {
date_set_date($date, $date->local->iso, $timezone_out, 'db', DATE_ISO);
}
elseif (($date->db->iso || $date->db->iso == 0) && !$date->local->iso) {
date_set_date($date, $date->db->iso, $timezone_out, 'local', DATE_ISO);
}
return;
}
if ($type == 'local') {
$date->local->timezone = $timezone_out;
// attempt conversion only when there is available data to use
if (!$date->db->iso && !$date->db->iso == 0) {
return;
}
// see if an offset applies, and adjust date accordingly
if ($offset = date_offset(date_gmgetdate($date->db->timestamp), $date->local->timezone)) {
$out_date = $date->db->timestamp + $offset;
date_set_date($date, $out_date, $timezone_out, $type, DATE_UNIX);
$date->local->offset = $offset;
// no offset, just set other part of date object to same value
}
else {
date_set_date($date, $date->db->iso, $timezone_out, $type, DATE_ISO);
$date->local->offset = 0;
}
}
else {
// attempt conversion only when there is available data to use
if (!$date->local->iso && !$date->local->iso == 0 || !$date->local->timezone) {
return;
}
// see if an offset applies, and adjust date accordingly
if ($offset = date_offset(date_gmgetdate($date->local->timestamp), $date->local->timezone)) {
$out_date = $date->local->timestamp - $offset;
date_set_date($date, $out_date, $timezone_out, $type, DATE_UNIX);
$date->local->offset = $offset;
}
else {
date_set_date($date, $date->local->iso, $timezone_out, $type, DATE_ISO);
$date->local->offset = 0;
}
}
return;
}
/**
* A function to calculate offset using timezone.inc file
*
* @param $date_parts - an array of date parts in the format created by getdate()
* @param $timezone - the timezone to use
* @return $offset - the offset of $timezone from GMT on the $date_parts date
*/
function date_offset($date_parts, $timezone = 'GMT') {
include_once './' . drupal_get_path('module', 'date_api') . '/date_timezones.inc';
// no adjustment needed for gmt dates
if ($timezone == 'GMT') {
return 0;
}
// find the timezone info for the input timezone
$timezones = array_flip(date_zonelist());
$zid = $timezones[$timezone];
// create a timestamp for the date to be evaluated
if ($date_parts['year'] < 1970) {
// fudge offset for dates prior to 1970 by finding the offset in 1971
$date_parts['year'] = 1971;
$timestamp = date_array2unix($date_parts);
}
else {
$timestamp = $date_parts[0];
}
return date_get_offset($zid, $timestamp);
}
/**
* A function to display the database value for the date object
*
* @param $date - the date object
* @param $format - DATE_UNIX or DATE_ISO, the type of value to display
* @param $type - 'db' or 'local', the date value to display
*/
function date_show_value($date, $type = 'db', $format = DATE_ISO) {
if ($format == DATE_UNIX) {
return $date->{$type}->timestamp;
}
else {
return $date->{$type}->iso;
}
}
/**
* A function to display formatted output for the date object
*
* @param $date - the date object
* @param $format_string - the format string to be used for the display
* @param $type - 'local' or 'db', the date value to be displayed
*/
function date_show_date($date, $format_string, $type = 'local') {
if ($type == 'db' || !$date->local->timestamp && $date->local->timestamp != 0) {
return date_format_date($format_string, date_fuzzy_stamp($date->db), $date->local->offset, $date->local->timezone) . $append;
}
elseif ($date->local->timestamp || $date->local->timestamp == 0) {
return date_format_date($format_string, date_fuzzy_stamp($date->local), $date->local->offset, $date->local->timezone) . $append;
}
}
/**
* Format date
*
* Translate month and day text in date formats.
* Using gmdate so php won't try to adjust value for server timezone.
* Needed because date object has already made necessary timezone adjustments.
*
* Similar to core format_date function but will work on old, pre-1970 dates
* if adodb library is available.
*/
function date_format_date($format, $timestamp, $offset = NULL, $timezone_name = NULL) {
$max = strlen($format);
if (isset($timezone_name) && !isset($offset)) {
$offset = date_offset(date_gmgetdate($timestamp), $timezone_name);
}
$date = '';
for ($i = 0; $i < $max; $i++) {
$c = $format[$i];
if (strpos('AaDFlM', $c) !== FALSE) {
$date .= t(date_gmdate($c, $timestamp));
}
elseif (strpos('BdgGhHiIjLmnsStUwWYyz', $c) !== FALSE) {
$date .= date_gmdate($c, $timestamp);
}
elseif ($c == 'r') {
$date .= date_format_date($timestamp, 'D, d M Y H:i:s O', $offset, $timezone_name);
}
elseif ($c == '\\') {
$date .= $format[++$i];
}
elseif ($c == 'O') {
if (isset($offset)) {
$hours = intval($offset / 3600);
$minutes = intval($offset / 60 - $hours * 60);
$date .= ' ' . sprintf('%+05d', $hours * 100);
}
}
elseif ($c == 'P') {
if (isset($offset)) {
$hours = intval($offset / 3600);
$minutes = intval($offset / 60 - $hours * 60);
$date .= ' ' . sprintf('%+03d', $hours) . ':' . sprintf('%02d', $minutes);
}
}
elseif ($c == 'e' || $c == 'T') {
if (isset($timezone_name)) {
$date .= ' ' . $timezone_name;
}
}
else {
$date .= $c;
}
}
return $date;
}
/**
* Create a valid timestamp that can be used for date formatting
* even if only partial date info is available,
* i.e. for an iso date with month and year only
*/
function date_fuzzy_stamp($datetype) {
if ($datetype->timestamp) {
return $datetype->timestamp;
}
else {
return date_gmmktime(array(
'year' => $datetype->parts['year'] ? $datetype->parts['year'] : date('Y'),
'mon' => $datetype->parts['mon'] ? $datetype->parts['mon'] : 1,
'mday' => $datetype->parts['mday'] ? $datetype->parts['mday'] : 1,
'hours' => $datetype->parts['hours'] ? $datetype->parts['hours'] : 0,
'minutes' => $datetype->parts['minutes'] ? $datetype->parts['minutes'] : 0,
'seconds' => $datetype->parts['seconds'] ? $datetype->parts['seconds'] : 0,
));
}
}
/**
* A function to append the zone offset or name to a display
*
* Alternative to timezone identifiers in format string
* needed because format string tz identification may display server zone rather than site or date zone
* no option for zone abbreviation (i.e. EST) because zone abbreviations
* are not unique, nor are they available in the timezone.inc data
*
* @param $type - the type of display desired
* - '0000' will display zone offset like -0500
* - '00:00' will display zone offset like -05:00
* - 'name' will display zone name
*/
function date_append_zone($date, $type = '') {
if (!$type) {
return;
}
$offset = intval($date->local->offset);
$hours = intval($offset / 3600);
$minutes = intval($offset / 60 - $hours * 60);
switch (trim($type)) {
case '0000':
return ' ' . sprintf('%+05d', $hours * 100);
case '00:00':
return ' ' . sprintf('%+03d', $hours) . ':' . sprintf('%02d', $minutes);
case 'name':
return ' ' . $date->local->timezone;
}
}
function date_append_zone_options() {
return array(
'' => '',
'0000' => '+-0000',
'00:00' => '+-00:00',
'name' => t('zone name'),
);
}
/**
* Time zone option list
*
* @return array of timezone ids (i.e. US/Eastern, US/Central)
* @param $limit - an optional offset value, to limit the results to timezones that match that offset
*/
function date_timezone_options($limit = '') {
include_once './' . drupal_get_path('module', 'date_api') . '/date_timezones.inc';
$zonelist = array();
if (!$limit) {
$zonelist = drupal_map_assoc(date_zonelist());
}
else {
$zones = date_get_timezones();
foreach ($zones as $zone) {
if ($zone['offset'] == $limit || $zone['offset_dst'] == $limit) {
$zonelist[$zone['timezone']] = $zone['timezone'];
}
}
}
$zonelist += array(
'GMT' => 'GMT',
);
asort($zonelist);
return $zonelist;
}
/**
* Set system variable for site default timezone
* Needed because current system variable tracks offset rather than timezone
*/
function date_set_site_timezone($val) {
include_once './' . drupal_get_path('module', 'date_api') . '/date_timezones.inc';
$timezones = date_zonelist();
if (!in_array($val, $timezones)) {
$val = 'GMT';
}
variable_set('date_default_timezone_name', $val);
}
/**
* Get system variable setting for site default timezone
*/
function date_get_site_timezone() {
return variable_get('date_default_timezone_name', '');
}
/**
* Timezone handling options
* omitting user option for now because we only know the user's offset at best, not their timezone
* come back later and enable this option if there is a way to collect and save user timezones
*
* the 'none' option will do no timezone conversions and will store and display dates exactly as entered
* useful in locales or situations where timezone conversions are not working reliably,
* for dates with no times, for historical dates where timezones are irrelevant,
* or anytime conversion is unnecessary or undesirable
*/
function date_timezone_handling_options() {
return array(
'gmt' => 'GMT',
'site' => t('Site\'s time zone'),
'date' => t('Date\'s time zone'),
//'user' => t('User\'s time zone'),
'none' => t('No time zone conversion'),
);
}
/**
* Function to figure out which timezone applies to a date and select it
*/
function date_get_timezone($handling, $timezone = '') {
switch ($handling) {
case 'site':
$timezone_out = date_get_site_timezone();
break;
case 'date':
$timezone_out = $timezone > '' ? $timezone : date_get_site_timezone();
break;
case 'user':
// come back here and add appropriate value if user timezones are can be collected and saved
// until then, user option is not enabled
case 'none':
$timezone_out = 'none';
break;
default:
$timezone_out = 'GMT';
}
return $timezone_out > '' ? $timezone_out : 'GMT';
}
/**
* Flexible Date/Time Drop-Down Selector
*
* $params = an array of values, including
* label = the label for the date group, default is 'Date'
* value = the date/time to be processed, default is the current date and time
* timezone_in = the timezone of the date/time value to be processed, default is GMT
* timezone_out = the timezone to be used when displaying the date, default is date site timezone, if set, or GMT
* valid timezones are standard timezone ids like US/Central, America/New_York, GMT
* format = the format of the date value, default is DATE_ISO
* DATE_UNIX => unix timestamp
* DATE_ISO => iso 8601 YYYY-MM-DDThh:mm:ss
* am/pm = 0 to display 24 hour format, 1 to display 12 hour format with am/pm selector, default is 0
* weight = the weight of the date group, default is 0
* delta = a delta value for the group to accomodate multiple date fields, default is 0
* granularity = an array of date parts to be selected, like array('Y','M','D'), default is M, D, Y
* Y => year, M => month, D => day, H => hours, N => minutes, S => seconds, T => timezone
* increment = increment minutes and seconds by increment amount, default is 1
* opt_fields = an array of fields that need not be filled out, default is empty array
* blank_default = 1 to show an empty date field with blank values, 0 to fill with current date, default is 0
* required = 1 if the field must contain a valid date, default is 1
* description = text to be used as a description for the fieldset
*/
function date_select_input($params) {
drupal_add_css('./' . drupal_get_path('module', 'date_api') . '/date.css');
// set the variables
$label = $params['label'] ? $params['label'] : t('Date');
$delta = isset($params['delta']) ? $params['delta'] : 0;
$granularity = is_array($params['granularity']) ? $params['granularity'] : array(
'M',
'D',
'Y',
);
$increment = isset($params['increment']) ? $params['increment'] : 1;
$required = isset($params['required']) ? $params['required'] : 1;
$format = isset($params['format']) ? $params['format'] : DATE_ISO;
$formats = $params['formats'];
$weight = isset($params['weight']) ? $params['weight'] : 0;
$opt_fields = is_array($params['opt_fields']) ? $params['opt_fields'] : array();
$blank_default = isset($params['blank_default']) ? $params['blank_default'] : 0;
$timezone_in = isset($params['timezone_in']) ? $params['timezone_in'] : (!$blank_default || $params['value'] ? 'GMT' : '');
$timezone_out = isset($params['timezone_out']) ? $params['timezone_out'] : (!$blank_default || $params['value'] ? date_get_site_timezone() : '');
$description = $params['description'];
$select_month = !in_array('mon', $params['text_parts']);
$select_day = !in_array('mday', $params['text_parts']);
$select_year = !in_array('year', $params['text_parts']);
$year_range = explode(':', $params['year_range']);
$years_back = abs($year_range[0]);
$years_forward = abs($year_range[1]);
if ($formats['input']['am_pm']) {
$hours_format = 'g';
for ($i = 0; $i <= 12; $i++) {
$hours_array[$i] = $i < 10 ? "0{$i}" : $i;
}
}
else {
$hours_format = 'G';
for ($i = 0; $i <= 23; $i++) {
$hours_array[$i] = $i < 10 ? "0{$i}" : $i;
}
}
// create a date object with the desired date
$date = date_make_date();
if ($params['value']) {
date_set_date($date, $params['value'], $timezone_in, 'db', $format);
date_convert_timezone($date, $timezone_in, $timezone_out, 'local');
}
// find current date
switch ($format) {
case DATE_UNIX:
$now = date_gmadj_zone(time());
break;
default:
$now = date_unix2iso(date_gmadj_zone(time()));
}
if (!$blank_default && $params['value'] == '') {
date_set_date($date, $now, $timezone_out, 'local', $format);
}
if (!$blank_default || $params['value'] > '') {
$year = date_show_date($date, 'Y');
$mon = date_show_date($date, 'n');
$mday = date_show_date($date, 'j');
$hours = date_show_date($date, $hours_format);
$minutes = intval(date_show_date($date, 'i'));
$seconds = intval(date_show_date($date, 's'));
$ampm = strtolower(date_show_date($date, 'a'));
}
// create the form values
$form['#title'] = $label;
$form['#weight'] = intval($weight);
$form['#theme'] = 'date_form_select';
$form['#attributes'] = array(
'class' => 'container-inline-date',
);
if (in_array('D', $granularity)) {
$form['mday'] = array(
'#default_value' => $mday,
'#title' => t('day'),
'#required' => $required && !in_array('mday', $opt_fields) ? $required : 0,
'#weight' => $formats['input']['select']['D'],
);
if ($select_day) {
$days_array = drupal_map_assoc(range(1, 31));
if (!$required || in_array('mday', $opt_fields) || $blank_default) {
array_unshift($days_array, '');
}
$form['mday']['#type'] = 'select';
$form['mday']['#options'] = $days_array;
}
else {
$form['mday']['#type'] = 'textfield';
$form['mday']['#maxlength'] = 2;
$form['mday']['#size'] = 2;
}
}
if (in_array('M', $granularity)) {
$form['mon'] = array(
'#default_value' => $mon,
'#title' => t('month'),
'#required' => $required && !in_array('mon', $opt_fields) ? $required : 0,
'#weight' => $formats['input']['select']['M'],
);
if ($select_month) {
$months_array = drupal_map_assoc(range(1, 12), 'map_month');
if (!$required || in_array('mon', $opt_fields) || $blank_default) {
array_unshift($months_array, '');
}
$form['mon']['#type'] = 'select';
$form['mon']['#options'] = $months_array;
}
else {
$form['mon']['#type'] = 'textfield';
$form['mon']['#maxlength'] = 2;
$form['mon']['#size'] = 2;
}
}
if (in_array('Y', $granularity)) {
$form['year'] = array(
'#default_value' => $year,
'#title' => t('year'),
'#required' => $required && !in_array('year', $opt_fields) ? $required : 0,
'#weight' => $formats['input']['select']['Y'],
);
if ($select_year) {
$year = $year > 0 ? $year : date_gmdate('Y', date_gmadj_zone(time()));
$years_array = drupal_map_assoc(range($year - $years_back, $year + $years_forward));
// array_unshift converts the assoc array to a numeric one, can't use it here
if (!$required || in_array('year', $opt_fields) || $blank_default) {
$years_array = array(
0 => '',
) + $years_array;
}
$form['year']['#type'] = 'select';
$form['year']['#options'] = $years_array;
}
else {
$form['year']['#type'] = 'textfield';
$form['year']['#maxlength'] = 4;
$form['year']['#size'] = 4;
}
}
if (in_array('H', $granularity)) {
$form['hours'] = array(
'#type' => 'select',
'#default_value' => $hours,
'#options' => $hours_array,
'#required' => $required && !in_array('hours', $opt_fields) ? $required : 0,
'#title' => t('hour'),
'#weight' => 4,
);
}
if (in_array('N', $granularity)) {
for ($i = 0; $i <= 59; $i += $increment) {
$minutes_array[$i] = $i < 10 ? "0{$i}" : $i;
}
$form['minutes'] = array(
'#type' => 'select',
'#default_value' => $minutes,
'#options' => $minutes_array,
'#required' => $required && !in_array('minutes', $opt_fields) ? $required : 0,
'#title' => t('minute'),
'#weight' => 5,
);
}
if (in_array('S', $granularity)) {
for ($i = 0; $i <= 59; $i += $increment) {
$seconds_array[$i] = $i < 10 ? "0{$i}" : $i;
}
$form['seconds'] = array(
'#type' => 'select',
'#default_value' => $seconds,
'#options' => $seconds_array,
'#required' => $required && !in_array('seconds', $opt_fields) ? $required : 0,
'#title' => t('second'),
'#weight' => 6,
);
}
if ($formats['input']['am_pm']) {
$options = array(
'am' => t('am'),
'pm' => t('pm'),
);
if (!$required || in_array('hours', $opt_fields) || $blank_default) {
array_unshift($options, '');
}
$form['ampm'] = array(
'#type' => 'select',
'#default_value' => $ampm,
'#options' => $options,
'#required' => $required && !in_array('hours', $opt_fields) ? $required : 0,
'#title' => t('am/pm'),
'#weight' => 8,
);
}
$form[] = array(
'#theme' => 'date_form_select_description',
'#weight' => 11,
'description' => array(
'#value' => $description,
),
);
return $form;
}
/**
* Text date input form, with optional jscalendar popup
*
* $params = an array of values, including
* label = the label for the date group, default is 'Date'
* value = the date/time to be processed, default is the current date and time
* timezone_in = the timezone of the date/time value to be processed, default is GMT
* timezone_out = the timezone to be used when displaying the date, default is date site timezone, if set, or GMT
* valid timezones are standard timezone ids like US/Central, America/New_York, GMT
* format = the format of the date value, default is DATE_ISO
* DATE_UNIX => unix timestamp
* DATE_ISO => iso 8601 YYYY-MM-DDThh:mm:ss
* weight = the weight of the date group, default is 0
* delta = a delta value for the group to accomodate multiple date fields, default is 0
* granularity = an array of date parts to be selected, like array('Y','M','D'), default is M, D, Y
* Y => year, M => month, D => day, H => hours, N => minutes, S => seconds, T => timezone
* required = 1 if the field must contain a valid date, default is 1
* description = text to be used as a description for the fieldset
* blank_default = 1 to show an empty date field with blank values, 0 to fill with current date, default is 0
* jscalendar = 1 use if available, 0 do not use
*/
function date_text_input($params) {
// set the variables
$label = $params['label'] ? $params['label'] : t('Date');
$delta = isset($params['delta']) ? $params['delta'] : 0;
$granularity = is_array($params['granularity']) ? $params['granularity'] : array(
'M',
'D',
'Y',
);
$required = isset($params['required']) ? $params['required'] : 1;
$blank_default = isset($params['blank_default']) ? $params['blank_default'] : 0;
$format = isset($params['format']) ? $params['format'] : DATE_ISO;
$formats = $params['formats'];
$weight = isset($params['weight']) ? $params['weight'] : 0;
$timezone_in = isset($params['timezone_in']) ? $params['timezone_in'] : (!$blank_default || $params['value'] ? 'GMT' : '');
$timezone_out = isset($params['timezone_out']) ? $params['timezone_out'] : (!$blank_default || $params['value'] ? date_get_site_timezone() : '');
$description = $params['description'];
$jscalendar = $params['jscalendar'] ? 1 : 0;
$opt_fields = is_array($params['opt_fields']) ? $params['opt_fields'] : array();
$field_name = $params['field_name'] ? $params['field_name'] : 'value';
// create a new date object and convert it to the right timezone
// create a date object with the desired date
$date = date_make_date();
if ($params['value']) {
date_set_date($date, $params['value'], $timezone_in, 'db', $format);
date_convert_timezone($date, $timezone_in, $timezone_out, 'local');
}
// if required and no date provided, use current date
if ($required && !$blank_default && $params['value'] == '') {
switch ($format) {
case DATE_UNIX:
$now = date_gmadj_zone(time());
break;
default:
$now = date_unix2iso(date_gmadj_zone(time()));
}
date_set_date($date, $now, $timezone_out, 'local', $format);
}
// get the local iso version of the database value
$value = date_iso2custom(date_show_value($date, 'local'), $formats['input']['text']);
// date-specific timezone not requested, just get date
$form[$field_name] = array(
'#type' => 'textfield',
'#title' => $label,
'#default_value' => $value,
'#required' => $delta == 0 ? $required : 0,
'#description' => $description,
'#weight' => $weight,
);
// if the jscalendar is used for input, add some attributes to be passed to the js
// also need to adjust the date format slightly to accomodate the js capability
if ($jscalendar && module_exists('jscalendar')) {
$form[$field_name]['#attributes'] = array(
'class' => 'jscalendar',
);
$form[$field_name]['#jscalendar_ifFormat'] = $formats['input']['jscal'];
$form[$field_name]['#jscalendar_showsTime'] = date_has_time($granularity) ? 'true' : 'false';
$form[$field_name]['#jscalendar_timeFormat'] = $formats['input']['am_pm'] ? '12' : '24';
$form['#theme'] = 'date_form_jscalendar';
}
else {
$form['#theme'] = 'date_form_text';
}
return $form;
}
/**
* Timezone input form
*
* $params = an array of values, including
* timezone_in = the timezone of the date/time value to be processed, default is GMT
* timezone_out = the timezone to be used when displaying the date, default is date site timezone, if set, or GMT
* valid timezones are standard timezone ids like US/Central, America/New_York, GMT
* granularity = an array of date parts to be selected, like array('Y','M','D'), default is M, D, Y
* Y => year, M => month, D => day, H => hours, N => minutes, S => seconds, T => timezone
* required = 1 if the field must contain a valid date, default is 1
* blank_default = 1 to show an empty date field with blank values, 0 to fill with current date, default is 0
* weight = the form weight
*/
function date_timezone_input($params) {
// set the variables
$required = isset($params['required']) ? $params['required'] : 1;
$blank_default = isset($params['blank_default']) ? $params['blank_default'] : 0;
$timezone_in = isset($params['timezone_in']) ? $params['timezone_in'] : (!$blank_default || $params['value'] ? 'GMT' : '');
$timezone_out = isset($params['timezone_out']) ? $params['timezone_out'] : (!$blank_default || $params['value'] ? date_get_site_timezone() : '');
$opt_fields = is_array($params['opt_fields']) ? $params['opt_fields'] : array();
$granularity = is_array($params['granularity']) ? $params['granularity'] : array(
'M',
'D',
'Y',
);
$weight = $params['weight'];
$label = $params['label'] ? $params['label'] . ' ' : '';
if (in_array('T', $granularity)) {
$form['timezone'] = array(
'#title' => $label . t('timezone'),
'#type' => 'select',
'#default_value' => $timezone_out ? $timezone_out : (!$blank_default ? 'GMT' : ''),
'#options' => $required ? date_timezone_options() : array(
'' => '',
) + date_timezone_options(),
'#required' => $required && !in_array('timezone', $opt_fields) ? $required : 0,
);
}
else {
$form['timezone'] = array(
'#type' => 'hidden',
'#value' => $timezone_out,
);
}
$form['#theme'] = 'date_form_timezone';
$form['#weight'] = $weight;
return $form;
}
/**
* Construct a value to save to the database from the date selector
*
* @param $array - an array of date parts collected by the date selector
* @param $type - DATE_UNIX or DATE_ISO
* @param $timezone_in - timezone of supplied value
* @param $granularity = an array of date parts to be selected, like array('Y','M','D'), default is M, D, Y
* Y => year, M => month, D => day, H => hours, N => minutes, S => seconds, T => timezone
*/
function date_selector_make_dbdate($array, $type = DATE_ISO, $timezone_in = 'GMT', $granularity = array(
'M',
'D',
'Y',
)) {
// adjust back to 24 hours time if 12 hours input was collected
if ($array['ampm'] == 'pm' && $array['hours'] < 12) {
$array['hours'] += 12;
}
// try to construct a date from the submitted values
$date = date_make_date();
if ($type == DATE_UNIX) {
if (date_set_date($date, date_array2unix($array), $timezone_in, 'local', $type)) {
return $date;
}
}
elseif ($type == DATE_ISO) {
if (date_set_date($date, date_array2iso($array), $timezone_in, 'local', $type)) {
return $date;
}
}
return FALSE;
}
/**
* Construct a value to save to the database from jscalendar input
*
* @param $value - a text value created by js_calendar
* @param $type - DATE_UNIX or DATE_ISO
* @param $format - a string containing the format the field is using (date() format)
* @param $timezone_in - timezone of supplied value
* @param $granularity = an array of date parts to be selected, like array('Y','M','D'), default is M, D, Y
* Y => year, M => month, D => day, H => hours, N => minutes, S => seconds, T => timezone
*/
function date_jscalendar_make_dbdate($value, $type, $format, $timezone_in = 'GMT', $granularity = array(
'M',
'D',
'Y',
)) {
$value = trim($value);
if ($value == '') {
return NULL;
}
switch ($type) {
case DATE_UNIX:
$value = date_custom2unix($value, $format);
break;
case DATE_ISO:
$value = date_custom2iso($value, $format);
break;
}
if ($value) {
if ($date = date_make_date($value, $timezone_in, 'local', $type)) {
return $date;
}
}
return FALSE;
}
/**
* Construct a value to save to the database from text input
*
* @param $value - string date value, could be iso format or text for strtotime conversion
* @param $type - DATE_UNIX or DATE_ISO
* @param $format - a string containing the format the field is using (date() format)
* @param $timezone_in - timezone of supplied value
* @param $granularity = an array of date parts to be selected, like array('Y','M','D'), default is M, D, Y
* Y => year, M => month, D => day, H => hours, N => minutes, S => seconds, T => timezone
*/
function date_text_make_dbdate($value, $type, $format, $timezone_in = 'GMT', $granularity = array(
'M',
'D',
'Y',
)) {
$value = trim($value);
if ($value == '') {
return NULL;
}
switch ($type) {
case DATE_UNIX:
$value = date_text2unix($value, $format);
break;
case DATE_ISO:
$value = date_text2iso($value, $format);
break;
}
if ($value) {
if ($date = date_make_date($value, $timezone_in, 'local', $type)) {
return $date;
}
}
return FALSE;
}
/**
* Validation function for date selector
* $params = an array of values including:
* required = is a valid date required, default is true
* opt_fields = an array of fields that need not be filled out, default is empty array
*/
function date_selector_validate($value, $fieldname, $params = array()) {
$type = $params['type'] > '' ? $params['type'] : DATE_ISO;
$required = isset($params['required']) ? $params['required'] : 1;
$opt_fields = is_array($params['opt_fields']) ? $params['opt_fields'] : array();
$granularity = $params['granularity'] ? $params['granularity'] : array(
'M',
'D',
'Y',
);
if ($value['ampm'] == 'pm' && $value['hours'] < 12) {
$value['hours'] += 12;
}
// check for invalid numbers in fields that were submitted using textfields
if (($required || $value['year']) && !in_array($value['year'], $opt_fields)) {
if (!date_part_is_valid($value['year'], 'year')) {
form_set_error($fieldname, t('year must be a number between %min and %max.', array(
'%min' => DATE_MIN_YEAR,
'%max' => DATE_MAX_YEAR,
)));
}
}
if (($required || $value['mon']) && !in_array($value['mon'], $opt_fields)) {
if (!date_part_is_valid($value['mon'], 'mon')) {
form_set_error($fieldname, t('month must be a number between 1 and 12.'));
}
}
if (($required || $value['mday']) && !in_array($value['mday'], $opt_fields)) {
if (!date_part_is_valid($value['mday'], 'day')) {
form_set_error($fieldname, t('day must be a number between 1 and 31.'));
}
}
// try to construct a date from the submitted values
if ($required && !date_selector_make_dbdate($value, $type)) {
form_set_error($fieldname, t('Date cannot be constructed using values %s.', array(
'%s' => implode(', ', $value),
)));
return FALSE;
}
else {
return TRUE;
}
}
/**
* Validation for jscalendar input
*/
function date_jscalendar_validate($value, $fieldname, $type, $format, $required, $granularity = array(
'M',
'D',
'Y',
)) {
$value = trim($value);
if (!$required && $value == '') {
return TRUE;
}
switch ($type) {
case DATE_UNIX:
if (!date_custom2unix($value, $format)) {
form_set_error($fieldname, t('The text \'%s\' is not a valid date.', array(
'%s' => $value,
)));
return FALSE;
}
break;
case DATE_ISO:
if (!date_custom2iso($value, $format)) {
form_set_error($fieldname, t('The text \'%s\' is not a valid date.', array(
'%s' => $value,
)));
return FALSE;
}
break;
}
return TRUE;
}
/**
* Validation for text input
*/
function date_text_validate($value, $fieldname, $type, $format, $required, $granularity = array(
'M',
'D',
'Y',
)) {
$value = trim($value);
if (!$required && $value == '') {
return TRUE;
}
switch ($type) {
case DATE_UNIX:
if (!($value = date_text2unix($value, $format))) {
form_set_error($fieldname, t('The text \'%s\' is not a valid date.', array(
'%s' => $value,
)));
return FALSE;
}
case DATE_ISO:
if (!($value = date_text2iso($value, $format))) {
form_set_error($fieldname, t('The text \'%s\' is not a valid date.', array(
'%s' => $value,
)));
return FALSE;
}
}
return TRUE;
}
/**
* Date conversion functions
*
* a variety of ways to convert values are provided
* arrays are in the format created by getdate()
* return false for anything that can't produce a valid year
* iso date may have a year only or year and month only
* unix dates must have at least a year month and day
*
* these function return 'ERROR' instead of FALSE because of
* problems distinguishing between a valid 0 value and a FALSE value
*
*/
function date_array2iso($array) {
if (!date_is_valid($array, 'array')) {
return 'ERROR';
}
return sprintf("%04d", intval($array['year'])) . '-' . sprintf("%02d", intval($array['mon'])) . '-' . sprintf("%02d", intval($array['mday'])) . 'T' . sprintf("%02d", intval($array['hours'])) . ':' . sprintf("%02d", intval($array['minutes'])) . ':' . sprintf("%02d", intval($array['seconds']));
}
function date_array2unix($array) {
if (!date_is_valid($array, 'array')) {
return 'ERROR';
}
// a date without a month and day cannot be made into a unix timestamp
if (!$array['mon'] || !$array['mday']) {
return NULL;
}
// using gmmktime instead of mktime so no server timezone adjustment is made
return date_gmmktime($array);
}
function date_iso2array($iso) {
if (!date_preg($iso)) {
return 'ERROR';
}
if (!date_is_valid($iso, DATE_ISO)) {
return 'ERROR';
}
// a unix date requires a year, month, and day
if (date_iso_year($iso) && date_iso_mon($iso) && date_iso_day($iso)) {
$unix = date_iso2unix($iso);
if ($unix === 'ERROR') {
return 'ERROR';
}
else {
return date_unix2array($unix);
}
// an iso date is valid even without a month and/or a day
}
elseif (date_iso_year($iso)) {
return array(
'year' => date_iso_year($iso),
'mon' => date_iso_mon($iso),
'mday' => date_iso_day($iso),
'hours' => date_iso_hours($iso),
'minutes' => date_iso_minutes($iso),
'seconds' => date_iso_seconds($iso),
0 => NULL,
);
}
else {
return 'ERROR';
}
}
function date_unix2array($unix) {
if (!date_is_valid($unix, DATE_UNIX)) {
return 'ERROR';
}
// using gmgetdate instead of getdate so no server timezone adjustment is made
return date_gmgetdate($unix);
}
function date_unix2iso($unix) {
if (!date_is_valid($unix, DATE_UNIX)) {
return 'ERROR';
}
// using gmdate instead of date so no server timezone adjustment is made
return date_gmdate(DATE_STRING_ISO, $unix);
}
function date_iso2unix($iso) {
if (!date_preg($iso)) {
return 'ERROR';
}
if (!date_is_valid($iso, DATE_ISO)) {
return 'ERROR';
}
// A unix date requires a year, month, and day.
// Make sure not to set '0' for month or day since that will revert to
// the previous month or day.
if (date_iso_year($iso)) {
$array = array(
'hours' => date_iso_hours($iso),
'minutes' => date_iso_minutes($iso),
'seconds' => date_iso_seconds($iso),
'mon' => max(1, date_iso_mon($iso)),
'mday' => max(1, date_iso_day($iso)),
'year' => date_iso_year($iso),
);
// using gmmktime instead of mktime so no server timezone adjustment is made
$unix = date_gmmktime($array);
// php versions earlier than 5.1 return -1 for a false response, convert that to 'ERROR'
if ($unix == -1) {
return 'ERROR';
}
return $unix;
}
else {
return NULL;
}
}
function date_iso2custom($iso, $format) {
if ($iso == '') {
return NULL;
}
$array = date_iso2array($iso);
$month_short = array(
"January" => t("Jan"),
"February" => t("Feb"),
"March" => t("Mar"),
"April" => t("Apr"),
"May" => t("May"),
"June" => t("Jun"),
"July" => t("Jul"),
"August" => t("Aug"),
"September" => t("Sep"),
"October" => t("Oct"),
"November" => t("Nov"),
"December" => t("Dec"),
);
$day_short = array(
"Monday" => t("Mon"),
"Tuesday" => t("Tue"),
"Wednesday" => t("Wed"),
"Thursday" => t("Thu"),
"Friday" => t("Fri"),
"Saturday" => t("Sat"),
"Sunday" => t("Sun"),
);
$repl = array(
"d" => str_pad($array['mday'], 2, "0", STR_PAD_LEFT),
"D" => $day_short[$array['weekday']],
"j" => $array['mday'],
"l" => $array['weekday'],
"N" => '',
"S" => '',
"w" => '',
"z" => '',
"W" => '',
"F" => $array['month'],
"m" => str_pad($array['mon'], 2, "0", STR_PAD_LEFT),
"M" => $month_short[$array['month']],
"n" => $array['mon'],
"t" => '',
"L" => '',
"o" => '',
"Y" => str_pad($array['year'], 4, "0", STR_PAD_LEFT),
"y" => substr(str_pad($array['year'], 4, "0", STR_PAD_LEFT), 2, 2),
"a" => $array['hours'] >= 12 ? 'pm' : 'am',
"A" => $array['hours'] >= 12 ? 'PM' : 'AM',
"B" => '',
"g" => $array['hours'] > 12 ? $array['hours'] - 12 : $array['hours'],
"G" => $array['hours'],
"h" => str_pad($array['hours'] > 12 ? $array['hours'] - 12 : $array['hours'], 2, "0", STR_PAD_LEFT),
"H" => str_pad($array['hours'], 2, "0", STR_PAD_LEFT),
"i" => str_pad($array['minutes'], 2, "0", STR_PAD_LEFT),
"s" => str_pad($array['seconds'], 2, "0", STR_PAD_LEFT),
"e" => '',
"I" => '',
"O" => '',
"P" => '',
"T" => '',
"z" => '',
"c" => '',
"r" => '',
"U" => '',
);
$repl["\\\\"] = "\\";
foreach ($repl as $key => $value) {
$repl["\\" . $key] = $key;
}
return strtr($format, $repl);
}
function date_custom2iso($date, $format) {
$array = array(
"d" => "\\d{1,2}",
// we allow 1 to be tolerant - maybe we shouldn't ?
"D" => "\\S{3,4}",
//Using S instead of w to pick up chars like German umlaute
"j" => "\\d{1,2}",
"l" => "\\S*",
//Using S instead of w to pick up chars like German umlaute
"N" => "\\d",
"S" => "\\w{2}",
"w" => "\\d",
"z" => "\\d{1,3}",
"W" => "\\d{1,2}",
"F" => "\\S*",
//Using S instead of w to pick up chars like German umlaute
"m" => "\\d{2}",
"M" => "\\S{3,4}",
//Using S instead of w to pick up chars like German umlaute
"n" => "\\d{1,2}",
"t" => "\\d{2}",
"L" => "\\d",
"o" => "\\d{4}",
"Y" => "\\d{4}",
"y" => "\\d{2}",
"a" => "am|pm",
"A" => "AM|PM",
"B" => "\\d{3}",
"g" => "\\d{1,2}",
"G" => "\\d{1,2}",
"h" => "\\d{1,2}",
// we allow 1 to be tolerant - maybe we shouldn't ?
"H" => "\\d{1,2}",
// we allow 1 to be tolerant - maybe we shouldn't ?
"i" => "\\d{2}",
"s" => "\\d{2}",
"e" => "\\w*",
"I" => "\\d",
"O" => "[+-]?\\d{4}",
"P" => "[+-]?\\d{2}\\:\\d{2}",
"T" => "\\w*",
"z" => "[+-]?\\d*",
"c" => "*",
"r" => "*",
"U" => "\\d*",
);
foreach ($array as $key => $value) {
$patterns[] = "`(^|[^\\\\\\\\])" . $key . "`";
// the letter with no preceding '\'
$repl1[] = '${1}(.)';
// a single character
$repl2[] = '${1}(' . $value . ')';
// the value
}
$patterns[] = "`\\\\\\\\([" . implode(array_keys($array)) . "])`";
$repl1[] = '${1}';
$repl2[] = '${1}';
$format_regexp = preg_quote($format);
// extract letters
$regex1 = preg_replace($patterns, $repl1, $format_regexp, 1);
preg_match('`^' . $regex1 . '$`', stripslashes($format), $letters);
array_shift($letters);
// extract values
$regex2 = preg_replace($patterns, $repl2, $format_regexp, 1);
preg_match('`^' . $regex2 . '$`', $date, $values);
array_shift($values);
// if we did not find all the values for the patterns in the format, abort
if (count($letters) != count($values)) {
return 'ERROR';
}
$final_date['hours'] = "00";
$final_date['minutes'] = "00";
$final_date['seconds'] = "00";
$final_date['mon'] = "00";
$final_date['mday'] = "00";
$final_date['year'] = "0000";
foreach ($letters as $i => $letter) {
$value = $values[$i];
switch ($letter) {
case 'd':
case 'j':
$final_date['mday'] = str_pad($value, 2, "0", STR_PAD_LEFT);
break;
case 'n':
case 'm':
$final_date['mon'] = str_pad($value, 2, "0", STR_PAD_LEFT);
break;
case 'F':
$array_month_long = array(
t('January') => 1,
t('February') => 2,
t('March') => 3,
t('April') => 4,
t('May') => 5,
t('June') => 6,
t('July') => 7,
t('August') => 8,
t('September') => 9,
t('October') => 10,
t('November') => 11,
t('December') => 12,
);
$final_date['mon'] = str_pad($array_month_long[$value], 2, "0", STR_PAD_LEFT);
break;
case 'M':
$array_month = array(
t('Jan') => 1,
t('Feb') => 2,
t('Mar') => 3,
t('Apr') => 4,
t('May') => 5,
t('Jun') => 6,
t('Jul') => 7,
t('Aug') => 8,
t('Sep') => 9,
t('Oct') => 10,
t('Nov') => 11,
t('Dec') => 12,
);
$final_date['mon'] = str_pad($array_month[$value], 2, "0", STR_PAD_LEFT);
break;
case 'Y':
case 'y':
$year = str_pad($value, 2, "0", STR_PAD_LEFT);
// 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);
break;
case 'a':
case 'A':
$am_pm = strtolower($value);
break;
case 'g':
case 'h':
case 'G':
case 'H':
$final_date['hours'] = str_pad($value, 2, "0", STR_PAD_LEFT);
break;
case 'i':
$final_date['minutes'] = str_pad($value, 2, "0", STR_PAD_LEFT);
break;
case 's':
$final_date['seconds'] = str_pad($value, 2, "0", STR_PAD_LEFT);
break;
case 'U':
// TODO ?
break;
}
}
// TODO : add some validation ? day in [1..31], etc...
switch ($am_pm) {
case 'am':
if ($final_date['hours'] == "12") {
$final_date['hours'] = "00";
}
break;
case 'pm':
if ($final_date['hours'] != "12") {
$final_date['hours'] += 12;
}
break;
}
return date_array2iso($final_date);
}
function date_custom2unix($date, $format) {
if ($iso = date_custom2iso($date, $format)) {
if ($unix = date_iso2unix($iso)) {
return $unix;
}
}
return 'ERROR';
}
/**
* Use stringtotime function to create an iso date out of text
*/
function date_text2iso($text, $format) {
// if date supplied in iso format, use it
// TODO : there's probably better to do...
// (do we _want_ to enter ISO formats ? if so we should have it in the input format settings)
if (date_preg($text) && date_part_is_valid(date_iso_year($text), 'year')) {
return $text;
}
// if not iso date, try to parse in the given format
$custom = date_custom2iso($text, $format);
if ($custom !== 'ERROR') {
return $custom;
}
// if custom parsing failed, try strtotime conversion
$iso = date_gmdate(DATE_STRING_ISO, strtotime($text . ' UTC'));
if (date_part_is_valid(date_iso_year($iso), 'year')) {
return $iso;
}
else {
return 'ERROR';
}
}
function date_text2unix($text, $format) {
if ($iso = date_text2iso($text, $format)) {
if ($unix = date_iso2unix($iso)) {
return $unix;
}
}
return 'ERROR';
}
function date_iso_year($iso) {
return (int) substr($iso, 0, 4);
}
function date_iso_mon($iso) {
return (int) substr($iso, 5, 2);
}
function date_iso_day($iso) {
return (int) substr($iso, 8, 2);
}
function date_iso_hours($iso) {
return (int) substr($iso, 11, 2);
}
function date_iso_minutes($iso) {
return (int) substr($iso, 14, 2);
}
function date_iso_seconds($iso) {
return (int) substr($iso, 17, 2);
}
// using gmdate instead of date so no server timezone adjustment is made to provided values
function date_unix_year($unix) {
return (int) date_gmdate('Y', $unix);
}
function date_unix_mon($unix) {
return (int) date_gmdate('m', $unix);
}
function date_unix_day($unix) {
return (int) date_gmdate('d', $unix);
}
function date_unix_hours($unix) {
return (int) date_gmdate('H', $unix);
}
function date_unix_minutes($unix) {
return (int) date_gmdate('i', $unix);
}
function date_unix_seconds($unix) {
return (int) date_gmdate('s', $unix);
}
/**
* Compute min and max dates for an ISO week
*
* based on ISO weeks, which start counting on the first Monday in a week that
* has at least 4 days in the current year
*
* @value - an argument in the format 2006-W20 (year + -W + week number)
* @return an array of ISO dates representing the first and last day in the week
*/
function date_iso_week_range($year, $week) {
// subtract 1 from week number so we don't double-count the final week
$weeks = intval($week - 1);
// get a unix value for the first day of the year
$first_day_of_year = date_iso2unix($year . '-01-01T00:00:00');
// get to the day of week of the first day of the year, 0 is Sunday
$dow = date_gmdate('w', $first_day_of_year);
// ISO week counts actual first week only if it has at least 4 days in it
if ($dow > 2) {
$weeks += 1;
}
// calc adjustment from first day of year dow back or forward to Monday
$shift = intval((1 - $dow) * 86400);
// the day we want is $weeks away from first day of year, adjusted to the Monday of that week by $shift
$first_day_of_week = $first_day_of_year + $weeks * 604800 + $shift;
$last_day_of_week = $first_day_of_week + 604800 - 1;
// convert the unix dates back to iso
return array(
$first_day_of_week,
$last_day_of_week,
);
}
/**
* Find the last day of a month
*
* @param mixed $month
* @param mixed $year
* @return last day of the specified month and year
*/
function date_last_day_of_month($month, $year) {
return date_gmdate('t', date_gmmktime(array(
'year' => intval($year),
'mon' => intval($month),
'mday' => 1,
)));
}
/**
* Functions to test the validity of various date parts
*
* @param $format could be 'array', DATE_UNIX, or DATE_ISO
*/
function date_is_valid($value, $format) {
switch ($format) {
case 'array':
if (!date_part_is_valid($value['year'], 'year') || !date_part_is_valid($value['mon'], 'mon') || !date_part_is_valid($value['mday'], 'mday')) {
return FALSE;
}
return TRUE;
case DATE_UNIX:
if (!date_part_is_valid(date_unix_year($value), 'year') || !date_part_is_valid(date_unix_mon($value), 'mon', 1) || !date_part_is_valid(date_unix_day($value), 'mday', 1)) {
return FALSE;
}
return TRUE;
default:
if (!date_part_is_valid(date_iso_year($value), 'year') || !date_part_is_valid(date_iso_mon($value), 'mon') || !date_part_is_valid(date_iso_day($value), 'mday')) {
return FALSE;
}
return TRUE;
}
}
/**
* Function to test validity of specific date part
*
* @param $value - the value to test
* @param $part - the type of date part provided, coult be 'year', 'mon', or 'mday'
* @parma $min either 0 or 1, use to set min for mon and mday
* can be 0 for iso dates, set to 1 for unix timestamps that require a complete date
*/
function date_part_is_valid($value, $part, $min = 0) {
switch ($part) {
case 'year':
if ($value < DATE_MIN_YEAR || $value > DATE_MAX_YEAR) {
return FALSE;
}
break;
case 'mon':
if ($value < $min || $value > 12) {
return FALSE;
}
break;
case 'mday':
if ($value < $min || $value > 31) {
return FALSE;
}
break;
case 'week':
if ($value < 0 || $value > 53) {
return FALSE;
}
break;
}
return TRUE;
}
/**
* Regex validation for iso date
*/
function date_preg($item) {
if (preg_match('/([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $item)) {
return TRUE;
}
else {
return FALSE;
}
}
/**
* a function to figure out if any time data is to be collected or displayed
*/
function date_has_time($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
return sizeof(array_intersect($granularity, array(
'H',
'N',
'S',
))) > 0 ? TRUE : FALSE;
}
/**
* Function to create an option list for input formats
*
* @return array of date format strings
* with a key of the format string and a value of the current date displayed in that format
*
*/
function date_input_options() {
$formats = array(
'Y-m-d H:i' => 'Y-m-d H:i:s',
'm/d/Y - H:i' => 'm/d/Y - H:i:s',
'd/m/Y - H:i' => 'd/m/Y - H:i:s',
'Y/m/d - H:i' => 'Y/m/d - H:i:s',
'd.m.Y - H:i' => 'd.m.Y - H:i:s',
'm/d/Y - g:ia' => 'm/d/Y - g:i:sa',
'd/m/Y - g:ia' => 'd/m/Y - g:i:sa',
'Y/m/d - g:ia' => 'Y/m/d - g:i:sa',
'M j Y - H:i' => 'M j Y - H:i:s',
'j M Y - H:i' => 'j M Y - H:i:s',
'Y M j - H:i' => 'Y M j - H:i:s',
'M j Y - g:ia' => 'M j Y - g:i:sa',
'j M Y - g:ia' => 'j M Y - g:i:sa',
'Y M j - g:ia' => 'Y M j - g:i:sa',
);
$options = array();
$options['site-wide'] = t('default') . ' (' . format_date(time(), 'custom', $formats[variable_get('date_format_short', 'm/d/Y - H:i')]) . ')';
foreach (array_values($formats) as $f) {
$options[$f] = format_date(time(), 'custom', $f);
}
return $options;
}
/**
* Function to create an option list that will display various date and time formats
*
* @param $tz_handling - default is 'site'
* @param $illustration_date - an iso date to use for illustration of the date options
* default date for illustration: August 1 YYYY 2:05:10 PM
* - single digit months and days to see leading zeros
* - a month number different than the day number to see month and day positions
* - an afternoon time to illustrate 24 hours vs am/pm formats
*
* @return array of date format strings for all date_date_options() and/or date_time_options()
* with a key of the format string and a value of the illustration date displayed in that format
*
*/
function date_output_options($tz_handling = 'site', $illustration_date = NULL) {
$illustration_date = $illustration_date ? $illustration_date : date_gmdate('Y', time()) . '-08-01T14:05:10';
$date = date_make_date($illustration_date, date_get_timezone($tz_handling), 'local', DATE_ISO);
// from system module, possible date formats
$dateshort = 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',
);
$datemedium = 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',
);
$datelong = 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',
);
$datestrings = array_merge($dateshort, $datemedium, $datelong);
$view = array();
foreach ($datestrings as $datestring) {
$parts = explode(' - ', $datestring);
// create an option that shows date only without time
$view[trim($parts[0])] = date_show_date($date, trim($parts[0]));
$view[$datestring] = date_show_date($date, $datestring);
}
asort($view);
return $view;
}
function date_formats($format, $granularity) {
//split date part and time part
preg_match("/([djDlzwWmnFMYy].*[djDlzwWmnFMYy])/", $format, $matches, PREG_OFFSET_CAPTURE);
$format_date = $matches[1][0];
$format_date_pos = $matches[1][1];
preg_match("/([gGhHisaA].*[gGhHisaA])/", $format, $matches, PREG_OFFSET_CAPTURE);
$format_time = $matches[1][0];
$format_time_pos = $matches[1][1];
$format_separator = substr($format, $format_date_pos + strlen($format_date), $format_time_pos - ($format_date_pos + strlen($format_date)));
$jscal_format_date = $jscal_format_time = array();
$text_format_date = $text_format_time = array();
$select_format_date = array();
$weight_index = 0;
$desc_date = array();
$desc_time = array();
$format_to_jscalendar = array(
'd' => '%d',
'j' => '%e',
'D' => '%a',
'l' => '%A',
'z' => '%j',
'w' => '%w',
'W' => '%U',
'm' => '%m',
'n' => '%m',
'F' => '%B',
'M' => '%b',
'Y' => '%Y',
'y' => '%y',
'g' => '%l',
'G' => '%k',
'h' => '%I',
'H' => '%H',
'i' => '%M',
's' => '%S',
'a' => '%P',
'A' => '%p',
);
foreach (preg_split('//', $format_date, -1, PREG_SPLIT_NO_EMPTY) as $c) {
switch ($c) {
case 'd':
case 'j':
if (in_array('D', $granularity)) {
$jscal_format_date[] = $format_to_jscalendar[$c];
$text_format_date[] = $c;
$select_format_date['D'] = $weight_index++;
}
if ($c == 'd') {
$desc_date[] = 'DD';
}
if ($c == 'j') {
$desc_date[] = 'D';
}
break;
case 'F':
case 'M':
case 'm':
case 'n':
if (in_array('M', $granularity)) {
$jscal_format_date[] = $format_to_jscalendar[$c];
$text_format_date[] = $c;
$select_format_date['M'] = $weight_index++;
}
if ($c == 'M') {
$desc_date[] = t('Jan');
}
if ($c == 'm') {
$desc_date[] = 'MM';
}
if ($c == 'n') {
$desc_date[] = 'M';
}
if ($c == 'F') {
$desc_date[] = t('January');
}
break;
case 'Y':
case 'y':
if (in_array('Y', $granularity)) {
$jscal_format_date[] = $format_to_jscalendar[$c];
$text_format_date[] = $c;
$select_format_date['Y'] = $weight_index++;
}
if ($c == 'Y') {
$desc_date[] = 'YYYY';
}
if ($c == 'y') {
$desc_date[] = 'YY';
}
break;
default:
if (!preg_match('/[a-zA-Z]/', $c) && !isset($date_separator)) {
$date_separator = $c;
}
break;
}
}
if (date_has_time($granularity)) {
foreach (preg_split('//', $format_time, -1, PREG_SPLIT_NO_EMPTY) as $c) {
switch ($c) {
case 'g':
case 'G':
case 'h':
case 'H':
if (in_array('H', $granularity)) {
$jscal_format_time[] = $format_to_jscalendar[$c];
$text_format_time[] = $c;
}
if ($c == 'g' || $c == 'h') {
$desc_time[] = 'H';
}
if ($c == 'G' || $c == 'H') {
$desc_time[] = 'HH';
}
break;
case 'i':
if (in_array('N', $granularity)) {
$jscal_format_time[] = $format_to_jscalendar[$c];
$text_format_time[] = $c;
}
$desc_time[] = 'MM';
break;
case 's':
if (in_array('S', $granularity)) {
$jscal_format_time[] = $format_to_jscalendar[$c];
$text_format_time[] = $c;
}
$desc_time[] = 'SS';
break;
case 'a':
case 'A':
if (date_has_time($granularity)) {
$jscal_format_ampm = $format_to_jscalendar[$c];
$text_format_ampm = $c;
$am_pm = true;
}
if ($c == 'a') {
$desc_time[] = 'am';
}
if ($c == 'A') {
$desc_time[] = 'AM';
}
break;
default:
if (!preg_match('/[a-zA-Z]/', $c) & !isset($time_separator)) {
$time_separator = $c;
}
break;
}
}
}
// we store the current site-wide value, in order to be able to detect its changes
if ($format == 'site-wide' || $format == variable_get('date_format_short', 'm/d/Y - H:i')) {
$formats['input']['site-wide'] = $format;
}
$formats['input']['jscal'] = implode($date_separator, $jscal_format_date);
$formats['input']['jscal'] .= date_has_time($granularity) ? $format_separator . implode($time_separator, $jscal_format_time) . $jscal_format_ampm : '';
$formats['input']['text'] = implode($date_separator, $text_format_date);
$formats['input']['text'] .= date_has_time($granularity) ? $format_separator . implode($time_separator, $text_format_time) . $text_format_ampm : '';
$formats['input']['select'] = $select_format_date;
$formats['input']['am_pm'] = $am_pm;
$formats['input']['desc'] = implode($date_separator, $desc_date);
$formats['input']['desc'] .= date_has_time($granularity) ? $format_separator . implode($time_separator, $desc_time) : '';
return $formats;
}
/**
* An difference array of granularity elements that are NOT in the granularity array.
*/
function date_nongranularity_array($granularity) {
return array_diff(array(
'Y',
'M',
'D',
'H',
'N',
'S',
), $granularity);
}
/**
* Unset undesired date part values.
*/
function date_unset_granularity($item, $granularity, $type) {
if (!($nongranularity = date_nongranularity_array($granularity))) {
return $item;
}
else {
if ($type == DATE_ISO) {
$date = date_iso2array($item);
}
else {
$date = date_unix2array($item);
}
foreach ($nongranularity as $level) {
switch ($level) {
case 'S':
$date['seconds'] = 0;
break;
case 'N':
$date['minutes'] = 0;
break;
case 'H':
$date['hours'] = 0;
break;
case 'M':
$date['mon'] = $type == DATE_UNIX ? 1 : 0;
break;
case 'D':
$date['mday'] = $type == DATE_UNIX ? 1 : 0;
break;
}
}
if ($type == DATE_ISO) {
return date_array2iso($date);
}
else {
return date_array2unix($date);
}
}
}
/**
* Strip date parts that are not in the granularity array out of a date format string.
*/
function date_strip_granularity($format, $granularity) {
$replace = array();
foreach (date_nongranularity_array($granularity) as $element) {
switch ($element) {
case 'D':
$replace = array_merge($replace, array(
'l,',
'l',
'D,',
'D-',
'D/',
'D',
'd,',
'd-',
'd/',
'd',
'j,',
'j-',
'j/',
'j',
));
break;
case 'M':
$replace = array_merge($replace, array(
'F,',
'F-',
'F/',
'F',
'M,',
'M-',
'M/',
'M',
'm,',
'm-',
'm/',
'm',
'n,',
'n-',
'n/',
'n',
));
break;
case 'H':
$replace = array_merge($replace, array(
'H:',
'H',
'h:',
'h',
'G:',
'g:',
'g',
'a',
'A',
' - ',
));
break;
case 'N':
$replace = array_merge($replace, array(
'i:',
'i',
));
break;
case 'S':
$replace = array_merge($replace, array(
's',
));
break;
}
}
return str_replace($replace, '', $format);
}
/**
* Convert date() to strftime() format strings
*
* @param $format - a format string for date()
* @return corresponding format string for strftime()
*/
function date_date2strftime($format) {
return strtr($format, date_date2strftime_replace());
}
/**
* Date() to strftime() replacement array
*
* Adjusted for differences between unix and windows strftime()
*
* Not all date formats have corresponding strftime formats
* Trying for best match or blank for no match
*/
function date_date2strftime_replace() {
static $replace = array();
if (empty($replace)) {
if (stristr(PHP_OS, 'WIN')) {
$type = 'windows';
}
else {
$type = 'unix';
}
$replace = array(
'd' => '%d',
// day of month, leading zero
'j' => $type == 'unix' ? '%e' : '%#d',
// day of month, no leading zero
'F' => '%B',
// full month name
'M' => '%b',
// month abbreviation
'm' => '%m',
// month number, leading zero
'n' => $type == 'unix' ? '%m' : '%#m',
// month number, no leading zero
'Y' => '%Y',
// year, 4 digit
'y' => '%y',
// year, 2 digit
'l' => '%A',
// full day name
'D' => '%a',
// abbreviated day name
'w' => '%w',
// dow, 0 for sunday
'N' => '%u',
// dow, 7 for sunday
'H' => '%H',
// 24 hour hour, leading zero
'h' => '%I',
// 12 hour hour, leading zero
'G' => type == 'unix' ? '%H' : '%#H',
// 24 hour hour, no leading zero
'g' => type == 'unix' ? '%I' : '%#I',
// 12 hour hour, no leading zero
'i' => '%M',
// minutes, leading zero
's' => '%S',
// seconds, leading zero
'a' => '%p',
// am/pm lowercase(strftime windows is only upppercase)
'A' => '%p',
// am/pm capitalized (striftime unix is only lowercase)
'W' => '%V',
// ISO week number of year, starting on first Monday
'o' => '%G',
// ISO year that matches ISO week
'T' => '%Z',
// server timezone name
'r' => $type == 'unix' ? '%c' : '%#c',
// formatted complete date and time (Thu, 21 Dec 2000 16:01:07)
/* date formats with no good strftime match */
'z' => '',
// day of year (0-365), strftime equivalent %j uses 1-365
'S' => '',
// day of month ordinal like st, nd, rd
't' => '',
// number of days in month, 28-31
'L' => '',
// leap year, 0 or 1
'I' => '',
// daylight savings time, 0 or 1
'B' => '',
// Swatch internet time, 000-999
'e' => '',
// server timezone identifier like US/Eastern
'O' => '',
// server timezone to gmt offset (+0200)
'P' => '',
// server timezone to gmt offset (+02:00)
'Z' => '',
// server timezone to gmt offset in seconds
'U' => '',
// seconds since Unix Epoch
'c' => '',
);
}
return $replace;
}
/**
* Server timezone adjustment.
*
* Used to compute default timezone adjustment made by SQL server
* so server adjustment can be removed and replaced with correct timezone
* adjustment values.
*
* @return amount in seconds that server adjusts for timezone.
*/
function date_server_zone_adj() {
global $db_type;
static $server_zone_adj;
if (!isset($server_zone_adj)) {
switch ($db_type) {
case 'mysql':
case 'mysqli':
// Newest MYSQL versions allow us to set the server to GMT to eliminate adjustments.
if ($GLOBALS['db_type'] == 'mysqli' || version_compare(mysql_get_server_info(), '4.1.3', '>=')) {
db_query("SET @@session.time_zone = '+00:00'");
$server_zone_adj = 0;
}
elseif (version_compare(mysql_get_server_info(), '4.1.1', '>=')) {
$server_zone_adj = db_result(db_query("SELECT UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(UTC_TIMESTAMP())"));
}
else {
$server_zone_adj = date('Z');
}
break;
case 'pgsql':
// EXTRACT TIMEZONE returns the timezone adjustment in seconds.
$server_zone_adj = db_result(db_query("SELECT EXTRACT('TIMEZONE' FROM NOW())"));
break;
}
// If no value got set by this point,
// fall back to using php timezone adjustment as an estimate.
if (!isset($server_zone_adj)) {
$server_zone_adj = date('Z');
}
}
return $server_zone_adj;
}
/**
* Cross-database date SQL wrapper function
* allows use of normalized native date functions in both mysql and postgres.
* Designed to be extensible to other databases.
*
* @param $result_type - NOW, DATE, YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DOW, DOY, WEEK
* @param $field - the name of the date field to be analyzed
* @param $date_type - the type of date field being analyzed, int or iso
* @param $offset - timezone offset in seconds, can be either a value or fieldname
* @param $offset_op - the operation to perform on the offset, + or -
* @return a SQL statement appropriate for the $db_type
*
* example: date_sql('WEEK', 'MYFIELD', 'int', 'MYOFFSETFIELD', '+')
* mysql returns: WEEK(FROM_UNIXTIME(MYFIELD) + INTERVAL MYOFFSETFIELD SECOND, 3)
* postgres returns: EXTRACT(WEEK FROM(TIMESTAMP(MYFIELD::ABSTIME::INT4) + INTERVAL MYOFFSETFIELD SECONDS))
*/
function date_sql($result_type, $field, $date_type = 'int', $offset = '', $offset_op = '+') {
global $db_type;
// NOW() is timezone-adjusted by OS, adjust only for the server adj,
// correct offset will get added back in later step.
if ($date_type == 'NOW' || $field == 'NOW()') {
switch ($db_type) {
case 'mysql':
case 'mysqli':
if (date_server_zone_adj()) {
$field = "(NOW() - INTERVAL " . date_server_zone_adj() . " SECOND)";
}
break;
case 'pgsql':
if (date_server_zone_adj()) {
$field = "(NOW() - INTERVAL '" . date_server_zone_adj() . " SECONDS')";
}
break;
}
}
elseif ($date_type == 'int' && $field) {
switch ($db_type) {
case 'mysql':
case 'mysqli':
$field = "FROM_UNIXTIME({$field})";
if (date_server_zone_adj()) {
$field = "({$field} - INTERVAL " . date_server_zone_adj() . " SECOND)";
}
break;
case 'pgsql':
$field = "({$field}::ABSTIME)";
if (date_server_zone_adj()) {
$field = "({$field} - INTERVAL '" . date_server_zone_adj() . " SECONDS')";
}
break;
}
}
elseif ($date_type == 'iso' && $field) {
$field = " REPLACE({$field},'T',' ')";
}
// Now apply requested offset to the adjusted query field.
if ($offset) {
switch ($db_type) {
case 'mysql':
case 'mysqli':
$field = "({$field} {$offset_op} INTERVAL ({$offset}) SECOND)";
break;
case 'pgsql':
$field = "({$field} {$offset_op} INTERVAL '{$offset} SECONDS')";
break;
}
}
// Return requested sql.
// Note there is no space after FROM to avoid db_rewrite problems
// see http://drupal.org/node/79904.
switch ($result_type) {
case 'NOW':
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}))";
case 'WEEK':
// ISO week number for date
switch ($db_type) {
case 'mysql':
case 'mysqli':
// 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}))";
}
case 'DOW':
switch ($db_type) {
case 'mysql':
case 'mysqli':
// 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}))";
}
case 'DOY':
switch ($db_type) {
case 'mysql':
case 'mysqli':
return "DAYOFYEAR({$field})";
case 'pgsql':
return "EXTRACT (DOY FROM ({$field}))";
}
}
}
/**
* A helper function to do cross-database concatation of date parts
*
* @param $array - an array of values to be concatonated in sql
* @return - correct sql string for database type
*/
function date_sql_concat($array) {
global $db_type;
switch ($db_type) {
case 'mysql':
case 'mysqli':
return "CONCAT(" . implode(",", $array) . ")";
case 'pgsql':
return implode(" || ", $array);
}
}
/**
* A helper function to do cross-database padding of date parts
*
* @param $str - a string to apply padding to
* @param $size - the size the final string should be
* @param $pad - the value to pad the string with
* @param $side - the side of the string to pad
*/
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}')";
}
}
/**
* Themes for date input form elements
*/
/**
* Date selector form
*
* $form contains the whole date selector form.
* Make any changes needed, render it, and return the result.
*
*/
function theme_date_form_select($form) {
$form['#type'] = 'fieldset';
return drupal_render($form);
}
/**
* Date selector description
*
* $form contains the description added to the date selector.
* Make any changes needed, render it, and return the result.
*/
function theme_date_form_select_description($form) {
$description = drupal_render($form);
if ($description) {
return '<br class="clear" /><div class="description"><div class="form-item">' . $description . '</div></div>';
}
return '';
}
/**
* Text input form
*
* $form contains a text input form.
* Make any changes needed, render it, and return the result.
*/
function theme_date_form_text($form) {
return drupal_render($form);
}
/**
* jsCalendar input form
*
* $form contains a jscalendar input form.
* Make any changes needed, render it, and return the result.
*/
function theme_date_form_jscalendar($form) {
return drupal_render($form);
}
/**
* Timezone input form
*
* $form contains a timzone input form.
* Make any changes needed, render it, and return the result.
*/
function theme_date_form_timezone($form) {
return drupal_render($form);
}
/**
* 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 granularity options and their lables
*
* @return array
*/
function date_granularity_names() {
return array(
'Y' => t('Year'),
'M' => t('Month'),
'D' => t('Day'),
'H' => t('Hour'),
'N' => t('Minute'),
'S' => t('Second'),
);
}
/**
* Array of granularity keys and the names of the related array parts.
*
* @return array
*/
function date_granularity_parts() {
return array(
'Y' => 'year',
'M' => 'mon',
'D' => 'mday',
'H' => 'hours',
'N' => 'minutes',
'S' => 'seconds',
);
}
/**
* Rewrite a format string so it only inludes elements from a
* specified granularity array.
*
* Example, turn 'F j, Y - H:i' into 'F j, Y'
*
* @param $format
* a format string
* @param $granularity
* an array of allowed date parts, all others will be removed
* array('Y', 'M', 'D', 'H', 'N', 'S');
* @return
* a format string with all other elements removed
*/
function date_limit_format($format, $granularity) {
$regex = array();
// Get rid of dash separating date and time if either is missing.
if (!date_has_time($granularity) || sizeof(array_intersect($granularity, array(
'Y',
'M',
'D',
)) == 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 'Y':
$regex[] = '([\\-/\\.]?[Yy][\\-/\\.,]?)';
break;
case 'D':
$regex[] = '([\\-/\\.]?[lDdj][\\-/\\.,]?)';
break;
case 'M':
$regex[] = '([\\-/\\.]?[FMmn][\\-/\\.,]?)';
break;
case 'H':
$regex[] = '([HhGg][:]?)';
break;
case 'N':
$regex[] = '([:]?[i])';
break;
case 'S':
$regex[] = '([:]?[s])';
break;
}
}
// Remove selected values from string.
// Don't leave any trailing punctuation behind.
$format = trim(preg_replace($regex, array(), $format));
return preg_replace('([\\-/\\.,]$)', '', $format);
}
/**
* 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 ('Y', 'M', 'D', 'H', 'N', 'S');
*/
function date_nongranularity($granularity) {
return array_diff(array(
'Y',
'M',
'D',
'H',
'N',
'S',
), $granularity);
}
Functions
Name | Description |
---|---|
date_adj_zone | These functions will remove server timezone adjustment from timestamps needed because some php date functions automatically adjust to server zone but the date object uses raw values for date parts and does manual timezone adj needed for ability to… |
date_append_zone | A function to append the zone offset or name to a display |
date_append_zone_options | |
date_array2iso | Date conversion functions |
date_array2unix | |
date_convert_timezone | Timezone conversion function |
date_custom2iso | |
date_custom2unix | |
date_date | |
date_date2strftime | Convert date() to strftime() format strings |
date_date2strftime_replace | Date() to strftime() replacement array |
date_formats | |
date_format_date | Format date |
date_fuzzy_stamp | Create a valid timestamp that can be used for date formatting even if only partial date info is available, i.e. for an iso date with month and year only |
date_getdate | |
date_get_site_timezone | Get system variable setting for site default timezone |
date_get_timezone | Function to figure out which timezone applies to a date and select it |
date_gmadj_zone | |
date_gmdate | |
date_gmgetdate | We need a gmgetdate function, which does not exist because the getdate function creates an array where date parts and timestamp don't match getdate date parts are timezone-adjusted to the server zone and timestamp is not we need an array where… |
date_gmmktime | |
date_gmstrftime | |
date_granularity_names | Array of granularity options and their lables |
date_granularity_parts | Array of granularity keys and the names of the related array parts. |
date_has_time | a function to figure out if any time data is to be collected or displayed |
date_input_options | Function to create an option list for input formats |
date_iso2array | |
date_iso2custom | |
date_iso2unix | |
date_iso_day | |
date_iso_hours | |
date_iso_minutes | |
date_iso_mon | |
date_iso_seconds | |
date_iso_week_range | Compute min and max dates for an ISO week |
date_iso_year | |
date_is_valid | Functions to test the validity of various date parts |
date_jscalendar_make_dbdate | Construct a value to save to the database from jscalendar input |
date_jscalendar_validate | Validation for jscalendar input |
date_last_day_of_month | Find the last day of a month |
date_limit_format | Rewrite a format string so it only inludes elements from a specified granularity array. |
date_load_library | Date wrapper functions |
date_long_formats | An array of long date formats. |
date_make_date | Function to create a date object |
date_medium_formats | An array of medium date formats. |
date_mktime | |
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_nongranularity_array | An difference array of granularity elements that are NOT in the granularity array. |
date_no_conversion | Function to identify dates that must never have timezone conversion. |
date_offset | A function to calculate offset using timezone.inc file |
date_output_options | Function to create an option list that will display various date and time formats |
date_part_is_valid | Function to test validity of specific date part |
date_preg | Regex validation for iso date |
date_selector_make_dbdate | Construct a value to save to the database from the date selector |
date_selector_validate | Validation function for date selector $params = an array of values including: required = is a valid date required, default is true opt_fields = an array of fields that need not be filled out, default is empty array |
date_select_input | Flexible Date/Time Drop-Down Selector |
date_server_zone_adj | Server timezone adjustment. |
date_set_date | Function to set local and db date parts in the date object |
date_set_site_timezone | Set system variable for site default timezone Needed because current system variable tracks offset rather than timezone |
date_short_formats | An array of short date formats. |
date_show_date | A function to display formatted output for the date object |
date_show_value | A function to display the database value for the date object |
date_sql | Cross-database date SQL wrapper function allows use of normalized native date functions in both mysql and postgres. Designed to be extensible to other databases. |
date_sql_concat | A helper function to do cross-database concatation of date parts |
date_sql_pad | A helper function to do cross-database padding of date parts |
date_strftime | |
date_strip_granularity | Strip date parts that are not in the granularity array out of a date format string. |
date_text2iso | Use stringtotime function to create an iso date out of text |
date_text2unix | |
date_text_input | Text date input form, with optional jscalendar popup |
date_text_make_dbdate | Construct a value to save to the database from text input |
date_text_validate | Validation for text input |
date_time | Implementation of time() adjusted for the current site and user. |
date_timezone_handling_options | Timezone handling options omitting user option for now because we only know the user's offset at best, not their timezone come back later and enable this option if there is a way to collect and save user timezones |
date_timezone_input | Timezone input form |
date_timezone_options | Time zone option list |
date_unix2array | |
date_unix2iso | |
date_unix_day | |
date_unix_hours | |
date_unix_minutes | |
date_unix_mon | |
date_unix_seconds | |
date_unix_year | |
date_unset_granularity | Unset undesired date part values. |
theme_date_form_jscalendar | jsCalendar input form |
theme_date_form_select | Date selector form |
theme_date_form_select_description | Date selector description |
theme_date_form_text | Text input form |
theme_date_form_timezone | Timezone input form |