Xác định chính xác nếu chuỗi ngày là một ngày hợp lệ trong định dạng đó


183

Tôi đang nhận được một chuỗi ngày từ một API và nó được định dạng là yyyy-mm-dd.

Tôi hiện đang sử dụng biểu thức chính quy để xác thực định dạng chuỗi, hoạt động ổn, nhưng tôi có thể thấy một số trường hợp có thể là định dạng đúng theo chuỗi nhưng thực sự là một ngày không hợp lệ. tức là 2013-13-01chẳng hạn

Có cách nào tốt hơn trong PHP để lấy một chuỗi như 2013-13-01và cho biết đó có phải là ngày hợp lệ hay không cho định dạng yyyy-mm-dd?


Bản sao có thể có của xác thực ngày php
Vivek Athalye

1
Câu trả lời ở đây là tốt hơn nhiều.
Sebastien

Câu trả lời:


450

Bạn có thể sử dụng DateTimelớp cho mục đích này:

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;
}

[ Chức năng lấy từ câu trả lời này . Cũng trên php.net . Nguyên văn bởi Glavić . ]


Các trường hợp thử nghiệm:

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

Bản giới thiệu!


14
Nếu bạn đang sử dụng PHP 5.2.x, bạn nên sử dụng strtotimeđể lấy dấu thời gian unix sau đó date('Y-m-d', $t)để lấy ngày chuỗi. Sau đó, bạn so sánh chúng giống như câu trả lời này.
pedromanoel

2
@pedromanoel: đối với đầu vào datetime tiêu chuẩn bạn có thể sử dụng strtotime, nhưng đối với các định dạng không chuẩn strtotimekhông nhận ra, bạn sẽ cần một số giải pháp khác. Và đối với hỗ trợ phiên bản php 5.2 đã dừng vào tháng 1 năm 2011, vì hỗ trợ 5.3 đã dừng vào tháng 8 năm 2014.
Glavić

2
xem xét ngày nàyvar_dump( validateDate('2012-2-9'));
trị vì

4
Các chức năng hoạt động chính xác. Nó trả về false vì định dạng thr bạn chỉ định không chính xác. Nếu bạn muốn sử dụng ngày và tháng mà không có số 0 đứng đầu, thì định dạng nên là 'Y-n-j', @reignsly.
Amal Murali

1
@ AntonyD'Andrea: không, nó sẽ không hoạt động nếu không có phần đó. Bởi vì $dsẽ không sai khi bạn cung cấp ngày tháng, phần này đã tràn ra, như tháng thứ 13 (2013-13-01). Nhưng nó thực sự phụ thuộc vào những gì bạn muốn. Nếu bạn cần ví dụ validateDate('2015-55-66')là hợp lệ, thì có, bạn chỉ cần kiểm tra xem có phải $dlà đối tượng hay không.
Glavić

80

Xác định xem có chuỗi nào là ngày không

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

2
Điều này xác nhận toàn bộ một loạt các định dạng ngày hợp lệ không chỉ yyyy-mm-dd.
EWit

10
@MichelAyres điều này là do php xem 2015-02-30là một ngày hợp lệ bởi vì khi ngày đưa ra lớn hơn số ngày trong tháng đã cho (hoặc âm) php sẽ chuyển sang tháng tiếp theo. Vì ngày được đảm bảo có định dạng, yyyy-mm-ddđiều này có thể được sửa bằng cách thay đổi trả về return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21

2
Tại sao (bool)strtotime('s')đi ra như sự thật?
Peon

cái này cũng trả về 1 checkIsAValidDate ("F");
Vaibhav Bhanushali

chúng ta có thể sử dụng $myDateString = str_replace("/", '-', $myDateString);trước khi trả về nếu chuỗi ngày chứa dấu gạch chéo (/) như: - dd / mm / yyyy
Yashrajsinh Jadeja

37

Sử dụng theo cách đơn giản với chức năng dựng sẵn php:

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

Kiểm tra

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

1
Giải pháp đơn giản tuyệt vời, làm việc lần đầu tiên, cảm ơn :)
David Bell

Một lần nữa, khi sử dụng một bài kiểm tra, bên trong một ifđể trả về đơn giản truehoặc false, trả lại chính bài kiểm tra đó.
Victor Schröder

4
Giả định này có ít nhất 3 phần tử trong mảng $ tempDate.
người27

