Benar menentukan apakah string tanggal adalah tanggal yang valid dalam format itu

184

Saya menerima string tanggal dari API, dan diformat sebagai yyyy-mm-dd.

Saat ini saya menggunakan regex untuk memvalidasi format string, yang berfungsi ok, tapi saya bisa melihat beberapa kasus di mana itu bisa menjadi format yang benar sesuai dengan string tetapi sebenarnya tanggal yang tidak valid. yaitu 2013-13-01, misalnya.

Apakah ada cara yang lebih baik dalam PHP untuk mengambil string seperti 2013-13-01dan memberi tahu apakah itu tanggal yang valid atau tidak untuk format yyyy-mm-dd?

Marty Wallace
sumber
Kemungkinan duplikat validasi tanggal php
Vivek Athalye
2
Jawabannya di sini jauh lebih baik.
Sebastien

Jawaban:

454

Anda dapat menggunakan DateTimekelas untuk tujuan ini:

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

[ Fungsi diambil dari jawaban ini . Juga di php.net . Awalnya ditulis oleh Glavić . ]


Kasus uji:

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

Demo!

Amal Murali
sumber
14
Jika Anda menggunakan PHP 5.2.x, Anda harus menggunakan strtotimeuntuk mendapatkan cap waktu unix kemudian date('Y-m-d', $t)untuk mendapatkan tanggal string. Kemudian Anda membandingkannya seperti jawaban ini.
pedromanoel
2
@pedromanoel: untuk input datetime standar yang dapat Anda gunakan strtotime, tetapi untuk format non-standar yang strtotimetidak dikenali, Anda akan memerlukan beberapa solusi lain. Dan untuk dukungan php versi 5.2 berhenti pada Januari 2011, untuk dukungan 5.3 berhenti pada Agustus 2014.
Glavić
2
pertimbangkan tanggal inivar_dump( validateDate('2012-2-9'));
memerintah
4
Fungsi ini bekerja dengan benar. Itu kembali salah karena format yang Anda tentukan salah. Jika Anda ingin menggunakan hari dan bulan tanpa memimpin nol, maka formatnya harus 'Y-n-j', @reignsly.
Amal Murali
1
@ AntonyD'Andrea: tidak, itu tidak akan berfungsi tanpa bagian itu. Karena $dtidak akan salah dalam Anda memberikan tanggalnya, yang memiliki bagian berlebih, seperti bulan ke 13 (2013-13-01). Tapi itu sangat tergantung apa yang Anda inginkan. Jika Anda perlu misalnya validateDate('2015-55-66')valid, maka ya, Anda hanya perlu memeriksa apakah $dobjek atau tidak.
Glavi
81

Tentukan apakah string adalah tanggal

function checkIsAValidDate($myDateString){
    return (bool)strtotime($myDateString);
}
arsh
sumber
2
Ini memvalidasi seluruh jajaran format tanggal yang valid tidak hanya yyyy-mm-dd.
EWit
10
@MichelAyres ini karena php melihat 2015-02-30sebagai tanggal yang valid karena ketika hari yang diberikan lebih besar dari jumlah hari pada bulan tertentu (atau negatif) php beralih ke bulan berikutnya. Karena tanggal dijamin dari format yyyy-mm-ddini dapat diperbaiki dengan mengubah kembali ke return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21
2
Mengapa (bool)strtotime('s')benar?
Peon
ini juga mengembalikan 1 checkIsAValidDate ("F");
Vaibhav Bhanushali
kita dapat menggunakan $myDateString = str_replace("/", '-', $myDateString);sebelum kembali jika string tanggal berisi garis miring (/) seperti: - dd / mm / yyyy
Yashrajsinh Jadeja
37

Gunakan dengan cara sederhana dengan fungsi php prebuilt:

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

Uji

   checkmydate('2015-12-01'); //true
   checkmydate('2015-14-04'); //false
anggur
sumber
1
Solusi mudah yang bagus, bekerja pertama kali, terima kasih :)
David Bell
Sekali lagi, saat menggunakan tes, di dalam ifuntuk mengembalikan secara sederhana trueatau false, mengembalikan tes itu sendiri.
Victor Schröder
4
Ini mengasumsikan setidaknya ada 3 elemen dalam array $ tempDate.
27
2
@ person27:return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]...
neurino
@vineet - ini gagal. Jika tahun ini 2, 20, 202, 2020atau bahkan jika tahun ini 20201- itu mengembalikan true setiap waktu.
rolinger
16

