Development

#26 ([PATCH] New form helper functionality for dates)

You must first sign up to be able to contribute.

Ticket #26 (closed enhancement: fixed)

Opened 8 years ago

Last modified 7 years ago

[PATCH] New form helper functionality for dates

Reported by: acidbox Assigned to:
Priority: minor Milestone: 0.6.1
Component: Version: 0.6.0
Keywords: date time select helper Cc:
Qualification:

Description

I think it would be a great addition to the FormHelper? to have the ability to create a select_day_tag, select_month_tag, select_year_tag and a consolodated select_date_tag helper. I coded up the preliminary methods for this (below), and have tested them with the latest beta.

Things I haven't done - I did not add I18N for the date formats - Built the function to convert the select_date_tag to a timestamp for insertion - Accounted for dates pre-1970 (I recommend the ADODB Time Library).

Let me know if I can help you with any of the code here.

function select_day_tag($name, $value, $options = "")
{
	$data = array();
	for ($x = 1; $x < 32; $x++)
	{
		$data[((strlen($x < 2)) ? 0 . $x : $x)] = date($output, strtotime(date("Y") . "-" . 12 . "-" . $x));
	}
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_month_tag($name, $value, $options = "")
{
	$data = array();
	for ($x = 1; $x < 13; $x++)
	{
		$data[((strlen($x < 2)) ? 0 . $x : $x)] = date("n", strtotime(date("Y") . "-" . ((strlen($x < 2)) ? 0 . $x : $x) . "-" . 01));
	}
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_year_tag($name, $value, $options = "")
{
	$options['year_start'] = (!empty($options['year_start']) AND is_numeric($options['year_start'])) ? $options['year_start'] : date("Y") - 10;
	$options['year_end'] = (!empty($options['year_end']) AND is_numeric($options['year_end'])) ? $options['year_end'] : date("Y");
	
	$data = array();
	for ($x = $options['year_start']; $x < ($options['year_end'] + 1); $x++)
	{
		$data[$x] = $x;
	}
	
	unset($options['year_start'], $options['year_end']);
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_date_tag($name, $value, $options = "")
{
	//Culture is not implemented yet (default for now is mm/dd/yyyy)
	$day = ($options['discard_day'] != true) ? select_day_tag($name . '_day', date('d', strtotime($value)), $options) : "";
	if (isset($options['discard_day']))
	{
		unset($options['discard_day']);
	}
	$month = select_month_tag($name . '_month', date('m', strtotime($value)), $options);
	$year = select_year_tag($name . '_year', $value, $options);

	return $month . $day . $year;
			
}

Attachments

date_select.patch (9.2 kB) - added by brujahRg on 03/08/06 12:26:54.
tidied up the code. patch against r954

Change History

11/07/05 09:01:54 changed by acidbox

11/07/05 09:09:28 changed by acidbox

11/07/05 09:14:46 changed by acidbox

Sample Usage:

<?php echo(select_month_tag('month', 4)); ?> <?php echo(select_day_tag('day', 15)); ?> <?php echo(select_year_tag('year', 2001, array('year_start' => 1969, 'year_end' => 2007))); ?>

<?php echo(select_date_tag('date', '2005-04-01')); ?>

11/07/05 19:06:18 changed by acidbox

Added the time helpers as well as did some modifications to the date helpers to add some additional functionality. Sorry for the lack of comments.

I created the "add_zeros" function to just prepend a zero on short strings. It probably doesn't belong in the helper file, but I wasn't sure where you'd want it, or if you already have a function that does the same thing. So you might want to move it somewhere else and update the calls from each helper or replace what I made with something you already have.

function add_zeros($string, $strlen)
{
	if ($strlen > strlen($string))
	{
		for ($x = strlen($string); $x < $strlen; $x++)
		{
			$string = "0" . $string;
		}
	}
		
	return $string;
}

function select_day_tag($name, $value, $options = "")
{
	$data = array();
	for ($x = 1; $x < 32; $x++)
	{
		$data[add_zeros($x, 2)] = date("d", strtotime(date("Y") . "-" . 12 . "-" . $x));
	}
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_month_tag($name, $value, $options = "")
{
	$data = array();
	
	if ($options['use_short_month'] == true)
	{
		$date_format = "M";
	}
	elseif ($options['use_long_month'] == true)
	{
		$date_format = "F";
	}
	else
	{
		$date_format = "m";
	}
	
	for ($x = 1; $x < 13; $x++)
	{
		$data[add_zeros($x, 2)] = date($date_format, strtotime(date("Y") . "-" . add_zeros($x, 2) . "-" . 01));
	}
	
	if (isset($options['use_short_month']))
	{
		unset($options['use_short_month']);
	}
	
	if (isset($options['use_long_month']))
	{
		unset($options['use_long_month']);
	}
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_year_tag($name, $value, $options = "")
{
	$options['year_start'] = (!empty($options['year_start']) AND is_numeric($options['year_start'])) ? $options['year_start'] : date("Y") - 10;
	$options['year_end'] = (!empty($options['year_end']) AND is_numeric($options['year_end'])) ? $options['year_end'] : date("Y");
	
	$data = array();
	for ($x = $options['year_start']; $x < ($options['year_end'] + 1); $x++)
	{
		$data[$x] = $x;
	}
	
	unset($options['year_start'], $options['year_end']);
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper date format YYYY-MM-DD)
 * @param array $options
 * @return string
 */
function select_date_tag($name, $value, $options = "")
{
	//Culture is not implemented yet (default for now is mm/dd/yyyy)
	$day = ($options['discard_day'] != true) ? select_day_tag($name . '_day', date('d', strtotime($value)), $options) : "";

	$month = select_month_tag($name . '_month', date('m', strtotime($value)), $options);
	$year = select_year_tag($name . '_year', $value, $options);

	if (isset($options['date_seperator']))
	{
		$date = $month . $options['date_seperator'] . (($options['discard_day'] != true) ? $day . $options['date_seperator'] : "") . $year;
	}
	else
	{
		$date = $month . $day . $year;
	}
	
	if (isset($options['discard_day']))
	{
		unset($options['discard_day']);
	}
	
	if (isset($options['date_seperator']))
	{
		unset($options['date_seperator']);
	}
	
	return $date;
			
}

function select_second_tag($name, $value, $options = "")
{
	$data = array();
	for ($x = 0; $x < 60; ((is_numeric($options['second_step'])) ? $x = $x + $options['second_step'] : $x++))
	{
		$data[add_zeros($x, 2)] = $x;
	}
	
	if (isset($options['second_step']))
	{
		unset($options['second_step']);
	}	
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_minute_tag($name, $value, $options = "")
{
	$data = array();
	
	for ($x = 0; $x < 60; ((is_numeric($options['minute_step'])) ? $x = $x + $options['minute_step'] : $x++))
	{
		$data[add_zeros($x, 2)] = $x;
	}
	
	if (isset($options['minute_step']))
	{
		unset($options['minute_step']);
	}
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

function select_hour_tag($name, $value, $options = "")
{
	$data = array();
	for ($x = 1; $x < (($options['24hour_time'] == true) ? 24 : 13); $x++)
	{
		$data[add_zeros($x, 2)] = $x;
	}
	
	if (isset($options['24hour_time']))
	{
		unset($options['24hour_time']);
	}
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}

/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper time format HH:MM:SS)
 * @param array $options
 * @return string
 */
function select_time_tag($name, $value, $options = "")
{
	$hour = select_hour_tag($name . "_hour" , date((($options['24hour_time'] == true) ? "H" : "h"), strtotime($value)), $options);
	$minute = select_minute_tag($name . "_minute" , date("i", strtotime($value)), $options);
	if ($options['include_second'] == true)
	{
		$second = select_second_tag($name . "_second" , date("s", strtotime($value)), $options);
	}
	
	if (isset($options['time_seperator']))
	{
		$time = $hour . $options['time_seperator'] . $minute . (($options['include_second'] == true) ? $options['time_seperator'] .  $second : "");
		unset($options['time_seperator']);
	}
	else 
	{
		$time = $hour . $minute . (($options['include_second'] == true) ? $second : "");
	}
	
	if ($options['include_second'] == true)
	{
		unset($options['include_second']);
	}
	
	return $time;
}

/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper datetime format YYYY-MM-DD HH:MM:SS)
 * @param array $options
 * @return string
 */
function select_datetime_tag($name, $value, $options = "")
{
	$date = select_date_tag($name, $value, $options);
	$time = select_time_tag($name, $value, $options);
	
	if (isset($options['datetime_seperator']))
	{
		$datetime = $date . $options['datetime_seperator'] . $time;
		unset($options['datetime_seperator']);
	}
	else
	{
		$datetime = $date . $time;
	}
	
	return $datetime;
}
example usage:

<?php echo(select_month_tag('month', 4)); ?>
<?php echo(select_day_tag('day', 15)); ?>
<?php echo(select_year_tag('year', 2001, array('year_start' => 1969, 'year_end' => 2007))); ?>
<br />
<?php echo(select_date_tag('date', '2005-04-01')); ?>
<br />
<?php echo(select_hour_tag('hour', 4)); ?>
<?php echo(select_minute_tag('minute', 15, array('minute_step' => 15))); ?>
<?php echo(select_second_tag('second', 30, array('second_step' => 15))); ?>
<br />
<?php echo(select_time_tag('time', '', array('minute_step' => 15, 'include_second' => true, 'second_step' => 15, 'time_seperator' => ' : '))); ?>
<br />
<?php echo(select_datetime_tag('datetime', '2005-05-15 08:30:30', array('minute_step' => 15, 'include_second' => true, 'second_step' => 15, 'datetime_seperator' => '<br />', 'date_seperator' => ' / ', 'time_seperator' => ' : '))); ?>

11/07/05 19:11:37 changed by acidbox

Things to consider for the future:

- Localization for culture (Presentation)
- Localization for language on long dates (i.e. January vs Janvier)
- Timezone offsets
- rich javascript calendar integration
- Handling of pre 1970 dates

11/08/05 22:17:18 changed by RoVeRT <rovert@rovert.net>

What about using sprintf to prepend the 0, sprintf('%02d', $x) results in 02 for 2.

11/09/05 15:46:08 changed by acidbox

I thought about that at first. But, having a function that will prepend zeros on any string seems to be a better choice. In rails, there is a function called leading_zero_on_single_digits() which basically does the same thing. I'm thinking that the add_zeros function should be included in the core so it can be used with other things than just the helper.

What do you think?

11/10/05 17:20:07 changed by acidbox

I added a select_ampm_tag to the above time helpers. The only other function that had to be updated was the select_time_tag, so that's updated as well.

Code

function select_ampm_tag($name, $value, $options = "")
{
	$data = array('AM' => 'AM', 'PM' => 'PM');
	
	$option_tags = options_for_select($data, $value);
	
	return select_tag($name, $option_tags, $options);
}


/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper time format HH:MM:SS)
 * @param array $options
 * @return string
 */
function select_time_tag($name, $value, $options = "")
{
	$hour = select_hour_tag($name . "_hour" , date((($options['24hour_time'] == true) ? "H" : "h"), strtotime($value)), $options);
	$minute = select_minute_tag($name . "_minute" , date("i", strtotime($value)), $options);
	if ($options['include_second'] == true)
	{
		$second = select_second_tag($name . "_second" , date("s", strtotime($value)), $options);
	}
	
	if ($options['include_ampm'] == true)
	{
		$ampm = select_ampm_tag($name . "_ampm" , date("A", strtotime($value)), $options);
	}
	
	if (isset($options['time_seperator']))
	{
		$time = $hour . $options['time_seperator'] . $minute . (($options['include_second'] == true) ? $options['time_seperator'] .  $second : "") . (($options['include_ampm'] == true) ? " "  .  $ampm : "");
		unset($options['time_seperator']);
	}
	else 
	{
		$time = $hour . $minute . (($options['include_second'] == true) ? $second : "");
	}
	
	if ($options['include_second'] == true)
	{
		unset($options['include_second']);
	}
	
	if ($options['include_ampm'] == true)
	{
		unset($options['include_ampm']);
	}	
	
	return $time;
}

Example Usage:

<?php echo(select_time_tag('time', '2005-11-10 14:15:30', array('minute_step' => 15, 'include_second' => true, 'include_ampm' => true, 'second_step' => 15, 'time_seperator' => ' : '))); ?>

Once again, I haven't added any i18n to these helpers.

01/05/06 17:49:57 changed by brujahRg

This implementation has been based on rails helpers and supports some more options. I18n is implemented for date field ordering, date seperator, month names. Options and html_options are seperated as parameters to prevent some filtering code (which was needed to filter out options before calling tag helpers so they dont appear on html output).

  • I need to prepare some detailed information and examples for usage.
  • This code relies on latest changeset (#337). It won't work on stable or nightly build releases.
  • Since it uses array as tag names, using the validator or manually handling the request parameter to get the timestamp is neccessary before any db-query.
  • Ticket http://www.symfony-project.com/trac/ticket/100 must be solved to make the validation to work properly.
  • Integration with existing javascript date helper may be considered.

Some example usages:

<?php echo (select_datetime_tag('date', $params->get('birthdate'))); ?>
<?php echo (select_datetime_tag('date', '2005-18-01', 'include_blank = 1', 'class=whatever')); ?>
<?php echo (select_date_tag('date', '2005-18-01', array('culture'=>'tr', 'include_custom'=>'choose me'), 'class=whatever')); ?>
<?php echo (select_date_tag('date', array('month'=>1, day=>18, year=>2005), array('discard_day' => true, 'date_seperator'=>'.'), 'class=whatever')); ?>
<?php echo (select_time_tag('time', '18:30:12', array('include_custom'=>array('hour'=>'choose hour', 'minute'=>'choose_minute'), 'time_seperator'=>'&nbsp;'), 'class=whatever')); ?>
<?php echo (select_time_tag('time', '18:30:12', 'include_second = 1', 'class=whatever')); ?>

formhelpers:

function select_day_tag($name, $value, $options = array(), $html_options = array())
{
  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  for ($x = 1; $x < 32; $x++)
  {
    $select_options[$x] = _add_zeros($x, 2);
  }

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

function select_month_tag($name, $value, $options = array(), $html_options = array())
{

  $culture = _get_option($options, 'culture', sfContext::getInstance()->getUser()->getCulture());

  $I18n_arr = _get_I18n_date_locales($culture);

  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  if (_get_option($options, 'use_month_numbers')) 
  {
    for ($k = 1; $k < 13; $k++) 
    {
      $select_options[$k] = _add_zeros($k, 2);
    }
  }
  else
  {  
    if (_get_option($options, 'use_short_month')) 
    {
      $month_names = $I18n_arr['dateFormatInfo']->getAbbreviatedMonthNames();
    }
    else
    {
      $month_names = $I18n_arr['dateFormatInfo']->getMonthNames();
    }

    $add_month_numbers = _get_option($options, 'add_month_numbers');
    foreach ($month_names as $k => $v) 
    {
      $select_options[$k + 1] = ($add_month_numbers) ? ($k + 1 . ' - ' . $v) : $v;
    }
  }

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

function select_year_tag($name, $value, $options = array(), $html_options = array())
{
  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  if (strlen($value) > 0 && is_numeric($value))
  {
    $year_origin = $value;
  }
  else
  {
    $year_origin = date('Y');
  }

  $year_start = _get_option($options, 'year_start', $year_origin - 5);
  $year_end = _get_option($options, 'year_end', $year_origin + 5);

  $ascending = ($year_start < $year_end);
  $until_year = ($ascending) ? $year_end + 1 : $year_end - 1;

  for ($x = $year_start; $x != $until_year; ($ascending) ? $x++ : $x--)
  {
    $select_options[$x] = $x;
  }

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper date format: array('year'=>2005, 'month'=>1, 'day'=1) or timestamp or english date text)
 * @param array $options
 * @return string
 */
function select_date_tag($name, $value, $options = array(), $html_options = array())
{
  $html_options = _parse_attributes($html_options);
  $options = _parse_attributes($options);

  $culture = _get_option($options, 'culture', sfContext::getInstance()->getUser()->getCulture());
  //set it back for month tag
  $option['culture'] = $culture;

  $I18n_arr = _get_I18n_date_locales($culture);

  $date_seperator = _get_option($options, 'date_seperator', $I18n_arr['date_seperator']);

  $discard_month = _get_option($options, 'discard_month');
  $discard_day = _get_option($options, 'discard_day');
  $discard_year = _get_option($options, 'discard_year');

  //discarding month automatically discards day
  if ($discard_month) 
    $discard_day = true;

  $order = _get_option($options, 'order');

  $tags = array();

  if (is_array($order) && count($order) == 3)
  {
    foreach ($order as $k => $v)
    {
      $tags[] = $v[0]; //'day' => 'd' | 'month' => 'm'
    }
  }
  else
  {
    $tags = $I18n_arr['date_order'];
  }

  if ($include_custom = _get_option($options, 'include_custom'))
  {
    $include_custom_month = (is_array($include_custom))
        ? ((isset($include_custom['month'])) ? array('include_custom'=>$include_custom['month']) : array()) 
        : array('include_custom'=>$include_custom);

    $include_custom_day = (is_array($include_custom))
        ? ((isset($include_custom['day'])) ? array('include_custom'=>$include_custom['day']) : array()) 
        : array('include_custom'=>$include_custom);

    $include_custom_year = (is_array($include_custom))
        ? ((isset($include_custom['year'])) ? array('include_custom'=>$include_custom['year']) : array()) 
        : array('include_custom'=>$include_custom);
  }
  else
  {
    $include_custom_month = array();
    $include_custom_day = array();
    $include_custom_year = array();
  }

  $html_options['id'] = $name . '_month';
  $m = ($discard_month != true) ? select_month_tag($name . '[month]', _parse_value_for_date($value, 'month', 'm'), $options + $include_custom_month, $html_options) : '';

  $html_options['id'] = $name . '_day';
  $d = ($discard_day != true) ? select_day_tag($name . '[day]', _parse_value_for_date($value, 'day', 'd'), $options + $include_custom_day, $html_options) : '';

  $html_options['id'] = $name . '_year';
  $y = ($discard_year != true) ? select_year_tag($name . '[year]', _parse_value_for_date($value, 'year', 'Y'), $options + $include_custom_year, $html_options) : '';

  //we have $tags = array ('m','d','y')
  foreach ($tags as $k => $v)
  {
    $tags[$k] = $$v;
  }

  return implode($date_seperator, $tags);
}

function select_second_tag($name, $value, $options = array(), $html_options = array())
{
  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  $second_step = _get_option($options, 'second_step', 1);
  for ($x = 0; $x < 60; $x += $second_step)
  {
    $select_options[$x] = _add_zeros($x, 2);
  }

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

function select_minute_tag($name, $value, $options = array(), $html_options = array())
{
  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  $minute_step = _get_option($options, 'minute_step', 1);
  for ($x = 0; $x < 60; $x += $minute_step)
  {
    $select_options[$x] = _add_zeros($x, 2);
  }

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

function select_hour_tag($name, $value, $options = array(), $html_options = array())
{
  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  $_12hour_time = _get_option($options, '12hour_time');

  $start_hour = ($_12hour_time) ? 1 : 0;
  $end_hour = ($_12hour_time) ? 12 : 23;

  for ($x = $start_hour; $x <= $end_hour; $x++)
  {
    $select_options[$x] = _add_zeros($x, 2);
  }

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

function select_ampm_tag($name, $value, $options = array(), $html_options = array())
{
  $select_options = array();

  if (_get_option($options, 'include_blank'))
  {
    $select_options[''] = '';
  }
  else if ($include_custom = _get_option($options, 'include_custom'))
  {
    $select_options[''] = $include_custom;
  }

  $select_options['AM'] = 'AM';
  $select_options['PM'] = 'PM';

  $option_tags = options_for_select(array_flip($select_options), $value);

  return select_tag($name, $option_tags, $html_options);
}

/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper time format: array('hour'=>0, 'minute'=>0, 'second'=0) or timestamp or english date text)
 * @param array $options
 * @return string
 */
function select_time_tag($name, $value, $options = array(), $html_options = array())
{
  $html_options = _parse_attributes($html_options);
  $options = _parse_attributes($options);

  $time_seperator = _get_option($options, 'time_seperator', ':');
  $ampm_seperator = _get_option($options, 'ampm_seperator', '');
  $include_second = _get_option($options, 'include_second');
  $_12hour_time = _get_option($options, '12hour_time');

  $options['12hour_time'] = $_12hour_time; //set it back. hour tag needs it.

  if ($include_custom = _get_option($options, 'include_custom'))
  {
    $include_custom_hour = (is_array($include_custom))
        ? ((isset($include_custom['hour'])) ? array('include_custom'=>$include_custom['hour']) : array()) 
        : array('include_custom'=>$include_custom);

    $include_custom_minute = (is_array($include_custom))
        ? ((isset($include_custom['minute'])) ? array('include_custom'=>$include_custom['minute']) : array()) 
        : array('include_custom'=>$include_custom);

    $include_custom_second = (is_array($include_custom))
        ? ((isset($include_custom['second'])) ? array('include_custom'=>$include_custom['second']) : array()) 
        : array('include_custom'=>$include_custom);

    $include_custom_ampm = (is_array($include_custom))
        ? ((isset($include_custom['ampm'])) ? array('include_custom'=>$include_custom['ampm']) : array()) 
        : array('include_custom'=>$include_custom);
  }
  else
  {
    $include_custom_hour = array();
    $include_custom_minute = array();
    $include_custom_second = array();
    $include_custom_ampm = array();
  }

  $tags = array();

  $html_options['id'] = $name . '_hour';
  $tags[] = select_hour_tag($name . '[hour]', _parse_value_for_date($value, 'hour', ($_12hour_time) ? 'h' : 'H'), $options + $include_custom_hour, $html_options);

  $html_options['id'] = $name . '_minute';
  $tags[] = select_minute_tag($name . '[minute]', _parse_value_for_date($value, 'minute', 'i'), $options + $include_custom_minute, $html_options);

  if ($include_second)
  {
    $html_options['id'] = $name . '_second';
    $tags[] = select_second_tag($name . "[second]" , _parse_value_for_date($value, 'second', 's'), $options + $include_custom_second, $html_options);
  }

  $time = implode($time_seperator, $tags);

  if ($_12hour_time)
  {
    $html_options['id'] = $name . '_ampm';
    $time .=  $ampm_seperator . select_ampm_tag($name . "[ampm]" , _parse_value_for_date($value, 'ampm', 'A'), $options + $include_custom_ampm, $html_options);
  }

  return $time;
}

/**
 * Enter description here...
 *
 * @param string $name
 * @param string $value (proper datetime format YYYY-MM-DD HH:MM:SS)
 * @param array $options
 * @return string
 */
function select_datetime_tag($name, $value, $options = array(), $html_options = array())
{
  $datetime_seperator = _get_option($options, 'datetime_seperator', '');

  $date = select_date_tag($name, $value, $options, $html_options);
  $time = select_time_tag($name, $value, $options, $html_options);

  return $date . $datetime_seperator. $time;
}

function _add_zeros($string, $strlen)
{
  if ($strlen > strlen($string))
  {
    for ($x = strlen($string); $x < $strlen; $x++)
    {
      $string = '0' . $string;
    }
  }

  return $string;
}

function _get_I18n_date_locales($culture = '')
{
  require_once('i18n/DateFormat.php');

  if (empty($culture))
  {
    $culture = sfContext::getInstance()->getUser()->getCulture();
  }

  $ret_val = array();
  $ret_val['culture'] = $culture;

  $dateFormatInfo = DateTimeFormatInfo::getInstance($culture);
  $date_format = strtolower($dateFormatInfo->getShortDatePattern());

  $ret_val['dateFormatInfo'] = $dateFormatInfo;
    
  $match_pattern = "/([dmy]+)(.*?)([dmy]+)(.*?)([dmy]+)/";
  if (!preg_match($match_pattern, $date_format, $match_arr))
  {
    //if matching fails use en shortdate
    preg_match($match_pattern, 'm/d/yy', $match_arr);
  }

  $ret_val['date_seperator'] = $match_arr[2];

  //unset all but [dmy]+
  unset($match_arr[0], $match_arr[2], $match_arr[4]);
  
  $cnt = 0;
  foreach ($match_arr as $k => $v)
  {
    $ret_val['date_order'][$cnt++] = $v[0]; //$arr[date_order][0] = 'm'; [1] = 'd'; [2] = 'y';
  }
  
  return $ret_val;
}



/**
* _parse_value_for_date function can parse any date field from $value given as:
*  - an array('year'=>2000, 'month'=> 1, ..
*  - a timestamp
*  - english text presentation of date (i.e '14:23', '03:30 AM', '2005-12-25' Refer to strtotime function in PHP manual)
*/
function _parse_value_for_date($value, $name, $format_char)
{
  if (is_array($value))
  {
    return (isset($value[$name])) ? $value[$name] : '';
  }
  else if (is_numeric($value))
  {
    return date($format_char, $value);
  }
  else if ($value == '' || ($name == 'ampm' && ($value == 'AM' || $value == 'PM')))
  {
    return $value;
  }

  return date($format_char, strtotime($value));
}

Validator:

class myDateValidator extends sfValidator
{

  /**
   * Convert date field array to timestamp
   * 
   * @param array An array of date fields to be converted to timestamp
   * @return mixed timestamp for date
   *               false if it is not a valid date.
   */
  private function array_to_timestamp($arr)
  {
    if (!is_array($arr))
      return false;

    //set default values for omitted parts. (discard_day, discard_month, discard_year)
    if (!isset($arr['day'])) $arr['day'] = 1;
    if (!isset($arr['month'])) $arr['month'] = 1;
    if (!isset($arr['year'])) $arr['year'] = date('Y');

    //default values for omitted time parts
    if (!isset($arr['hour'])) $arr['hour'] = 0;
    if (!isset($arr['minute'])) $arr['minute'] = 0;
    if (!isset($arr['second'])) $arr['second'] = 0;

    if (isset($arr['ampm']))
    {
      //we must convert to 24hour format
      if ($arr['ampm'] == 'PM')
      {
        $arr['hour'] += ($arr['hour'] == 12) ? 0 : 12;
      }
      else if ($arr['ampm'] == 'AM')
      {
        $arr['hour'] -= ($arr['hour'] == 12) ? 12 : 0;
      }
      else
      {
        //we have an invalid or empty value for ampm field.
        return false;
      }
    }

    if (checkdate($arr['month'], $arr['day'], $arr['year']))
    {
      $timestamp = mktime($arr['hour'], $arr['minute'], $arr['second'], $arr['month'], $arr['day'], $arr['year']);
      if ($timestamp !== false && $timestamp !== -1)
      {
        return $timestamp;
      }
    }

    return false;
  }


  /**
   * Execute this validator.
   *
   * @param mixed A file or parameter value/array.
   * @param error An error message reference.
   *
   * @return bool true, if this validator executes successfully, otherwise
   *              false.
   */
  public function execute (&$value, &$error)
  {
    $timestamp = $this->array_to_timestamp($value);
    if ($timestamp === false)
    {
      $error = $this->getParameterHolder()->get('date_error');
      return false;
    }
    //overwrite request parameter with timestamp. so we dont have to handle the date array again. (i.e. in db-query)
    $value = $timestamp;

    return true;
  }

  public function initialize ($context, $parameters = null)
  {
    // initialize parent
    parent::initialize($context);

    // set defaults
    $this->getParameterHolder()->set('date_error', 'Invalid date');

    $this->getParameterHolder()->add($parameters);

    return true;
  }
}

01/05/06 21:58:53 changed by RoVeRT <rovert@rovert.net>

When posting big chuncks uf code like this please zip it up and put in an attachment it makes it much easier for everyone

03/08/06 12:26:54 changed by brujahRg

  • attachment date_select.patch added.

tidied up the code. patch against r954

03/08/06 12:37:12 changed by brujahRg

  • keywords set to date time select helper.
  • status changed from new to closed.
  • version changed from 0.5.X to 0.6.0.
  • resolution set to fixed.
  • milestone changed from 0.6.0 to 0.6.1.

Tidied up the code for date-select helpers

Btw, i'm closing this ticket since the helper functions have been included in Symfony @ r954.

03/08/06 17:51:49 changed by anonymous

  • status changed from closed to reopened.
  • resolution deleted.

03/22/06 18:00:19 changed by anonymous

  • summary changed from New form helper functionality for dates to [PATCH] New form helper functionality for dates.

03/25/06 20:16:31 changed by brujahRg

I really think this patch should be applied soon in order to close this prolonged ticket. And before the helpers got enhanced/modified so the patch may become obsolete or more difficult to integrate.

http://www.symfony-project.com/trac/attachment/ticket/26/date_select.patch

04/07/06 11:23:21 changed by fabien

  • status changed from reopened to closed.
  • resolution set to fixed.

fixed in r1142.

07/31/06 16:47:37 changed by jakuza

http://www.symfony-project.com/snippets/snippet/68 for rich version of select_date_tag