ตรวจสอบว่าสตริงวันที่เป็นวันที่ที่ถูกต้องในรูปแบบนั้นหรือไม่


184

ฉันได้รับสตริงวันจาก API yyyy-mm-ddและจะมีการจัดรูปแบบเป็น

ขณะนี้ฉันกำลังใช้ regex เพื่อตรวจสอบความถูกต้องของรูปแบบสตริงซึ่งใช้งานได้ แต่ฉันเห็นบางกรณีซึ่งอาจเป็นรูปแบบที่ถูกต้องตามสตริง แต่จริง ๆ แล้วเป็นวันที่ไม่ถูกต้อง เช่น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 เขียนโดยGlavić ]


กรณีทดสอบ:

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 timestamp จากนั้นdate('Y-m-d', $t)รับค่าสตริงวันที่ จากนั้นคุณเปรียบเทียบพวกเขาเช่นเดียวกับคำตอบนี้
pedromanoel

2
@pedromanoel: สำหรับอินพุต datetime มาตรฐานที่คุณสามารถใช้ได้strtotimeแต่สำหรับรูปแบบที่strtotimeไม่ได้มาตรฐานที่ไม่รู้จักคุณจะต้องใช้โซลูชันอื่น และสำหรับ php version 5.2 support หยุดทำงานในเดือนมกราคม 2011, 5.3 การสนับสนุนหยุดลงในเดือนสิงหาคม 2014
Glavić

2
พิจารณาวันนี้var_dump( validateDate('2012-2-9'));
รัชกาล

4
ฟังก์ชั่นทำงานอย่างถูกต้อง มันคืนค่าเท็จเนื่องจากรูปแบบ thr ที่คุณระบุไม่ถูกต้อง หากคุณต้องการใช้วันและเดือนที่ไม่มีศูนย์นำหน้ารูปแบบควรเป็น'Y-n-j'@reignsly
Amal Murali

1
@ AntonyD'Andrea: ไม่มันจะไม่ทำงานหากไม่มีส่วนนั้น เพราะ$dจะไม่เป็นเท็จในคุณให้วันที่ซึ่งมีชิ้นส่วน overflown เช่นเดือนที่ 13 (2013-13-01) แต่มันขึ้นอยู่กับสิ่งที่คุณต้องการจริงๆ หากคุณต้องการตัวอย่างvalidateDate('2015-55-66')ที่ถูกต้องแล้วใช่คุณจะต้องตรวจสอบว่า$dเป็นวัตถุหรือไม่
Glavić

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");
Vaibhav Bhanushali

เราสามารถใช้$myDateString = str_replace("/", '-', $myDateString);ก่อนส่งคืนหากสตริงวันที่มีเครื่องหมายทับ (/) เช่น: - dd / mm / yyyy
Yashrajsinh Jadeja

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
วิธีแก้ปัญหาที่ดีตรงไปตรงมาทำงานเป็นครั้งแรกขอบคุณ :)
David Bell

อีกครั้งเมื่อใช้การทดสอบภายในifเพื่อกลับง่าย ๆtrueหรือfalseกลับการทดสอบตัวเอง
Victor Schröder

4
สิ่งนี้ถือว่ามีองค์ประกอบอย่างน้อย 3 รายการในอาร์เรย์ $ tempDate
27

2
@ person27:return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]...
neurino

@vineet - สิ่งนี้ล้มเหลว ถ้าปีคือ2, 20, 202, 2020หรือแม้กระทั่งถ้าปีคือ20201- มันกลับจริงทุกครั้ง
rolinger

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กลับการทดสอบตัวเอง
Victor Schröder

แต่ 2018-3-24 กลับเท็จวิธีได้รับ 2018-3-24 เมื่อรูปแบบจะใช้ผลตอบแทน 2018-03-24; ฉันจะคืนความจริงในสองวิธีได้อย่างไร
Aquiles Perez

12

ตัวเลือกนี้ไม่เพียง แต่เรียบง่าย แต่ยอมรับได้เกือบทุกรูปแบบแม้ว่าจะมีรูปแบบที่ไม่ได้มาตรฐานก็ตาม

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

นี่ควรเป็นคำตอบที่ยอมรับได้! ง่ายกว่านี้มาก
เว็บมาสเตอร์ G

2
สิ่งสำคัญที่ควรทราบคือสิ่งนี้จะไม่ทำงานกับรูปแบบบริติช (d / m / Y) เนื่องจากจะถือว่าเป็นการแปลงแบบอเมริกัน (m / d / Y) ดูเหมือนว่าจะทำงานเฉพาะในกรณีที่วันนั้นต่ำกว่า 12!
ซิลเวสเตอร์ Saracevas

@galki - ฉันทดสอบและไม่ผ่านค่าบางค่า ถ้า $ date = '202-03-31' มันจะคืนค่าจริง แต่นั่นไม่ใช่วันที่ที่ถูกต้อง ฉันพบว่าหากคุณเปลี่ยนปีเป็นปีที่ไม่ถูกต้องก็จะส่งกลับจริง
rolinger

@rolinger แปลก ... บางทีมันอาจจะเห็น 202AD 'strtotime' ประทับเวลาปีใดให้
galki

