Howto detect if typed date is valid

This simple tip allow you to detect if the date is typed correctly and the date format is as expected.

/**
*
* Check if the given date is valid
* @param string $date
*
* @param string $separator
*
* @param string $format defines the order which year month and day are in the $date string
* this string supports "d" for days "m" for month and "y" for year
*
* @param int|bool $lower2DigitsDate (optional default 1950) if the given date is
* defined as 2 digits value it will be adjusted
* according to this value if the parameter is false
* the correction will not be performed
*
* @example $date = '2012-08-30'; $validDate = isValidDate($date, '-', 'ymd');
* @example $date = '30/08/2012'; $validDate = isValidDate($date, '/', 'dmy');
* @example $date = '08/30/2012'; $validDate = isValidDate($date, '/', 'mdy');
* @example $date = '08/30/12'; $validDate = isValidDate($date, '/', 'mdy');
*
* @return boolean
*/
function isValidDate($date, $separator = '/', $format = 'dmy', $lower2DigitsDate = 1950){
/*
* Detect the Datetime structure
*/
$yearIndex = strpos($format, 'y');
$monthIndex = strpos($format, 'm');
$dayIndex = strpos($format, 'd');
/*
* split the string date into an array of three elements according to given separator
*/
$dateElements = preg_split('#'. preg_quote($separator, '#') . '#', $date);
/*
* Check for EXACT 3 parts in the date
*/
if(count($dateElements)!=3) return false;
$day = intval($dateElements[$dayIndex]);
$month = intval($dateElements[$monthIndex]);
$year = intval($dateElements[$yearIndex]);
/*
* Convert 2 digits year in 4 digits year
*/
if($year<100 && $lower2DigitsDate !==false){
$marker = ($lower2DigitsDate%100);
if($year<$marker) $year += 100;
$year = $lower2DigitsDate-$marker + $year;
$dateElements[$yearIndex] = $year;
}
$monthDays = array( 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31);
/**
* Exception on introduction of Gregorian Calendar
* @see http://diegolamonica.info/howto-detect-if-typed-date-is-valid/#comment-5426
*/
if($year==1582 && $month==10 && $day>4 && $day<15) return false;
/**
* Feb has 29 days in the leap years
* @see http://en.wikipedia.org/wiki/Leap_year#Algorithm
*/
$leapYear = ($year % 4 == 0 && ($year % 100 != 0 || $year % 400 == 0) );
if($leapYear) $monthDays[2] = 29;
// Output the adjusted date (with 4 digits year)
$date = implode($separator, $dateElements);
/*
* Check if the day of the month is into the range
*/
return ($monthDays[$month] >= $day && $day>0);
}
view raw isValidDate.php hosted with ❤ by GitHub

Commenti

6 risposte a “Howto detect if typed date is valid”

  1. Avatar Giacomo
    Giacomo

    Riddle: catch the bug.

    isValidDate('30/08/2012', '/', 'dmy') == true
    isValidDate('29/02/2000', '/', 'dmy') == true
    isValidDate('10/10/1580', '/', 'dmy') == true
    isValidDate('29/02/2001', '/', 'dmy') == false
    isValidDate('10/10/1582', '/', 'dmy') == true
    isValidDate('10/12/2121', '/', 'dmy') == true
    isValidDate('10/10/2000', '/', 'dmy') == true
    

    where is the function lack?

    1. Hi Giacomo,
      trying the following code:

      Hi Giacomo,
      trying the following code:

      var_dump(validaData('30/08/2012', '/', 'dmy')); # bool(true)
      var_dump(validaData('29/02/2000', '/', 'dmy')); # bool(true)
      var_dump(validaData('10/10/1580', '/', 'dmy')); # bool(true)
      var_dump(validaData('29/02/2001', '/', 'dmy')); # bool(false)
      var_dump(validaData('10/10/1582', '/', 'dmy')); # bool(true)
      var_dump(validaData('10/12/2121', '/', 'dmy')); # bool(true)
      var_dump(validaData('10/10/2000', '/', 'dmy')); # bool(true) 
      

      the output is as expected. So… where is the bug? :)

  2. Avatar Giacomo
    Giacomo

    Think: which was the day after 4th October 1582 ?

    1. It was the October, 5th 1582, not? :)

  3. Avatar Giacomo
    Giacomo

    no, it wasn’t!
    the day after 4th october, was 15th october, according to Gregorian calendar.

    ….but ….

    …but…. there are many consideration we could do. (i.e. Swedish Reign used Giulian (Assange) calendar till 1699)

    1. touche! :)

      Thanks Giacomo! As you can notice, I’ve changed the script.