Sergio Santopietro
Sergio Santopietro

Reputation: 86

How to validate dates without leading zero on day and month?

I need to validate a precise date format in php.

In my case the optimum date format should be: e.g. 1/1/2017 (without leading zeros) and the code should allow me to avoid the rest of date's format.

The following code is what i wrote but with no result:

if(preg_match("/([1-9]|[1-2][0-9]|3[0-1]-([1-9]|1[0-2])-^[0-9]{4})$/", $date){
    // insert into etc. etc....
}else{
    // update etc. etc....
}

The problem is that the code doesn't properly validate the date; it accepts every kind of date format.

Upvotes: 6

Views: 24062

Answers (4)

Turan Zamanlı
Turan Zamanlı

Reputation: 3926

you can use with Carbon

$date->format('j')

Upvotes: 8

mickmackusa
mickmackusa

Reputation: 47874

I noticed that the OP's submitted answer was not bulletproof, so I started to research some of the functions mentioned in the comments under the question and some of my own thoughts.

I agree with apokryfos in that using regex to validate a date expression is not best practice. A pure regex solution is going to be an increasingly verbose and decreasingly comprehensible pattern because it will have to factor leap years both in the past and future. For this reason, I've investigated a few date functions that php has on offer.

  1. date_parse_from_format() as suggested by Alex Howansky. Unfortunately, it will not be a stand-alone solution for this case because the format parameter obeys the syntax/rules of DateTime::createFromFormat():

enter image description here

See how d and j are grouped together, as are m and n. Consequently, this function will catch invalid dates, but not the unwanted leading zeros.

  1. strptime() as suggested by Casimir et Hippolyte. This function affords matching days without leading zeros using %e. This function does not have a character that matches non-zero-leading month numbers. Furthermore, there can be hiccups with this function bases on the operating system.

  2. check_date() seems like a logical choice, but again it will not flinch at zero-led numbers. Furthermore, this function requires a bit more data preparation than the others, because it requires the month, day, and year values to be individualized.

  3. if(!DateTime::createFromFormat('j/n/Y', $date)) suggested by deceze regarding a slightly different scenario will not work in this case. createFromFormat() will go to great lengths to construct a valid date -- even a string like 99/99/9999 will make it through.


In an attempt to create the most concise expression, here is what I can offer as a seemingly bulletproof solution using a DateTime class:

if (($d=DateTime::createFromFormat('n/j/Y',$date)) && $date==$d->format('n/j/Y')){
    // valid
}else{
    // invalid
}

strtotime() can be used with a single condition for this case because the OP's date format uses slashes as a delimiter and this function will correctly parse the date expression "American-style".

This seems to be the simplest way to check for a valid date without leading zeros: Demo Link

if(date('n/j/Y',strtotime($date))==$date){
    // valid
}else{
    // invalid
}

If you are dealing with datetime expressions and don't wish to check the time portion, you can call this line before conditional line:

$date = explode(' ', $date)[0];  // create an array of two elements: date and time, then only access date

Demo Link

or

$date = strstr($date, ' ', true); // extract substring prior to first space

Upvotes: 12

Sergio Santopietro
Sergio Santopietro

Reputation: 86

After several hours finally i found the correct answer. The correct pattern for php is to use single quote (') and not the double quote (") e.g.:

preg_match('/^([1-9]|[1-2][0-9]|3[0-1])\/([1-9]|1[0-2])\/([0-9]{4})/',$date)

this works fine for me... Thanks everyone especially to @Mohammad Hamedani 'cause the expression was correct but the f******g quote makes me gone crazy

Upvotes: 0

Mohammad Hamedani
Mohammad Hamedani

Reputation: 3354

Your date delimiter is / and not -, so add \/ to regex for /. And use ^ at the start of regex:

if(preg_match("/^([1-9]|[1-2][0-9]|3[0-1])\/([1-9]|1[0-2])\/([0-9]{4})$/", $date){

Upvotes: 2

Related Questions