When attempting to choose a starting/ending date greater than 100 years ago (i.e. '-120 years' or '120 years ago') the date errors and returns 1969.

Comments

weekbeforenext’s picture

Version: 6.x-3.15 » 6.x-3.16

I encountered a similar problem when I upgraded from Webform 3.11 to 3.16. I have been able to set a date range up to +/-25 years and the year select box works properly. If I increase to +/- 26 years, the select box shows 1969-1986.

quicksketch’s picture

Title: 100 Year Limit on Date » Start dates before 1970 cause validation errors

So in short this issue *sounds like* any date before 1970, whether it is is relative (-26 years) or absolute (Dec 1, 1960), the form will throw a validation error of "The entered date must be Dec 31 1969 or earlier."

weekbeforenext’s picture

Not exactly. I set the date range as follows:

Start Date: Dec 31 1948
End Date: Dec 31 1958

In this instance, the year select box rendered properly and the error wasn't thrown. I think it has to do with the number of years that are options. Seems like you aren't allowed to create a range of more than 50 years.

quicksketch’s picture

Huh, interesting. Thanks, the more information the better.

weekbeforenext’s picture

I've located the problem but haven't quite figured it out yet. The bug happens in the webform_strtodate function in weform.module.

Start Date: "Dec 31 1900" becomes "1969-12-31"
End Date: "Dec 31 2050" becomes "1969-12-31"

Start Date: "-26 years" becomes "1986-03-07"
End Date: "+26 years" becomes "1969-12-31"

Start Date: "-25 years" becomes "1987-03-07"
End Date: "+25 years" becomes "2037-03-07"

Start Date: "-2 years" becomes "2010-03-07"
End Date: "+26 years" becomes "1969-12-31"

I will revisit my investigation tomorrow, but I just thought I'd share what I found in case it helps determine a fix sooner.

weekbeforenext’s picture

Looks like the problem is with the php function strtotime().

The problem with dates before 1970 is due to:

"Additionally, not all platforms support negative timestamps, therefore your date range may be limited to no earlier than the Unix epoch. This means that e.g. dates prior to Jan 1, 1970 will not work on Windows, some Linux distributions, and a few other operating systems. PHP 5.1.0 and newer versions overcome this limitation though." - http://us2.php.net/manual/en/function.strtotime.php

I can actually get dates prior to 1970 to work down to Dec 31 1901. Dec 31 1900 breaks.

The problem with +26 years is due to:

"As with each of the time-related functions, and as mentioned in the time() notes, strtotime() is affected by the year 2038 bug on 32-bit systems." - http://us2.php.net/manual/en/function.strtotime.php#80541

Some people have posted work arounds and I will investigate that now. Just wanted to post this as an explanation of the problem. I am on a Windows server and it is most likely 32-bit. Not sure how I am able to do the dates earlier than 1970 though.

weekbeforenext’s picture

It may not be pretty, but I fixed these exceptions in webform.module for rendering:

function webform_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;
  }
  // If the timezone is still empty or not set, use the site timezone.
  if (empty($timezone_name) || $timezone_name == 'user') {
    $timezone_name = variable_get('date_default_timezone_name', NULL);
  }

  if (!empty($timezone_name) && class_exists('DateTimeZone')) {
    // Suppress errors if encountered during string conversion. Exceptions are
    // only supported for DateTime in PHP 5.3 and higher.
    try {
      @$timezone = new DateTimeZone($timezone_name);
      @$datetime = new DateTime($string, $timezone);
      return @$datetime->format($format);
    }
    catch (Exception $e) {
      return '';
    }
  }
  else {
	  if(!strtotime($string)){//if strtotime() fails because of its limitations
		  if(preg_match("/\d{4}/", $string, $absolute)){//if the date string contains a year
			return webform_safe_strtodate($format, $string);
		  }
		  if(strpos($string, "year") && preg_match("/[+-]/", $string, $relative)){//if the date string is relative in years
			$current_year = date('Y');
			$current_date = date($format);
			$relative_date = explode(" ", $string);
			list($operator,$value) = sscanf($relative_date[0],'%[+-]%d');
			switch($operator) {
				case '+' :
					$year = $current_year + $value;
					break;
				case '-' :
					$year = $current_year - $value;
					break;
			}
			return str_replace($current_year, $year, $current_date);
		  }
	  }
    return date($format, strtotime($string));
  }
}

/**
 * Work around PHP strtotime() limitations.
 */
function webform_safe_strtodate($format, $string){
    preg_match("/\d{4}/", $string, $match);
    $year = intval($match[0]);//converting the year to integer
    if($year >= 2038){
        $new_year = 2000;//new_year will be for sure < 2038
        $new_date = date($format, strtotime(str_replace($year, $new_year, $string)));//replacing the year with the new_year, try strtotime, rendering the date
        return str_replace($new_year, $year, $new_date);//returning the date with the correct year
	}
	if($year <= 1970 && stristr(PHP_OS, "WIN") && !stristr(PHP_OS, "DARWIN")){ //OS seems to be Windows, not Unix nor Mac
        $diff = 1975 - $year;//calculating the difference between 1975 and the year
        $new_year = $year + $diff;//year + diff = new_year will be for sure > 1970
        $new_date = date($format, strtotime(str_replace($year, $new_year, $string)));//replacing the year with the new_year, try strtotime, rendering the date
        return str_replace($new_year, $year, $new_date);//returning the date with the correct year
    }
    return date($format, strtotime($string));//do normal strtotime
}

The validation still needs some work.

quicksketch’s picture

Thanks @weekbeforenext! Being on 64-bit, *nix machines, it's unlikely that I would be able to reproduce the problem, so appreciate your sleuthing. To complete the picture, what version of PHP are you running? Webform already requires PHP 5.1, so I'm a bit surprised that the strtotime() limitations are affecting you.

Could you make your changes available as a patch?

weekbeforenext’s picture

I'm testing on PHP 5.2.8 but I first experienced the problems on PHP 5.2.14. I'm pretty sure my sites are running on 32-bit Windows.

I will work on creating a patch. I still need to make modifications to the validation. I'm glad to help out.

weekbeforenext’s picture

StatusFileSize
new2.3 KB

Attached is a patch for what I've done so far. I still need to look at the validation portion.

ardnet’s picture

Hi, was just wondering whether this issue has already been fixed, as I got the same problem now.
Just FYI, I'm using Webform version 6.x-3.18 and PHP ver. 5.3.3, and whether it's necessary to do Webform update just to resolve this issue.

Thanks

danchadwick’s picture

Issue summary: View changes
Status: Active » Closed (won't fix)

The 6.x branch is receiving critical bug fixes only.