проверка php на действительную дату, странные преобразования дат

Есть ли способ проверить, действительны ли дата / время, как вы думаете, это легко проверить:

$date = '0000-00-00';
$time = '00:00:00';
$dateTime = $date . ' ' . $time;

if(strtotime($dateTime)) {
    // why is this valid?
}

что меня действительно понимает, так это следующее:

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

Результат: "1999-11-30",

Хм? я пошел от 0000-00-00 до 1999-11-30 ???

Я знаю, что могу провести сравнение, чтобы увидеть, совпадает ли дата одного из этих значений с датой, которая у меня есть, но это не очень надежный способ проверки. Есть ли хороший способ проверить, действительна ли у меня дата? У кого-нибудь есть хорошая функция, чтобы проверить это?

Изменить: Люди спрашивают, что я запускаю: Запуск PHP 5.2.5 (cli) (построен: 23 июля 2008 г., 11:32:27) на Linux localhost 2.6.18-53.1.14.el5 # 1 SMP, среда, 5 марта 11 : 36: 49 EST 2008 i686 i686 i386 GNU / Linux


person SeanDowney    schedule 26.09.2008    source источник
comment
Попробуйте это: php.net/manual/en/function.checkdate.php   -  person Joshua Kissoon    schedule 19.02.2012
comment
strtotime (0000-00-00 00:00:00) возвращает FALSE в 32-битной системе. strtotime (0000-00-00 00:00:00) возвращает -62169955200 в 64-битной системе.   -  person Silver Moon    schedule 21.11.2012


Ответы (10)


Из 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;
}
?>
person mk.    schedule 26.09.2008

Как упоминалось здесь: https://bugs.php.net/bug.php?id=45647

Здесь нет ошибки, 00-00-00 означает 2000-00-00, то есть 1999-12-00, то есть 1999-11-30. Никаких ошибок, совершенно нормально.

И, как показано в нескольких тестах, откат назад является ожидаемым поведением, хотя и немного тревожным:

>> 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'
person Izkata    schedule 29.03.2012

эхо-дата ('Г-м-д', strtotime ($ date));

Результаты: "1999-11-30"

Результат strtotime - 943920000 - это примерно количество секунд между эпохой Unix. (база, от которой отсчитывается время) до 1999-11-30.

Есть задокументированная ошибка MySQL на mktime(), localtime(), strtotime() всех возвращает это нечетное значение, когда вы пробуете время до начала эпохи (включая «0000-00-00 00:00:00»). В связанном потоке ведутся споры о том, действительно ли это ошибка:

Поскольку метка времени начинается с 1970 года, я не думаю, что она вообще должна работать.

Ниже приведена функция, которую я использую для преобразования dateTimes, например, выше, в метку времени для сравнения и т. Д., Которая может быть вам полезна для дат после "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);
}
person ConroyP    schedule 26.09.2008
comment
Я пробовал дату ('Y-m-d', convert_date_string ('0000-00-00 00:00:00')), но все же дает дату 1999 года - person SeanDowney; 26.09.2008
comment
Нашел отчет об ошибке PHP о странном поведении функций, основанных на времени, в PHP для значения 0000-00 ... В этой ветке ведутся споры о том, действительно ли это ошибка, как будто люди когда-нибудь захотят вычислить дату до 1970 года! - person ConroyP; 26.09.2008

Не ждите согласованных результатов, когда вы находитесь за пределами допустимого диапазона:

cf strtotime

cf Элементы календаря Gnu с датой .html

"Для числовых месяцев разрешен формат ISO 8601" год-месяц-день ", где год - любое положительное число, месяц - число от 01 до 12, а день - число от 01 до 31. Если число меньше десяти, должен присутствовать ноль в начале ".

Так что «0000-00-00» дает странные результаты, это логично!


"Кроме того, не все платформы поддерживают отрицательные отметки времени, поэтому ваш диапазон дат может быть ограничен не ранее, чем эпоха Unix. Это означает, что, например,% e,% T,% R и% D (могут быть будет больше) и даты до 1 января 1970 года не будут работать в Windows, некоторых дистрибутивах Linux и некоторых других операционных системах. "

cf strftime


Вместо этого используйте функцию checkdate (более надежная):

месяц: месяц от 1 до 12 включительно.

день: день находится в пределах допустимого количества дней для данного месяца. Учитываются високосные годы.

год: год - от 1 до 32767 включительно.

person user22960    schedule 29.09.2008

Эта версия допускает, чтобы поле было пустым, имеет даты в формате мм / дд / гг или мм / дд / гггг, позволяет использовать однозначные часы, добавляет необязательные am / pm и исправляет некоторые незначительные ошибки в сопоставлении времени.

По-прежнему допускаются некоторые патологические времена, такие как «23:14 утра».

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;
}
person asupynuk    schedule 05.01.2011

Если вы просто хотите обработать преобразование даты без времени для поля даты mysql, вы можете изменить этот отличный код, как это сделал я. В моей версии PHP без выполнения этой функции я каждый раз получаю «0000-00-00». Раздражающий.

function ConvertDateString ($DateString)
{
    list($year, $month, $day) = explode("-", $DateString);
    return date ("Y-m-d, mktime (0, 0, 0, $month, $day, $year));
}
person dave    schedule 15.01.2010

Я просто изменил ответ Мартина выше, который будет проверять любой тип даты и возвращать в желаемом формате.

Просто измените формат, отредактировав приведенную ниже строку скрипта 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" ;
    }
}
?>
person Community    schedule 20.01.2012

Я использовал следующий код для проверки дат, поступающих из приложений ExtJS.

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);
}
person eli    schedule 25.04.2012

person    schedule
comment
это будет работать для недавних дат, но если у меня есть дата в начале девяностых, он всегда будет возвращать false - person SeanDowney; 03.04.2012
comment
@SeanDowney отредактировал, что должно вернуть ИСТИНА для вашего свидания в начале девяностых. - person Josue; 04.03.2013

person    schedule
comment
Это не работает с некоторыми крайними случаями, такими как 31 февраля или 31 апреля. Например, date (Y-m-d, strtotime (31.2.2012)) приводит к 2012-03-02, который проходит проверку контрольной даты, даже если пользователь не ввел действительную дату. - person Ville Salonen; 17.01.2012