Check if variable is a valid date with PHP - php

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?

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

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.

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.

Related

Timestamp Difference and Output

In My SQL Database I have a Timestamp Column with values like this one representing the Date of the last edit:
2015-01-17 08:55:34.000000
I want to compare the Date with the current date and when is the same day I want to echo Today and otherwise I want to Display the Date of the last edit:
$timefromdb = '2015-01-17 08:55:34.000000'
$edit = strtotime($timefromdb);
if($edit > $_SERVER['REQUEST_TIME']){echo "Today";}
else{
echo strftime("on %A, the %d %B %Y", $edit);
}
echo " at ".date('h:i',$edit)
It always Displays 01/01/1970. There must be a Problem with strtotime. I did a bit of research and it seems like my Timestamp Format isn't a valid one: http://php.net/manual/en/datetime.formats.php
Around the web are a lot of Questions about converting Timestamps but I just can't find the right one: I also got a bit confused by all the functions to convert date stuff.
So can someone Tell me how to get a valid Timestamp for using it in strftime and to compare it to the REQUEST_TIME.
Thanks in Advance!
UPDATE: As Always: The Problem sits in Front of the PC. I declared the Variable but never assgined the Timestamp to it :)
Chop off the .000000 from the date as it makes the date a format strtotime() cannot work with. There's several ways to do this. A simple substr is one of them.
$timefromdb = substr('2015-01-17 08:55:34.000000', 0, -7);
I'm not exactly understood you, but
try
1. compare gettype( $edit ) and gettype($_SERVER['REQUEST_TIME'])
2. not sure what $timefromdb will be more then $_SERVER['REQUEST_TIME'], because IMHO when user edited data, time of it action will me less then current time.

How do you validate a date format?

I want my users to be able to change the date format to whatever they like:
$dateformat = $_POST['format'];
$datestamp = date($dateformat,$timestamp);
How do I check if $dateformat is a correct valid date format string?
if( strtotime($_POST['format']) !== FALSE)
{
echo 'valid date';
}
else
{
echo 'invalid date';
}
But will not work on dates having year > 2048 as not defined in current PHP
checkdate() will tell you whether the date can be parsed should you decide to stick with a certain format:
strtotime() will let you know if a date string can be parsed - you can pass it any string. If the date cannot be parsed, the function returns false.
As a side note: I wouldn't let the user choose how to enter dates. This will make it very complicated for you, obviously - but also as user I would ask myself how I am supposed to enter the date, since most of the users will be used to instruction with regard to dates. Why not provide them with a simple drop down for year, month and date, and then use these three parameters with checkdate()?
I'd recommend you provide your users with a select drop down of various date formats then storing it in a database. You can then pull their selected format and insert it into the first parameter of the date() function.
Have a look into Zend_Date, but without knowing to interpret 06-03-2012 as 6th march or 3rd june it is not possible.
You know? 12/12/12 is the date, were the europeans and the americans can talk about the day without misunderstanding ;-)
Here's a regex implementation:
$input = 'M d Y';
if(preg_match('#(dd|DD|m|M|mm|MM|y|yy|YY|-|\s)+#', $input)) {
$valid = true;
print date($input);
} else {
print "invalid date format";
}
It assumes that the space char and dash chars are allowed.
It specifies flags listed here: http://php.net/manual/en/datetime.formats.date.php
More here: http://php.net/manual/en/function.date.php

preg_match: check birthday format (dd/mm/yyyy)

