Check if variable is a valid date with PHP
Asked Answered
S

3

39

I am working on a script that will import some data from a CSV file. As I am doing this I want to be able to check a variable to see if it is a valid date string.

I have seen several ways to check if a sting is a date, but most of them require you to now the format. I will not know the format that the date will in.

right now I am using strtotime(), but this fails to easily

$field ="May";
if(strtotime($field)){
    echo "This is a date";
}

In this case, "May" was the persons first name, and not a date at all.

Can any one recommend more reliable function?

Edit based on questions from some of you.

For a variable to pass as a "date" in my case, it would need to be specific to a day/month/year, so just "May" would be to vague to count.

Based on that and Pauls good point below we can also test to see if the string contains a number, such as

$field ="May";
if(strtotime($field) && 1 === preg_match('~[0-9]~', $field)){
    echo "This is a date";
}else{
    echo "Nope not a date";
}

This seems to cover my immediate needs, but can any one spot any issues or suggest improvements?

Schuler answered 21/5, 2012 at 20:13 Comment(12)
How would your script tell whether May was a name or a date?Implosion
You need to give some specifications what kind of values you accept. Otherwise "May" is just as good as any other value.Beechnut
Check if the person has a last-nameTutankhamen
Are you testing every single field you're getting to check if it is a date? Doesn't your Excel file have some sort of general format that it follows, like firstName, lastName, date, where you'd only need to check every third field or something?Ecclesiology
Aminuson, sadly I will be getting data from different sources so can not count on any consistancy.Schuler
Is there any pattern at all? Do the months appear numerically as well as in a string? Are the dates separated in cells, i.e. Month in A1, Day in B2, or are they all in one cell?Zoubek
Jahana, good point. For a field to be a "date" it would have to be specific to an exact year and day, so "May" is just to vagueSchuler
Paul Good point! Yes the date string I would need would have to have a number in it as well as just the word "May" to be valid.. So if(strtotime($field) && 1 === preg_match('~[0-9]~', $field)){} would be one step better!!Schuler
@Schuler - Yeah, That's a tough one, but at least you could filter it a little more. I'm sure you could get this a little more accurate, but that's beyond my skills. :)Zoubek
You are trying to interpret data in an unknown pattern that may or may not be a date... thats going to be tough. My concern is that if the input data is going to be that vague, you could mis-interpret the data and do more harm than good than if you just accepted what it gave you.Camelopardus
@Alex: Just matching a number in input is far from satisfactory as it can take '0May' as valid date.Kay
FluffyKitten, Agree. My detection at this point will be used to provide a "Best Guess" to users in a second import step, where they will have the ability to review a sample of X records, and confirm the data format and correct mapping to the database fields.Schuler
E
57

Use date_parse and check the values of the returned array

$date = date_parse("May")

// ["year"] == FALSE
// ["month"] == 5
// ["day"] == FALSE

You can also pass those into checkdate.

$date = date_parse($someString);
if ($date["error_count"] == 0 && checkdate($date["month"], $date["day"], $date["year"]))
    echo "Valid date";
else
    echo "Invalid date";
Eupatrid answered 21/5, 2012 at 20:42 Comment(6)
I think you got it... Can any one see any flaws with this?Schuler
A tiny flaw: date_parse uses the strtotime parsing rules, which are well-defined but finicky. It's possible to submit data that returns a legal date but is not what was intended.Nabokov
@Nabokov without requiring a well-defined format for input, any algorithm to parse a date automatically will have issuesEupatrid
I know this is old, but if you used date_parse("2014-01-01 12:00:00'; select * from users;") it will say the date is valid. However, the $date['error_count'] will be greater than 0, which might be a better option to go through. see ideone.com/Xl1HTbArabinose
@joseph4tw Good point. I've updated the answer to include checking the error count on the date_parse.Eupatrid
@Eupatrid $date["errors"] is an array, thus it will always be false. I think what you need is $date["error_count"]Genagenappe
T
5

I don't think there is a all-in-one answer to this problem. You may have different strategy depending on your use case.

Your strtotime() is a perfect solution, but as you say, you may end up with false positive. Why? Because may may be a word or a name. However, what is the result of strtotime('May')?

echo date(DateTime::ISO8601, strtotime('May'));
2012-05-21T00:00:00+0200

So giving only the month will return a date of the current year and the current day starting at midnight with the given month. A possible solution would be to check if your string has the current day and/or the current year included, this way, you may check against to make sure your date is a fully qualified date and valid.

echo date(DateTime::ISO8601, strtotime('May Day')); // (strtotime() returns false)
1970-01-01T01:00:00+0100

echo date(DateTime::ISO8601, strtotime('May 21'));
2012-05-21T00:00:00+0200

A simple strpos() or even a regex should do the trick.

However it is a bit odd and should be used only if you have no other way to do.

I believe that a better solution would be to define a set of valid format and interpolate the result to make sure that the date is valid.

$validDateFormatPatterns = array(
 '[0-9]{1,2}-[0-9]{1,2}-[0-9]{4}', // 21-05-2012, obviously this pattern is simple and would accept 05-21-2012,
 'the [0-9]{1,2}(th|st|nd|rd) (January|February|...|May|...|December) [0,9]{4}', // The 21st May 2012
);

You should try to cover most of the case and I'm sure you will be able to find regex that checks for most current date format.

In any case, you may need to adapt your function from time to time because there is no easy way to make it bulletproof.

Timeout answered 21/5, 2012 at 20:39 Comment(0)
S
1

I know this was asked a long time ago, but looking around for this and trying to avoid regex, I came up with this:

function checkInputIsDate($date) {
    return (bool)strpbrk($date,1234567890) && strtotime($date);
}

This works because it takes away the issues posted above where only a month is passed into strtotime by making sure there are numbers in the string with strpbrk as well as verifying strtotime outputs a date.

And learned about a function I didn't know existed.

Hope this helps someone.

Sealey answered 10/1, 2016 at 5:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.