Правильно определить, является ли строка даты действительной датой в этом формате


184

Я получаю строку даты из API, и она отформатирована как yyyy-mm-dd.

В настоящее время я использую регулярное выражение для проверки формата строки, который работает нормально, но я вижу некоторые случаи, когда это может быть правильный формат в соответствии со строкой, но на самом деле недопустимая дата. то есть 2013-13-01, например.

Есть ли лучший способ в PHP, чтобы взять строку, такую ​​как 2013-13-01и сказать, является ли она действительной датой или нет для формата yyyy-mm-dd?


Возможный дубликат проверки даты php
Vivek Athalye

2
Ответ здесь намного лучше в любом случае.
Себастьян

Ответы:


454

Вы можете использовать DateTimeкласс для этой цели:

function validateDate($date, $format = 'Y-m-d')
{
    $d = DateTime::createFromFormat($format, $date);
    // The Y ( 4 digits year ) returns TRUE for any integer with any number of digits so changing the comparison from == to === fixes the issue.
    return $d && $d->format($format) === $date;
}

[ Функция взята из этого ответа . Также на php.net . Первоначально написано Главич . ]


Тестовые случаи:

var_dump(validateDate('2013-13-01'));  // false
var_dump(validateDate('20132-13-01')); // false
var_dump(validateDate('2013-11-32'));  // false
var_dump(validateDate('2012-2-25'));   // false
var_dump(validateDate('2013-12-01'));  // true
var_dump(validateDate('1970-12-01'));  // true
var_dump(validateDate('2012-02-29'));  // true
var_dump(validateDate('2012', 'Y'));   // true
var_dump(validateDate('12012', 'Y'));  // false

Демо!


14
Если вы используете PHP 5.2.x, вы должны использовать strtotimeдля получения метки времени Unix, а затем date('Y-m-d', $t)для получения строковой даты. Затем вы сравниваете их так же, как этот ответ.
Pedromanoel

2
@pedromanoel: для стандартного ввода даты и времени, который вы можете использовать strtotime, но для нестандартных форматов, которые strtotimeне распознает, вам понадобится другое решение. А для php версии 5.2 поддержка прекращена в январе 2011 года, для 5.3 поддержка остановлена ​​в августе 2014 года.
Glavić

2
рассмотреть эту датуvar_dump( validateDate('2012-2-9'));
безжалостно

4
Функция работает правильно. Он вернул false, потому что указанный вами формат был неверным. Если вы хотите использовать день и месяц без 'Y-n-j'начальных нулей, то формат должен быть @reignsly.
Амаль Мурали

1
@ AntonyD'Andrea: нет, без этой части не получится. Потому $dчто не будет ложным, вы дадите ему дату, в которой есть переполненные части, например, 13-й месяц (2013-13-01). Но это действительно зависит от того, что вы хотите. Если вам нужно, например, validateDate('2015-55-66')чтобы быть действительным, то да, вам нужно только проверить, $dявляется ли объект или нет.
Главич

81

Определите, является ли какая-либо строка датой

function checkIsAValidDate($myDateString){
    return (bool)strtotime($myDateString);
}

2
Это проверяет целый ряд допустимых форматов даты, а не только yyyy-mm-dd.
EWit

10
@MichelAyres это связано с тем, что php воспринимается 2015-02-30как действительная дата, потому что когда указанный день превышает количество дней в данном месяце (или отрицательное значение), php переносится на следующий месяц. Поскольку дата гарантированно имеет формат, yyyy-mm-ddэто можно исправить, изменив возврат на return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21

2
Почему получается так (bool)strtotime('s'), как правда?
Peon

это также возвращает 1 checkIsAValidDate ("F");
Вайбхав Бханушали

мы можем использовать $myDateString = str_replace("/", '-', $myDateString);перед возвратом, если строка даты содержит косые черты (/), такие как: - дд / мм / гггг
Яшрайсинь Джадежа

37

Просто используйте с предустановленной функцией php:

