How do you validate a date format? - php

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

Related

Determine \DateTime has inferred a day in constructor

I am trying to make user-input accept a date to limit searching. I use the following:
try {
$begin = new \DateTime($range['begin']);
} catch (\Exception $e) {
$begin = null;
}
If the date fails to construct, then the query (not shown) is not modified.
Occasionally the users enter just a month, and it would be obvious then that the user wants to search between the first and last day of the month, and I might modify the query in a different way.
Unfortunately php infers, without other specification that the user means the first of the month. Is there any way to determine if this has happened? Another way to ask this question is how does one determine that a user has supplied a valid month without a day and distinguish that from supplying a date with first day of the month that leverages the myriad formats DateTime automatically interprets?
My first pass used date_parse, but that also infers the date.
better always to know format of input value, so then you can simple convert to datetime object, for example:
$inputFieldValue = '22/02/2017';
$date = \DateTime::createFromFormat('d/m/Y', $inputFieldValue);
if ($date instanceof \DateTime) {
echo 'input is valid date, do what you need';
} else {
echo 'input is not valid date';
}
more documentation http://php.net/manual/en/datetime.createfromformat.php

Format datetime from input string

I'm doing a date search filter where I have my date displayed as "j.n.Y G:i (26.6.2012 15:22)".
A user can enter the whole date or only a portion of it: "26.6","6.2012","6","15:22" are all valid inputs. Because I need to check this date in the database the format needs to be changed to the one of the database. For that I use:
$datum = '25.6.2012';
$date = DateTime::createFromFormat('j.n.Y',$datum);
echo $date->format('Y-m-d H:i');
Where I get an error if $datum is not in the format j.n.Y (if I only enter j.n or one of the above mentioned string portions i get an error).
A problem is also, for the entered string 'j.n.Y', i get the right output of the date, which also has the current time added to the date string (which was not in the initial date string). Example: I enter "22.6.2012", then I get the output "2012-06-22 15:33".
Can these two problems get fixed with existing php functions or should I make my own?
Help would be greatly appreciated.
You can list your acceptable data formats in an array, and loop around DateTime::createFromFormat() to see if any of the inputs produce an acceptable date:
$formats = array( 'j.n', 'j.n.Y');
$datum = '25.6.2012'; $date = false;
foreach( $formats as $format) {
$date = DateTime::createFromFormat( $format, $datum);
if( !($date === false)) break;
}
if( $date === false) {
echo "Invalid date!\n";
}
Finally, if you want to get rid of the current time in the newly created object and set the time to 00:00:00, just use the setTime() method on the date object:
// Sets the time to O hours, 0 minutes, 0 seconds
$date->setTime( 0, 0, 0);
For the first problem, you will need to write some code of your own because some of your acceptable inputs are not among the recognized input formats. Normalizing the input value will require you to fully parse it (a regular expression is a good way to start), and then you can call DateTime::createFromFormat without trouble.
For the second problem, putting an exclamation mark ! at the beginning of your format string would fix the time issue. From the documentation:
If format contains the character !, then portions of the generated
time not provided in format, as well as values to the left-hand side
of the !, will be set to corresponding values from the Unix epoch.
The Unix epoch is 1970-01-01 00:00:00 UTC.
However, since you are going to need to fully parse the input as mentioned above the matter is moot. Also note that the exclamation mark would cause missing values for year, month and day to use defaults that are probably undesirable.

Check if variable is a valid date with 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.

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

Categories