I am using the date element in my form. I would like to change the range for the years. The default is 1900 to 2050 as coded in expand_date(). How can I change the year range?

Comments

sebagr’s picture

I realise this might not be the best solution for this problem, but it's the only one I've been able to make work. It consists of tweaking the select element in case it's a year combobox. Since I want all years to range from the present to 2006, then it works for my entire site. Hope it helps.

function newsspace_select($element) {
	if($element['#parents'][1] == 'year'){
		$element['#options'] = range(date('Y'), 2006);
	}

  return theme_select($element);
}
itchy’s picture

In my hook_form() function I set the #after_build property for the date element. I set this value as an array with the name of my call back function.

function hook_form() {
    ...
    $form['closing_date'] = array(
        '#type' => 'date',
        '#title' => t('Closing date'),
        '#description' => t('Closing date for submitting applications.'),
        '#default_value' => array(
            'day' => format_date(time(), 'custom', 'j'),
            'month' => format_date(time(), 'custom', 'n'),
            'year' => format_date(time(), 'custom', 'Y')),
        '#after_build' => array('__set_year_range'));
    ...
}

The #after_build property executes the array of functions names after the form has been constructed at which point I need to replace the [year][#options] property value of my date element to my new range. The parameter $form_element is the closing_date element from my form (as defined above).

function __set_year_range($form_element, $form_values) {
    $form_element['year']['#options'] = drupal_map_assoc(range(2007, 2012));
    return $form_element;
}

This works fine for what I need. I'll take a closer look at your solution as I'm sure there is some new things that I can learn from it. Thanks a lot for replying.

ali_rahmi’s picture

function hook_form() {
   $form['range'] = array(
       '#type' => 'value',
       '#value' => 5      // value of range 
    );
   $form['closing_date'] = array(
        '#type' => 'date',
        '#title' => t('Closing date'),
        '#description' => t('Closing date for submitting applications.'),
        '#default_value' => array(
            'day' => format_date(time(), 'custom', 'j'),
            'month' => format_date(time(), 'custom', 'n'),
            'year' => format_date(time(), 'custom', 'Y')),
        '#after_build' => array('__set_year_range'));
    ...
}

it just a compliment to the solution above ...

function __set_year_range($form_element, $form_values) {
    $year_now= gmdate('Y');
    $range_value = $form_values['range'];
    $form_element['year']['#options'] = drupal_map_assoc(range($year_now - $range_value, $year_now));
    return $form_element;
}

from Morocco...

usonian’s picture

I was approaching this problem by overriding $element['date']['#process'] in hook_elements() to point to a customized version of the expand_date() function, but that didn't seem quite right. This is definitely less klugey. I tweaked the function so that the date range defaults to the 25 years before and after the current year, but uses the element's '#year_start' and '#year_end' properties if present, so you can customize individual date elements as necessary:

function __set_year_range($form_element, $form_values) {
  $year_start = isset($form_element['#year_start']) ? $form_element['#year_start'] : date('Y') - 25;
  $year_end = isset($form_element['#year_end']) ? $form_element['#year_end'] : date('Y') + 25;
  $form_element['year']['#options'] = drupal_map_assoc(range($year_start, $year_end));
  return $form_element;
}
Michael Phipps’s picture

Great solution. I noticed that #start_year and #end_year properties have been committed to CVS for version 7 see #47380: Date form element years range, so you may like to make a small change to reduce growing pains: (just flipping year_start around so it becomes start_year)

function __set_year_range($form_element, $form_values) {
  $start_year = isset($form_element['#start_year']) ? $form_element['#start_year'] : date('Y') - 10;
  $end_year = isset($form_element['#end_year']) ? $form_element['#end_year'] : date('Y') + 10;
  $form_element['year']['#options'] = drupal_map_assoc(range($start_year, $end_year));
  return $form_element;
}
prash.marne’s picture

thanks,
very helpful solution worked absolutely fine for me.

travala’s picture

I needed to limit the date range in my form and your solution worked perfectly.

Thank you.
Teja

attheshow’s picture

Itchy's solution worked really well for me too!

lostcarpark’s picture

The webform module adds a useful function for processing the date field, adding '#year_start' and '#year_end' elements to the date field. You can either put actual start and end years in these fields, or use + and - for offsets from the current year.

If you have this module active, you could call the webform function in your form creation as follows:

  $form['general']['dob'] = array(
    '#type' => 'date',
    '#title' => t('Date of Birth'),
    '#default_value' => "",
    '#required' => TRUE,
    '#year_start' => '-99',
    '#year_end' => '+0',
    '#after_build' => array('webform_expand_date'),
  );

If you don't have the Webform module on your site, I've copied a trimmed down version of the functions below (just change "my_module" to your module name):

/**
 * Form API #process function for Webform date fields.
 */
function my_module_pricing_expand_date($element) {
  // Convert relative dates to absolute ones.
  foreach (array('year_start', 'year_end') as $start_end) {
    $year = $element['#' . $start_end];
    if (strpos($year, '-') === 0 || strpos($year, '+') === 0) {
      $timezone = $component['extra']['timezone'] != 'user' ? NULL : 'user';
      $element['#' . $start_end] = my_module_pricing_strtodate('Y', $year . ' years', $timezone);
    }
  }

  // Tweak the year field.
  if (is_numeric($element['#year_start']) && is_numeric($element['#year_end'])) {
    $element['year']['#options'] = drupal_map_assoc(range($element['#year_start'], $element['#year_end']));
  }

  return $element;
}

function my_module_pricing_strtodate($format, $string, $timezone_name = NULL) {
  // Adjust the time based on the user or site timezone.
  // The "timezone_name" variable is provided by DateAPI in Drupal 6.
  if (variable_get('configurable_timezones', 1) && $timezone_name == 'user') {
    $timezone_name = isset($GLOBALS['user']->timezone_name) ? $GLOBALS['user']->timezone_name : NULL;
  }
  elseif (empty($timezone_name) || $timezone_name == 'user') {
    $timezone_name = variable_get('date_default_timezone_name', NULL);
  }

  if (!empty($timezone_name) && class_exists('DateTimeZone')) {
    $timezone = new DateTimeZone($timezone_name);
    $datetime = new DateTime($string, $timezone);
    return $datetime->format($format);
  }
  else {
    return date($format, strtotime($string));
  }
}

An example of its use is:

  $form['general']['dob'] = array(
    '#type' => 'date',
    '#title' => t('Date of Birth'),
    '#default_value' => "",
    '#required' => TRUE,
    '#year_start' => '-99',
    '#year_end' => '+0',
    '#after_build' => array('my_module_expand_date'),
  );

Hope this helps somebody.

James

cata.vancea’s picture

definitely helped me

It think there is a small bug in the code.
The function name should be function my_module_expand_date($element) and not with '_pricing_'

Thx once again !

benjy’s picture

A better way to do this:

  $form['booking-info']['return-date'] = array(
    '#type' => 'date_select',
    '#title' => t('Date & Time'),
    '#default_value' => date('d m Y')),
    '#required' => true,
    '#date_format' => 'd m Y H i',
    '#date_year_range' => '-0:+1',
  );
cvijo’s picture

If use date_popup, changing year range:

  $form['add']['date'] = array(
    '#title' => t('date :'),
    '#type' => 'date_popup',
    '#date_year_range' => '-50:+0',
    '#date_format' => 'd-m-Y',
    '#required' => TRUE,
  );

Select first year, mouth and date.