function checkmydate($date) {
  $tempDate = explode('-', $date);
  // checkdate(month, day, year)
  return checkdate($tempDate[1], $tempDate[2], $tempDate[0]);
}

Тест

   checkmydate('2015-12-01'); //true
   checkmydate('2015-14-04'); //false

1
Хорошее простое решение, сработало в первый раз, спасибо :)
Дэвид Белл

Опять же, при использовании теста, внутри, ifчтобы просто вернуться trueили falseвернуть сам тест.
Виктор Шредер

4
Предполагается, что в массиве $ tempDate есть как минимум 3 элемента.
27

2
@ person27:return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]...
неврино

@vineet - это не получается. Если год 2, 20, 202, 2020или даже если год 20201- это возвращает истину каждый раз.
Ролингер

16

Определите, является ли строка датой, даже если строка имеет нестандартный формат

(strtotime не принимает произвольный формат)

<?php
function validateDateTime($dateStr, $format)
{
    date_default_timezone_set('UTC');
    $date = DateTime::createFromFormat($format, $dateStr);
    return $date && ($date->format($format) === $dateStr);
}

// These return true
validateDateTime('2001-03-10 17:16:18', 'Y-m-d H:i:s');
validateDateTime('2001-03-10', 'Y-m-d');
validateDateTime('2001', 'Y');
validateDateTime('Mon', 'D');
validateDateTime('March 10, 2001, 5:16 pm', 'F j, Y, g:i a');
validateDateTime('March 10, 2001, 5:16 pm', 'F j, Y, g:i a');
validateDateTime('03.10.01', 'm.d.y');
validateDateTime('10, 3, 2001', 'j, n, Y');
validateDateTime('20010310', 'Ymd');
validateDateTime('05-16-18, 10-03-01', 'h-i-s, j-m-y');
validateDateTime('Monday 8th of August 2005 03:12:46 PM', 'l jS \of F Y h:i:s A');
validateDateTime('Wed, 25 Sep 2013 15:28:57', 'D, d M Y H:i:s');
validateDateTime('17:03:18 is the time', 'H:m:s \i\s \t\h\e \t\i\m\e');
validateDateTime('17:16:18', 'H:i:s');

// These return false
validateDateTime('2001-03-10 17:16:18', 'Y-m-D H:i:s');
validateDateTime('2001', 'm');
validateDateTime('Mon', 'D-m-y');
validateDateTime('Mon', 'D-m-y');
validateDateTime('2001-13-04', 'Y-m-d');

При использовании теста внутри ifможно просто вернуть trueили falseвернуть сам тест.
Виктор Шредер

Но 2018-3-24 возвращает false, метод получает 2018-3-24, когда применяется формат return 2018-03-24; как я могу вернуть истину двумя способами?
Акилес Перес

12

Эта опция не только проста, но также принимает практически любой формат, хотя в нестандартных форматах она может содержать ошибки.

$timestamp = strtotime($date);
return $timestamp ? $date : null;

Это должен был быть принятый ответ! Гораздо проще.
Веб-мастер G

2
Важно отметить, что это не будет работать с британским (d / m / Y) форматом, так как предполагается, что он конвертирует американский (m / d / Y). Это будет работать, только если день ниже 12!
Сильвестр Сарацевас

@galki - я проверил это, и оно не соответствует определенным значениям. Если $ date = '202-03-31', возвращается true. Но это недействительная дата. Я обнаружил, что если вы измените год на недействительный, он всегда вернет истину.
Ролингер

@ Странно странно ... может быть, он видит 202AD? Какую временную метку дает «strtotime»?
Галки

@galki - не уверен, но 202возвращает отрицательное число - который все еще проходит тест.
Ролингер

10

Вы также можете проанализировать дату для даты месяца и года, а затем использовать функцию PHP, о checkdate()которой вы можете прочитать здесь: http://php.net/manual/en/function.checkdate.php

Вы также можете попробовать это:

$date="2013-13-01";

