[ACCEPTED]-php check for a valid date, weird date conversions-strtotime

Accepted answer
Score: 23

From php.net

<?php
function isValidDateTime($dateTime)
{
    if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, $matches)) {
        if (checkdate($matches[2], $matches[3], $matches[1])) {
            return true;
        }
    }

    return false;
}
?>

0

Score: 5

As mentioned here: https://bugs.php.net/bug.php?id=45647

There is no bug here, 00-00-00 4 means 2000-00-00, which is 1999-12-00, which 3 is 1999-11-30. No bug, perfectly normal.

And 2 as shown with a few tests, rolling backwards 1 is expected behavior, if a little unsettling:

>> date('Y-m-d', strtotime('2012-03-00'))
string: '2012-02-29'
>> date('Y-m-d', strtotime('2012-02-00'))
string: '2012-01-31'
>> date('Y-m-d', strtotime('2012-01-00'))
string: '2011-12-31'
>> date('Y-m-d', strtotime('2012-00-00'))
string: '2011-11-30'
Score: 2

echo date('Y-m-d', strtotime($date));

results 14 in: "1999-11-30"

The result of 13 strtotime is 943920000 - this is the number of seconds, roughly, between 12 the Unix epoch (base from which time is measured) to 11 1999-11-30.

There is a documented mysql bug on mktime(), localtime(), strtotime() all returning 10 this odd value when you try a pre-epoch 9 time (including "0000-00-00 00:00:00"). There's 8 some debate on the linked thread as to whether 7 this is actually a bug:

Since the time stamp 6 is started from 1970, I don't think it supposed 5 to work in anyways.

Below is a function 4 that I use for converting dateTimes such 3 as the above to a timestamp for comparisons, etc, which 2 may be of some use to you, for dates beyond 1 "0000-00-00 00:00:00"

/**
 * Converts strings of the format "YYYY-MM-DD HH:MM:SS" into php dates
 */
function convert_date_string($date_string)
{
    list($date, $time) = explode(" ", $date_string);
    list($hours, $minutes, $seconds) = explode(":", $time);
    list($year, $month, $day) = explode("-", $date);
    return mktime($hours, $minutes, $seconds, $month, $day, $year);
}
Score: 1

Don't expect coherent results when you're 12 out of range:

cf strtotime

cf Gnu Calendar-date-items.html

"For numeric 11 months, the ISO 8601 format ‘year-month-day’ is 10 allowed, where year is any positive number, month is a number between 01 and 12, and 9 day is a number between 01 and 31. A leading zero must be present if a number 8 is less than ten."

So '0000-00-00' gives 7 weird results, that's logical!


"Additionally, not all platforms support negative timestamps, therefore your date range may be limited to no earlier than the Unix epoch. This 6 means that e.g. %e, %T, %R and %D (there 5 might be more) and dates prior to Jan 1, 1970 will not work on Windows, some Linux distributions, and a few other operating systems."

cf strftime


Use checkdate function 4 instead (more robust):

month: The month is between 1 and 12 inclusive.

day: The 3 day is within the allowed number of days 2 for the given month. Leap year s are taken into 1 consideration.

year: The year is between 1 and 32767 inclusive.

Score: 1

If you just want to handle a date conversion 4 without the time for a mysql date field, you 3 can modify this great code as I did. On 2 my version of PHP without performing this 1 function I get "0000-00-00" every time. Annoying.

function ConvertDateString ($DateString)
{
    list($year, $month, $day) = explode("-", $DateString);
    return date ("Y-m-d, mktime (0, 0, 0, $month, $day, $year));
}
Score: 1

This version allows for the field to be 5 empty, has dates in mm/dd/yy or mm/dd/yyyy 4 format, allow for single digit hours, adds 3 optional am/pm, and corrects some subtle 2 flaws in the time match.

Still allows some 1 pathological times like '23:14 AM'.

function isValidDateTime($dateTime) {
    if (trim($dateTime) == '') {
        return true;
    }
    if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})(\s+(([01]?[0-9])|(2[0-3]))(:[0-5][0-9]){0,2}(\s+(am|pm))?)?$/i', $dateTime, $matches)) {
        list($all,$mm,$dd,$year) = $matches;
        if ($year <= 99) {
            $year += 2000;
        }
        return checkdate($mm, $dd, $year);
    }
    return false;
}
Score: 0

I have been just changing the martin answer 4 above, which will validate any type of date 3 and return in the format you like.

Just 2 change the format by editing below line 1 of script strftime("10-10-2012", strtotime($dt));

<?php
echo is_date("13/04/10");

function is_date( $str ) {
    $flag = strpos($str, '/');

    if(intval($flag)<=0){
        $stamp = strtotime( $str );
    } else {
        list($d, $m, $y) = explode('/', $str);    
        $stamp = strtotime("$d-$m-$y");
    } 
    //var_dump($stamp) ;

    if (!is_numeric($stamp)) {
        //echo "ho" ;
        return "not a date" ;        
    }

    $month = date( 'n', $stamp ); // use n to get date in correct format
    $day   = date( 'd', $stamp );
    $year  = date( 'Y', $stamp );

    if (checkdate($month, $day, $year)) {
        $dt = "$year-$month-$day" ;
        return strftime("%d-%b-%Y", strtotime($dt));
        //return TRUE;
    } else {
        return "not a date" ;
    }
}
?>
Score: 0
<?php
function is_valid_date($user_date=false, $valid_date = "1900-01-01") {
    $user_date = date("Y-m-d H:i:s",strtotime($user_date));
    return strtotime($user_date) >= strtotime($valid_date) ? true : false;
}

echo is_valid_date("00-00-00") ? 1 : 0;    // return 0

echo is_valid_date("3/5/2011") ? 1 : 0;    // return 1

0

Score: 0

I have used the following code to validate 1 dates coming from ExtJS applications.

function check_sql_date_format($date) {
    $date = substr($date, 0, 10);
    list($year, $month, $day) = explode('-', $date);
    if (!is_numeric($year) || !is_numeric($month) || !is_numeric($day)) {
        return false;
    }
    return checkdate($month, $day, $year);
}

More Related questions