2
@ người27:return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]...
neurino

@vineet - cái này thất bại. Nếu năm nay là 2, 20, 202, 2020hoặc thậm chí nếu năm là 20201- nó trả về true mỗi lần.
rolinger

16

Xác định xem chuỗi có phải là ngày không, ngay cả khi chuỗi có định dạng không chuẩn

(strtotime không chấp nhận bất kỳ định dạng tùy chỉnh nào)

<?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');

Khi sử dụng một bài kiểm tra, bên trong ifđể trả về đơn giản truehoặc false, trả lại bài kiểm tra đó.
Victor Schröder

Nhưng 2018-3-24 đang trả về sai, phương thức nhận 2018-3-24, khi định dạng được áp dụng trả về 2018-03-24; Làm thế nào tôi có thể trở lại đúng theo hai cách?
Aquiles Perez

12

Tùy chọn này không chỉ đơn giản mà còn chấp nhận hầu hết mọi định dạng, mặc dù với các định dạng không chuẩn, nó có thể bị lỗi.

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

Đây nên là câu trả lời được chấp nhận! Nhiều, đơn giản hơn nhiều.
Quản trị trang web G

2
Điều quan trọng cần lưu ý là điều này sẽ không hoạt động với định dạng của Anh (d / m / Y) vì nó sẽ cho rằng nó chuyển đổi người Mỹ (m / d / Y). Nó dường như chỉ hoạt động nếu ngày thấp hơn 12!
Sylvester Saracevas

@galki - Tôi đã thử nghiệm điều này và nó thất bại một số giá trị nhất định. Nếu $ date = '202-03-31', nó trả về đúng. Nhưng đó không phải là một ngày hợp lệ. Tôi thấy rằng nếu bạn thay đổi năm thành một năm không hợp lệ thì nó luôn trả về đúng.
rolinger

@rolinger lạ ... có lẽ nó đang nhìn thấy 202AD? Dấu thời gian của năm nào 'strtotime' đưa ra?
galki

@galki - không chắc chắn, nhưng 202trả về số âm - vẫn vượt qua bài kiểm tra.
rolinger

9

Bạn cũng có thể Phân tích ngày cho tháng và năm và sau đó bạn có thể sử dụng hàm PHP checkdate()mà bạn có thể đọc ở đây: http://php.net/manual/en/feft.checkdate.php

Bạn cũng có thể thử cái này:

$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';
    }

trong trường hợp tháng hai (như nhận xét của elitechief21), hàm 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) && ngày (" Ymd ", strtotime ($ date)) == $ date; }
abdulwadood

4
Giải pháp này rất kém, vì nó không kiểm tra tính hợp lệ của ngày theo bất kỳ ý nghĩa nào. Bất kỳ tháng nào cũng có thể có 31 ngày, kể cả tháng Hai. Năm nào cũng có thể có ngày 29 tháng 2. Để xác thực ngày bằng RegExp sẽ yêu cầu một cái gì đó phức tạp hơn nhiều, với các tham chiếu ngược và các hướng nhìn tiêu cực.
Victor Schröder

9

Cách dễ nhất để kiểm tra xem ngày đã cho có hợp lệ hay không có thể chuyển đổi nó thành unixtime bằng cách sử dụng strtotime, định dạng ngày thành định dạng của ngày đã cho, sau đó so sánh nó:

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

Tất nhiên bạn có thể sử dụng biểu thức chính quy để kiểm tra tính hợp lệ, nhưng nó sẽ bị giới hạn ở định dạng đã cho, mỗi lần bạn sẽ phải chỉnh sửa nó để đáp ứng các định dạng khác, và nó cũng sẽ nhiều hơn yêu cầu. Các chức năng tích hợp là cách tốt nhất (trong hầu hết các trường hợp) để đạt được công việc.


1
Tôi cảm thấy rằng câu trả lời này có chất lượng khá thấp, đặc biệt là xem xét đã có câu trả lời theo thời gian.
GrumpyCrouton

4
Đây là câu trả lời ngắn nhất và nó hoạt động. Có một chút khắc nghiệt để nói rằng nó có chất lượng thấp.
Tim Rogers

@ user4600953 - đây là cách dễ nhất để làm việc. Rất nhiều người khác đang nói sử dụng checkdate()- nhưng tôi đang tìm kiếm checkdate không thành công nếu năm đó là BẤT K value giá trị nào: 2, 20, 202, 2020, 20201- tất cả đều trả về đúng. Tôi đang đi với giải pháp của bạn!
rolinger