@galki - ไม่แน่นอน แต่202คืนค่าจำนวนลบ - ซึ่งยังคงผ่านการทดสอบ
rolinger

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 จะเรียกร้องสิ่งที่ซับซ้อนมากขึ้นด้วยการอ้างอิงกลับและหัวมองเชิงลบ
Victor Schröder

9

วิธีที่ง่ายที่สุดในการตรวจสอบว่าวันที่ที่ระบุนั้นถูกต้องหรือไม่อาจแปลงเป็น Unixtime โดยใช้strtotimeการจัดรูปแบบให้เป็นรูปแบบของวันที่ที่กำหนดจากนั้นทำการเปรียบเทียบ:

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

แน่นอนว่าคุณสามารถใช้นิพจน์ทั่วไปเพื่อตรวจสอบความถูกต้อง แต่จะ จำกัด เฉพาะรูปแบบที่กำหนดทุกครั้งที่คุณต้องแก้ไขเพื่อให้เป็นไปตามรูปแบบอื่นและจะต้องเกินกว่าที่กำหนด ฟังก์ชันในตัวเป็นวิธีที่ดีที่สุด (ในกรณีส่วนใหญ่) เพื่อให้ได้งาน


1
ฉันรู้สึกว่าคำตอบนี้มีคุณภาพค่อนข้างต่ำโดยเฉพาะเมื่อพิจารณาว่ามีคำตอบ strtotime อยู่แล้ว
GrumpyCrouton

4
นี่คือคำตอบที่สั้นที่สุดและได้ผล มันค่อนข้างรุนแรงที่จะบอกว่ามันมีคุณภาพต่ำ
ทิมโรเจอร์ส

@ user4600953 - นี่เป็นวิธีที่ง่ายที่สุดที่ใช้งานได้ มีคนอื่นบอกว่าจะใช้checkdate()- แต่ฉันกำลังค้นหาวันที่ตรวจสอบล้มเหลวหากปีเป็นค่าใด ๆ : 2, 20, 202, 2020, 20201- ผลตอบแทนจริงทั้งหมด ฉันจะไปกับทางออกของคุณ!
rolinger

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

@Varricau ไม่คุณไม่ได้ตรวจสอบจะระเบิดถ้าพวกเขาหายไปคุณสามารถเขียน isset () สำหรับทุก ๆ คน แต่ฉันเพียงแค่หยุดการเตือน
Mr Heelis

7

ฉันมีสิ่งนี้ว่าแม้จะมี PHP, ฉันชอบที่จะได้พบกับการทำงานการแก้ปัญหา ตัวอย่างเช่นคำตอบที่ได้รับจาก @migli นั้นเป็นคำตอบที่ดีมีความยืดหยุ่นและสง่างาม

แต่มีปัญหา: ถ้าคุณต้องการตรวจสอบสตริง DateTime จำนวนมากด้วยรูปแบบเดียวกัน คุณจะต้องทำซ้ำรูปแบบทั่วทุกสถานที่สิ่งที่ขัดกับหลักการของDRY เราสามารถกำหนดรูปแบบเป็นค่าคงที่ แต่ยังคงเราจะต้องผ่านค่าคงที่เป็นอาร์กิวเมนต์สำหรับทุกการเรียกใช้ฟังก์ชัน

แต่อย่ากลัวเลย! เราสามารถใช้การแกงเพื่อช่วยชีวิตเราได้! PHP ไม่ได้ทำให้งานนี้น่าพอใจ แต่ก็ยังเป็นไปได้ที่จะใช้ currying กับ 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
คำตอบที่ดีที่สุดโดย IMHO ที่ถล่มทลาย (แก้ปัญหาเฉพาะของ OP ด้วยความยืดหยุ่นที่มากขึ้นและโค้ดในปริมาณที่เท่ากันกับคำตอบที่เหลือ)
StubbornShowaGuy

IMHO นี่เป็นการเขียนโปรแกรมที่น่าเกลียดจริงๆเพียงแค่ใส่ค่าของคุณลงในอาร์เรย์และวนรอบมันเพื่อตรวจสอบความถูกต้อง แต่โปรดอย่าทำเช่นนี้!
ทิม

ฉันอยากรู้ @Tim คุณช่วยยกตัวอย่างการตรวจสอบ array / loop ของคุณให้เราได้ไหม
Victor Schröder

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

แล้วอันนี้ละ?

เราเพียงแค่ใช้บล็อกลอง

$dateTime = 'an invalid datetime';

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

วิธีนี้ไม่ได้ จำกัด เพียงรูปแบบวันที่ / เวลาเพียงรูปแบบเดียวและคุณไม่จำเป็นต้องกำหนดฟังก์ชั่นใด ๆ


สิ่งนี้จะไม่ทำงานสำหรับค่าวันที่และเวลา 0000-00-00 00:00:00
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'เป็นค่าวันที่และเวลาที่ถูกต้อง เป็นเพียงมูลค่าแรก แต่วันที่ทรัพย์สินของวัตถุ datetime '-0001-11-30 00:00:00'จะ
Julian

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

สิ่งนี้จะคืนค่าว่างหากวันที่ไม่ถูกต้องหรือไม่ใช่รูปแบบ yyyy-mm-dd มิฉะนั้นจะส่งคืนวันที่



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
รหัสที่ไม่มีคำอธิบายใด ๆ ไม่มีประโยชน์มาก
Gert Arnold

-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";
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.