Tentukan apakah string adalah tanggal, meskipun string adalah format non-standar

(strtotime tidak menerima format khusus)

<?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');
migli
sumber
Saat menggunakan tes, di dalam sebuah ifuntuk mengembalikan secara sederhana trueatau false, mengembalikan tes itu sendiri.
Victor Schröder
Tapi 2018-3-24 kembali salah, metode menerima 2018-3-24, ketika format ini berlaku kembali 2018-03-24; bagaimana saya bisa mengembalikan true dalam dua cara?
Aquiles Perez
12

Opsi ini tidak hanya sederhana tetapi juga menerima hampir semua format, meskipun dengan format non-standar dapat menjadi buggy.

$timestamp = strtotime($date);
return $timestamp ? $date : null;
galki
sumber
Ini seharusnya jawaban yang diterima! Jauh lebih sederhana.
Webmaster G
2
Penting untuk dicatat bahwa ini tidak akan berfungsi dengan format Inggris (d / m / Y) karena akan menganggap itu mengonversi Amerika (m / d / Y). Tampaknya akan berfungsi hanya jika hari lebih rendah dari 12!
Sylvester Saracevas
@ galki - saya menguji ini dan gagal nilai-nilai tertentu. Jika $ date = '202-03-31' itu mengembalikan true. Tapi itu bukan tanggal yang valid. Saya menemukan bahwa jika Anda mengubah tahun menjadi tahun yang tidak valid, itu selalu menghasilkan true.
rolinger
@rolinger aneh ... mungkin melihat 202AD? Stempel waktu tahun berapa yang diberikan 'strtotime'?
galki
@ galki - tidak pasti, tetapi 202mengembalikan angka negatif - yang masih lulus tes.
rolinger
10

Anda juga dapat menguraikan tanggal untuk tanggal dan tahun bulan lalu Anda dapat menggunakan fungsi PHP checkdate()yang dapat Anda baca di sini: http://php.net/manual/en/function.checkdate.php

Anda juga dapat mencoba yang ini:

$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';
    }
Suvash sarker
sumber
dalam kasus februari (seperti yang dikomentari oleh elitechief21) fungsi 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
Solusi ini sangat buruk, karena tidak memeriksa validitas tanggal dalam arti apa pun. Setiap bulan dapat memiliki 31 hari, termasuk Februari. Setiap tahun dapat memiliki 29 Februari. Untuk memvalidasi tanggal menggunakan RegExp akan menuntut sesuatu yang jauh lebih kompleks, dengan referensi balik dan pandangan negatif ke depan.
Victor Schröder
9

Cara termudah untuk memeriksa apakah tanggal yang diberikan valid mungkin mengubahnya menjadi unixtime menggunakan strtotime, memformatnya ke format tanggal yang diberikan, kemudian membandingkannya:

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

Tentu saja Anda dapat menggunakan ekspresi reguler untuk memeriksa validitas, tetapi akan terbatas pada format yang diberikan, setiap kali Anda harus mengeditnya untuk memenuhi format lain, dan juga akan lebih dari yang diperlukan. Fungsi bawaan adalah cara terbaik (dalam banyak kasus) untuk mencapai pekerjaan.


sumber
1
Saya merasa bahwa jawaban ini kualitasnya cukup rendah, terutama mengingat sudah ada jawaban strtotime.
GrumpyCrouton
4
Ini adalah jawaban terpendek dan berhasil. Agak sulit untuk mengatakan bahwa kualitasnya rendah.
Tim Rogers
@ user4600953 - ini adalah yang termudah yang berfungsi. Banyak orang lain mengatakan untuk menggunakan checkdate()- tetapi saya menemukan checkdate gagal jika tahun adalah nilai APA PUN: 2, 20, 202, 2020, 20201- semua kembali benar. Saya akan pergi dengan solusi Anda!
rolinger
7

Sesuai dengan jawaban cl-sah, tapi ini terdengar lebih baik, lebih pendek ...

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

Uji

checkmydate('2015-12-01');//true
checkmydate('2015-14-04');//false
sdotbertoli
sumber
Anda harus menguji apakah count($tempDate) === 3meskipun
VDarricau
@VDarricau tidak, checkdate akan mengebom jika mereka hilang, Anda dapat menulis isset () untuk setiap orang tetapi saya hanya akan menekan peringatan
Mr Heelis
7