How do I make the expression which checks the birthday input to match a format like this dd/mm/yyyy? Below is what I came out so far, but it takes this too if I put 99/99/9999!
if (!preg_match("/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/", $cnt_birthday))
{
$error = true;
echo '<error elementid="cnt_birthday" message="BIRTHDAY - Only this birthday format - dd/mm/yyyy - is accepted."/>';
}
How can I make sure that its only 01 to 31 for dd and 01 to 12 for mm? but I am sure how to restrict yyyy... I think theoritical 9999 should be acceptable... let me know if you have a better idea!
thanks,
Lau
Based on Tim's checkdate based solution:
The extraction of day, month and year can easily be done using explode as:
list($dd,$mm,$yyyy) = explode('/',$cnt_birthday);
if (!checkdate($mm,$dd,$yyyy)) {
$error = true;
}
I would suggest using checkdate() for this instead:
if (preg_match("/([0-9]{2})\/([0-9]{2})\/([0-9]{4})/", $cnt_birthday, $matches)) {
if (!checkdate($matches[2], $matches[1], $matches[3])) {
$error = true;
echo '<error elementid="cnt_birthday" message="BIRTHDAY - Please enter a valid date in the format - dd/mm/yyyy"/>';
}
} else {
$error = true;
echo '<error elementid="cnt_birthday" message="BIRTHDAY - Only this birthday format - dd/mm/yyyy - is accepted."/>';
}
So regexp validates the format, checkdate validates the actual date.
Consider using strtotime() and reformat it with date(). It will provide more flexibility for users while entering a date and let's you use whatever formats you need in different places.
Personally, I am pretty lazy when it comes to accurate date calculation and abuse it like strtotime("-10 day",$timestamp). This has the benefit of lower possibility of getting sued by an annoyed parent becuse you calculated their little daughters age to be just above 18, not accounting for leap years correctly, and let her to your adult themed site, however ridiculous it may sound.
if(preg_match("/(\d{2})\/(\d{2})\/(\d{4})$/", $date,$matches)){
return (checkdate((int) $matches[2],(int)$matches[1],(int) $matches[3]) );
}else{
return false ;
}
preg_match to validate pattern dd/mm/yyyy
checkdate to validate date values
$ok = DateTime::createFromFormat('d/m/Y',$datestring)->format('d/m/Y') == $datestring;
PHP >= 5.3
To be really anal-retentive it might be easier to use your current regex, parse the numbers, then verify they're in range with checkdate(), but for kicks, here's the regex that ensures dates = 01-31 (and 1-9), and month = 01-12 (and 1-9).
preg_match("/([012]?[1-9]|[12]0|3[01])\/(0?[1-9]|1[012])\/([0-9]{4})/", $date_string)
Couple things of note
I've used grouping on all, required for the ORing (|) within, but also useful to extract those values if you want to do specific things with them
0000 doesn't make much sense as a date, but I've left the explosion of that regex as an excersise to the reader. If you really want this to verify birthdates (and you're expecting currently or relatively recently deceased people) restrict that to say 1900+ or 1800+, or whatever is an acceptable range for you. If you might be parsing historical figures' birthdays... your call.
This still doesn't check that the date range is correct for the month in question! so for that use checkdate()
maybe something like this would help
list($month,$day,$year)=explode("/",$date);
if(checkdate($month,$day,$year))
{
echo "good";
}
else{echo "bad";}
Only accepting a strictly formatted string is probably a bad practice. Assuming you're getting input from a webpage, it would be better to have separate fields for month, day, and year. They could just be text boxes, but it might be preferable to have drop-down menus, which would solve your limits problem (i.e. the only choices for month are 1,2,...,12). Requiring that users enter 01/01/2001 and not accepting 1/1/2001 is lazy programming. And only accepting "/" as a separator is awkward.
But, to touch on your original question even if you decide to stick with formatted strings — since it's a birthdate field, you should probably restrict the yyyy to:
if($yyyy > date('Y')) {
echo '<error elementid="cnt_birthday" message="BIRTHDAY - Year must be less than or equal to the current year."/>';
}
Otherwise people could have negative ages :)
Probably not the best solution, but here's my try.
You convert it to a time, and then reformat it back to the m/d/Y. If the string is unchanged, then, it was in the correct format to begin with.
$transformedDate = date("m/d/Y", strtotime($myDate));
if($transformedDate == $myDate){
return true;
} else{
return false;
}
Try this regex : ([0-9]{2}\/[0-9]{2}\/[0-9]{4})
I'm late to see this, but this solved my problem
if (1 !== preg_match('/(0[1-9]|1[0-9]|2[0-9]|3(0|1))\/(0[1-9]|1[0-2])\/\d{4}/',$value)) {
$this->form_validation->set_message('validate_emaildate','Date needs to have a valid date format - dd/mm/yyyy');
return FALSE;
}
Courtesy the following posts:
Regex format here.. thanks Abin.
Function to check the format [here]
(Codeigniter's regex match)
.. thanks Hashem
+cheers

How to check the data format in PHP

I am trying to check a date format to see if I can check the data variable has certain format like MM-DD-YYYY. if not, then exit(). I am not sure how to check the format and would appreciate if any one can help me about it. Thanks...
$date=05/25/2010;
if(XXXXX){
// do something....
}
you can use regular expressions
if(preg_match("/([0-9]{2})\/([0-9]{2})\/([0-9]{4})/"))
{
do something
}
Use a regular expression, as others have suggested. The ones posted before will accept invalid dates such as 99/99/9999 however. Here's an improved regex (lifed from here)
$date_regex = '!^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$!';
if (preg_match($date_regex, $date)) {
// do something
}
It will only take valid dates and it will also accept different separators (such as 05.20.2002 and 05-02-2002).
If you ask me it's bad user experience to force them to enter a particular format. YOU can handle different formats using strtotime().
If you are trying to do this to limit user's input, you can always use strtotime() on the users input and convert it to a unix timestamp then use the date() function to display it how you want to.
If you really want to determine if it is in a certain format, or only require a certain format, a preg_match() with a regular expression will be of assistance, I believe on that page they have examples of parsing dates. If not it would be something like this:
if (preg_match('~[0-9]{2}-[0-9]{2}-[0-9]{4}~', $dateStr)) { echo 'Correct format'; }
The obvious flaw with that is the date may pass the format test, but may not be a valid date. In my opinion, accept any date in the user input and use the strtotime / date to get it to the format you want.
http://us.php.net/strtotime
If I understand you correctly, you want to check a string to make sure it follows the MM-DD-YYYY pattern?
If so, I would suggest two checks: one to make sure it follows the general pattern of digits, and another to check that the months are first and days are second.
function checkDate( $date )
{
if (preg_match("/[0|1][0-9]/[0-9][1-9]/[0-9]{4}/",$date)
{
if (substr($date,0,2)<=12 && substr($date,3,2)<=31)
{
return true;
}
}
return false
}
Update: Added an additional check on the days to make sure it is valid, based on NullUser's comment
http://php.net/manual/en/function.date-parse.php

Correct Regular expressions to match a date

What is the correct regular expression to use to validate a date like. 2009-10-22 or 2009-01-01 etc. Platform PHP
This (from regexplib.com) will match what you want, and perform checks for leap years, days-per-month etc. It's a little more tolerant of separators than you want, but that can be easily fixed. As you can see, it's rather hideous.
Alternatively (and preferably in my opinion) you may want to simply check for figures in the correct places, and then perform leap year and days-per-month checks in code. Sometimes one regexp isn't so understandable and there's greater clarity in performing the checks in code explicitly (since you can report precisely what's wrong - "only 30 days in November", rather than a "doesn't match pattern" message, which is next to useless)
If you want something simple that does a little more than just validates format, but doesn't go as far as validating how many days is in the month that is entered, or leap years, you can use this:
^(19|20)[0-9]{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$
This example allows years 19xx and 20xx
As you have to deal with accepting 2009-02-28 but not 2009-02-29 but accept 2008-02-28 you need more logic that 1 think a regex can give. (But if someone can show it I would be impressed)
I would try to convert it to a date and report if the conversion failed or if you you language has a check date function use that.
\d{4}-\d{2}-\d{2} would match string in that form, but to check if date is valid, you'd had to break that string to year, month and date (you can use this regexp for that) parts and check each of them.
You can additionally, make sure that year must start with 1 or 2: [12]\d{3}-\d{2}-\d{2}, and you can also do the same for month and day: [12]\d{3}-[01]\d-[0123]\d (but I would go with the first regexp and compare parts "manually")
found this on the web tested it with a few dates and looks stable, for dates between 1900 and 2000:
(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])
OK, a regex that will validate month and day ranges could be
[0-9]{4}-(?:1[0-2]|[1-9])-(?:3[01]|[12][0-9]|[1-9])
If you want to restrict the years, say, from 1900 to 2050, you could end up with
(?:2050|20[0-4][0-9]|19[0-9]{2})-(?:1[0-2]|[1-9])-(?:3[01]|[12][0-9]|[1-9])
They will not catch "subtly wrong" dates like February 31st, so it's really quite clear that a sanity check needs to be performed outside of the regex.
In .NET Regex:
\d{4}\-\d{2}\-\d{2}
[0-9]{4}-[0-9]{2}-[0-9]{2}
or
\d\d\d\d-\d\d-\d\d
or
...
simply read first regex tutorial
^\d{4}-\d{2}-\d{2}$
but no regular expression can prevent someone to enter "9867-39-56"
For a complete validation (which would include verifying that the day, month and year parts are valid) a Regex is not the tool of choice. Apart from month issues you'd get into trouble with leap years...
So, if you just want to check if the rough format is correct, or isolate the different parts (year-month-day), a regex is fine.
([0-9]{1,4})-(1[012]|0?[1-9])-([12][0-9]|3[01]|0?[1-9])
This is already pretty exact and captures the year (0..9999), month and day into capture groups, ready for parsing...
If you can rely on more than a regular expression, an hybrid solution by using Posix functions date() and time() delivered with PHP could look like this:
<?php
date_default_timezone_set("GMT");
function validateDate($date)
{
if (preg_match("^[0-9]{4}-[0-9]{2}-[0-9]{2}^", $date))
{
return date('Y-m-d', strtotime($date)) === $date;
}
return false;
}
// Some tests
$dates = array(
'2009-09-09', '2009-09-32', '2009-31-00', '2035-01-02',
);
foreach($dates AS $date)
{
echo $date .': '. (validateDate($date) ? 'OK' : 'FAILS') ."\n";
}
?>
It's not elegant plus you'll be limited by Unix Epoch time (from January 1 1970 00:00:00 GMT to January 19 2038 03:14:07 GMT), but it's reliable and it's well supported in PHP.

Categories