if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date))
    {
        echo 'Date is valid';
    }else{
        echo 'Date is invalid';
    }

в случае февраля (как прокомментировал elitechief21) функция isValidDate ($ date) {return preg_match ("/ ^ [0-9] {4} - (0 [1-9] | 1 [0-2]) - (0 [1-9] | [1-2] [0-9] | 3 [0-1]) $ / ", $ date) && date (" Ymd ", strtotime ($ date)) == $ date; }
abdulwadood

4
Это решение очень плохое, так как оно не проверяет достоверность даты в любом смысле. Любой месяц может иметь 31 день, включая февраль. У любого года может быть 29 февраля. Для проверки дат с использованием RegExp потребуется нечто гораздо более сложное, с обратными ссылками и негативным прогнозом.
Виктор Шредер

9

Самый простой способ проверить, является ли данная дата действительной, вероятно, преобразовав ее в unixtime, используя ее strtotime, отформатировав в формат данной даты, а затем сравнив ее:

function isValidDate($date) { return date('Y-m-d', strtotime($date)) === $date; }

Конечно, вы можете использовать регулярное выражение для проверки правильности, но оно будет ограничено данным форматом, каждый раз, когда вам придется редактировать его для соответствия другим форматам, а также это будет больше, чем требуется. Встроенные функции - это лучший способ (в большинстве случаев) для достижения работы.


1
Я чувствую, что этот ответ довольно низкого качества, особенно с учетом того, что уже есть ответы на этот вопрос.
GrumpyCrouton

4
Это самый короткий ответ, и он работает. Немного сурово сказать, что это низкое качество.
Тим Роджерс

@ user4600953 - это самый простой, который работает. Многие другие говорят, что используют checkdate()- но я считаю, что checkdate не работает, если год ЛЮБОЕ значение: 2, 20, 202, 2020, 20201- все возвращают true. Я собираюсь с вашим решением!
ролингер

7

Согласна с ответом cl-sah, но звучит лучше, короче ...

function checkmydate($date) {
  $tempDate = explode('-', $date);
  return checkdate($tempDate[1], $tempDate[2], $tempDate[0]);
}

Тест

checkmydate('2015-12-01');//true
checkmydate('2015-14-04');//false

Вам нужно проверить , если count($tempDate) === 3хотя
VDarricau

@VDarricau нет, вы не делаете, checkdate будет бомбить, если они отсутствуют, вы можете написать isset () для каждого, но я бы просто подавил предупреждения
Мистер Хилис

7

У меня есть такая вещь, что даже с PHP мне нравится находить функциональные решения. Так, например, ответ, данный @migli, действительно хороший, очень гибкий и элегантный.

Но есть проблема: что, если вам нужно проверить множество строк DateTime в одном и том же формате? Вам придется повторить формат повсеместно, что противоречит принципу СУХОЙ . Мы могли бы поместить формат в константу, но, тем не менее, нам пришлось бы передавать константу в качестве аргумента для каждого вызова функции.

Но не бойся больше! Мы можем использовать карри для нашего спасения! PHP не делает эту задачу приятной, но все еще возможно реализовать карри с помощью PHP:

<?php
function validateDateTime($format)
{
    return function($dateStr) use ($format) {
        $date = DateTime::createFromFormat($format, $dateStr);
        return $date && $date->format($format) === $dateStr;
    };
}

Итак, что мы только что сделали? По сути, мы обернули тело функции в анонимный и вместо этого вернули такую ​​функцию. Мы можем вызвать функцию проверки так:

validateDateTime('Y-m-d H:i:s')('2017-02-06 17:07:11'); // true

Да, не большая разница ... но настоящая сила исходит от частично примененной функции , которая стала возможной благодаря карри:

// Get a partially applied function
$validate = validateDateTime('Y-m-d H:i:s');

// Now you can use it everywhere, without repeating the format!
$validate('2017-02-06 17:09:31'); // true
$validate('1999-03-31 07:07:07'); // true
$validate('13-2-4 3:2:45'); // false