Saya memiliki hal ini, bahkan dengan PHP, saya suka mencari solusi fungsional . Jadi, misalnya, jawaban yang diberikan oleh @migli benar-benar bagus, sangat fleksibel dan elegan.

Tetapi memiliki masalah: bagaimana jika Anda perlu memvalidasi banyak string DateTime dengan format yang sama? Anda harus mengulangi format di semua tempat, yang bertentangan dengan prinsip KERING . Kita bisa meletakkan format dalam konstanta, tetapi tetap saja, kita harus meneruskan konstanta sebagai argumen untuk setiap pemanggilan fungsi.

Tapi jangan takut lagi! Kita bisa menggunakan kari untuk menyelamatkan kita! PHP tidak membuat tugas ini menyenangkan, tetapi masih memungkinkan untuk menerapkan currying dengan PHP:

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

Jadi, apa yang baru saja kita lakukan? Pada dasarnya kami membungkus fungsi tubuh dalam anonim dan mengembalikan fungsi tersebut sebagai gantinya. Kami dapat memanggil fungsi validasi seperti ini:

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

Ya, bukan perbedaan besar ... tetapi kekuatan sebenarnya berasal dari fungsi yang diterapkan sebagian , dimungkinkan oleh kari:

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

Pemrograman fungsional FTW!

Victor Schröder
sumber
2
Jawaban terbaik oleh IMHO longsor (memecahkan masalah spesifik OP dengan fleksibilitas yang lebih besar dan jumlah kode yang hampir sama dengan sisa jawaban)
StubbornShowaGuy
IMHO ini benar-benar pemrograman yang buruk, cukup masukkan nilai-nilai Anda dalam array dan lewati untuk memvalidasi, tapi tolong jangan lakukan ini!
Tim
Saya ingin tahu @Tim, dapatkah Anda memberi kami contoh validasi array / loop Anda?
Victor Schröder
5

Saya khawatir solusi yang paling banyak dipilih ( https://stackoverflow.com/a/19271434/3283279 ) tidak berfungsi dengan baik. Kasing uji keempat (var_dump (validateDate ('2012-2-25')); // false) salah. Tanggalnya benar, karena sesuai dengan format - m memungkinkan satu bulan dengan atau tanpa memimpin nol (lihat: http://php.net/manual/en/datetime.createfromformat.php ). Oleh karena itu tanggal 2012-2-25 dalam format Ymd dan test case harus benar bukan salah.

Saya percaya bahwa solusi yang lebih baik adalah dengan menguji kemungkinan kesalahan sebagai berikut:

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

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

Bagaimana dengan yang ini?

Kami cukup menggunakan blok coba-tangkap.

$dateTime = 'an invalid datetime';

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

Pendekatan ini tidak terbatas hanya pada satu format tanggal / waktu, dan Anda tidak perlu mendefinisikan fungsi apa pun.

Julian
sumber
ini tidak akan bekerja untuk nilai datetime 0000-00-00 00:00:00
Naseeruddin VN
@NaseeruddinVN '0000-00-00 00:00:00'adalah nilai datetime yang valid. Ini hanya nilai pertama. Namun, properti tanggal objek datetime akan menjadi '-0001-11-30 00:00:00'.
Julian
1

Solusi Regex yang diuji:

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

Ini akan mengembalikan nol jika tanggal tidak valid atau bukan format tttt-bb-tk, jika tidak maka akan mengembalikan tanggal.

Akumaburn
sumber
1

Validasi dengan fungsi checkdate :

$date = '2019-02-30';

$date_parts = explode( '-', $date );

if(checkdate( $date_parts[1], $date_parts[2], $date_parts[0] )){
    //date is valid
}else{
    //date is invalid
}
Pangeran Ahmed
sumber
Dokumentasi untuk checkdate: w3schools.com/php/func_date_checkdate.asp
Prince Ahmed
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) === '-');
}
Marco Demaio
sumber
-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);
        }

    }
Subham Ghorui
sumber
1
Kode tanpa penjelasan apa pun tidak terlalu berguna.
Gert Arnold
-2

Cobalah ini:

$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";
}
Youssef Gamra
sumber