7

Phù hợp với câu trả lời của cl-sah, nhưng âm thanh này hay hơn, ngắn hơn ...

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

Kiểm tra

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

Bạn sẽ cần phải kiểm tra xem count($tempDate) === 3mặc dù
VDarricau

@VDarricau không bạn không, checkdate sẽ đánh bom nếu chúng bị mất, bạn có thể viết ngay lập tức () cho mọi người nhưng tôi chỉ đơn giản là đàn áp các cảnh báo
Mr Heelis

7

Tôi có một điều rằng, ngay cả với PHP, tôi thích tìm chức năng giải pháp . Vì vậy, ví dụ, câu trả lời được đưa ra bởi @migli thực sự là một câu hỏi hay, rất linh hoạt và thanh lịch.

Nhưng nó có một vấn đề: nếu bạn cần xác thực nhiều chuỗi DateTime có cùng định dạng thì sao? Bạn sẽ phải lặp lại định dạng ở mọi nơi, điều gì đi ngược lại với DRY nguyên tắc . Chúng ta có thể đặt định dạng trong một hằng số, nhưng vẫn vậy, chúng ta sẽ phải truyền hằng số dưới dạng đối số cho mọi lệnh gọi hàm.

Nhưng đừng sợ nữa! Chúng tôi có thể sử dụng cà ri để giải cứu của chúng tôi! PHP không làm cho nhiệm vụ này dễ chịu, nhưng vẫn có thể thực hiện currying với PHP:

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

Vì vậy, những gì chúng ta vừa làm? Về cơ bản, chúng tôi đã bọc phần thân hàm trong một ẩn danh và thay vào đó trả về hàm đó. Chúng ta có thể gọi hàm xác nhận như thế này:

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

Vâng, không phải là một sự khác biệt lớn ... nhưng sức mạnh thực sự đến từ chức năng được áp dụng một phần , được thực hiện bằng cách cà ri:

// 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

Lập trình chức năng FTW!


2
Câu trả lời hay nhất của IMHO lở đất (giải quyết vấn đề cụ thể của OP với tính linh hoạt cao hơn và số lượng mã tương tự như phần còn lại của câu trả lời)
StubbornShowaGuy

IMHO đây là chương trình thực sự xấu xí, chỉ cần đặt các giá trị của bạn vào một mảng và lặp qua chúng để xác thực, nhưng xin đừng làm điều này!
Tim

Tôi tò mò @Tim, bạn có thể cho chúng tôi một ví dụ về xác thực mảng / vòng lặp của bạn không?
Victor Schröder

5

Tôi sợ rằng hầu hết các giải pháp được bình chọn ( https://stackoverflow.com/a/19271434/3283279 ) không hoạt động đúng. Trường hợp thử nghiệm thứ tư (var_dump (validateDate ('2012-2-25')); // false) là sai. Ngày này là chính xác, vì nó tương ứng với định dạng - m cho phép một tháng có hoặc không có số 0 (xem: http://php.net/manual/en/datetime.createfromformat.php ). Do đó, ngày 2012-2-25 có định dạng Ymd và trường hợp thử nghiệm phải đúng không sai.

Tôi tin rằng giải pháp tốt hơn là kiểm tra lỗi có thể xảy ra như sau:

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

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

3

Cái này thì sao?

Chúng tôi chỉ đơn giản là sử dụng một khối thử bắt.

$dateTime = 'an invalid datetime';

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

Cách tiếp cận này không giới hạn chỉ ở một định dạng ngày / giờ và bạn không cần xác định bất kỳ chức năng nào.


điều này sẽ không hoạt động với giá trị thời gian 0000-00-00 00:00:00
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'là một giá trị thời gian hợp lệ. Đó chỉ là giá trị đầu tiên. Tuy nhiên, thuộc tính ngày của đối tượng datetime sẽ là '-0001-11-30 00:00:00'.
Julian

1

Đã thử nghiệm giải pháp 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;
    }

Điều này sẽ trả về null nếu ngày không hợp lệ hoặc không phải là định dạng yyyy-mm-dd, nếu không nó sẽ trả về ngày.



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
Mã mà không có lời giải thích nào là không hữu ích.
Gert Arnold

-2

Hãy thử xem:

$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";
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.