Функциональное программирование FTW!


2
Лучший ответ от опрометчивого ИМХО (решает конкретную проблему ОП с большей гибкостью и почти таким же количеством кода, как и остальные ответы)
StubbornShowaGuy

ИМХО, это действительно уродливое программирование, просто поместите ваши значения в массив и прокрутите их для проверки, но, пожалуйста, не делайте этого!
Тим

Мне интересно @Tim, не могли бы вы привести пример проверки вашего массива / цикла?
Виктор Шредер

5

Я боюсь, что большинство проголосовавших решение ( https://stackoverflow.com/a/19271434/3283279 ) не работает должным образом. Четвертый контрольный пример (var_dump (validateDate ('2012-2-25')); // false) неверен. Дата правильна, потому что она соответствует формату - m позволяет месяц с или без нуля (см .: http://php.net/manual/en/datetime.createfromformat.php ). Поэтому дата 2012-2-25 имеет формат Ymd, и контрольный пример должен быть истинным, а не ложным.

Я считаю, что лучшим решением будет проверить возможную ошибку следующим образом:

function validateDate($date, $format = 'Y-m-d') {
    DateTime::createFromFormat($format, $date);
    $errors = DateTime::getLastErrors();

    return $errors['warning_count'] === 0 && $errors['error_count'] === 0;
}

3

Как насчет этого?

Мы просто используем блок try-catch.

$dateTime = 'an invalid datetime';

try {
    $dateTimeObject = new DateTime($dateTime);
} catch (Exception $exc) {
    echo 'Do something with an invalid DateTime';
}

Этот подход не ограничен только одним форматом даты / времени, и вам не нужно определять какую-либо функцию.


это не будет работать для значения datetime 0000-00-00 00:00:00
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'является допустимым значением даты и времени. Это просто первое значение. Однако свойство date объекта datetime будет '-0001-11-30 00:00:00'.
Джулиан

1

Проверенное решение Regex:

    function isValidDate($date)
    {
            if (preg_match("/^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$/", $date)) {
                    return $date;
            }
            return null;
    }

Это вернет ноль, если дата недействительна или не в формате гггг-мм-дд, в противном случае она вернет дату.



0
/*********************************************************************************
Returns TRUE if the input parameter is a valid date string in "YYYY-MM-DD" format (aka "MySQL date format")
The date separator can be only the '-' character.
*********************************************************************************/
function isMysqlDate($yyyymmdd)
{
    return checkdate(substr($yyyymmdd, 5, 2), substr($yyyymmdd, 8), substr($yyyymmdd, 0, 4)) 
        && (substr($yyyymmdd, 4, 1) === '-') 
        && (substr($yyyymmdd, 7, 1) === '-');
}

-1
    /**** date check is a recursive function. it's need 3 argument 
    MONTH,DAY,YEAR. ******/

    $always_valid_date = $this->date_check($month,$day,$year);

    private function date_check($month,$day,$year){

        /** checkdate() is a php function that check a date is valid 
        or not. if valid date it's return true else false.   **/

        $status = checkdate($month,$day,$year);

        if($status == true){

            $always_valid_date = $year . '-' . $month . '-' . $day;

            return $always_valid_date;

        }else{
            $day = ($day - 1);

            /**recursive call**/

            return $this->date_check($month,$day,$year);
        }

    }

1
Код без каких-либо объяснений не очень полезен.
Герт Арнольд

-2

Попробуйте это:

$date = "2017-10-01";


function date_checker($input,$devider){
  $output = false;

  $input = explode($devider, $input);
  $year = $input[0];
  $month = $input[1];
  $day = $input[2];

  if (is_numeric($year) && is_numeric($month) && is_numeric($day)) {
    if (strlen($year) == 4 && strlen($month) == 2 && strlen($day) == 2) {
      $output = true;
    }
  }
  return $output;
}

if (date_checker($date, '-')) {
  echo "The function is working";
}else {
  echo "The function isNOT working";
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.