Currently, what's is the best to way to check dates and why?
In a "modern way" using DateTime?
$date="2014-02-04";
$dt = DateTime::createFromFormat("Y-m-d", $date);
return $dt !== false && !array_sum($dt->getLastErrors());
Or using regex?
$date="2014-02-04";
return (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date));
Do you have any other comments or suggestions?
with RegEx you can check only correct format of date string.
$date="2014-02-04";
return (preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", $date));
But if you want to check correct date so use checkdate PHP function
$arr = explode("-", $date);
if ( checkdate((int)$arr[1], (int)$arr[2], (int)$arr[0]) ) {
echo "Correct date";
} else {
echo "Incorrect date";
}
The best way is the one that best suits your needs.
If you think a 40 characters long regexp is better than a specialized function that can do the same job more efficiently and with more readable code, then by all means use a regexp.
Using DateTime is certainly the right way.
But if you really want a regex, have a look at here.
With regex we can only check format of the string but using the DateTime functions we can check the date is valid or not. So I prefer to use Datetime function to check date.
Definitely the first way.
Don't use regex for parsing dates or HTML.
Some basic reasons:
Regex is pretty slow when used on non-trivial patterns.
Try to avoid regex if there is a ready-made tailored function or classes on PHP.
Related
I have a date field that I would like to express through a MySQL Query or as a PHP function as yyyymmdd, basically without any - or /, all the examples I can find include these.
I could build it a piece at a time, so y.m.d, but thought someone here might have come across this for, its basically a naming convention for network folders, hence why no special characters.
Thank you in advance
You can use PHP's DateTime Class:
echo (new DateTime($dateField))->format('Ymd');
SQL you can use DATE_FORMAT
DATE_FORMAT(NOW(),'%Y%m%d') //20150513
PHP you can use using date
echo date('Ymd'); //20150513
You can use strtotime() and date() function like this:
$time = strtotime($yourdatefield);
$date = date('Ymd', $time);
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
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
can anyone suggest the neatest way to do this comparison? I need to test if a date provided in dd/mm/yyyy format is less than a fixed date, e.g 01/05/2009 - I know I can convert these to unix time format using strtotime, then make the comparison, but I'm curious if there is a quicker way to do it - many thanks, just looking for a hint to improve my code!
One option is just to reverse the format - create a string of the form
yyyy/mm/dd
That's a sortable format, so you can just do an ordinal string comparison. Of course, this means you won't detect invalid data etc.
There's probably not a shorter way code wise, and I wouldn't bother optimizing this unless you're sure it's a bottleneck.
However, as long as you're sure it will always be the exact same format (including 2 digits for month and day and with 0s) you should be able to reorder the string to put the year first, then the month, and then the day, and then just compare the strings.
However, I'm not sure this would be faster than just letting the libraries convert to unix time and then comparing those.
If you can change the format that the dates are stored in, you could define them as yyyy/mm/dd and then just compare the strings.
I think that your solution of converting it to Epoch then doing a comparison is as fast and as clean as your going to get.
if you want to improve your code, I would suggest you to use DateTime class. It's been introduced in php 5.2.0 (so, it still might not be supported on all servers)
in php 5.3.0 you can write something like this:
$d1 = DateTime::createFromFormat('d/m/Y', '02/03/2009');
$d2 = DateTime::createFromFormat('d/m/Y', '02/05/2009');
$interval = $d1->diff($d2);
echo $interval->format('%R%d days');
Well, you could use the PHP date class, but I am not sure it would be any better than you current solution...
http://php.net/manual/en/book.datetime.php
use this method
yearmonthday
you have 01.05.2010 and 03.07.2010
and to compare : 20100501 <= or => 20100703
$fixedDate = '01/05/2009';
$variableDate = '28/04/2010';
// Now we do our timestamping magic!
$fixedDate = implode('', array_reverse(explode('/', $fixedDate)));
$variableDate = implode('', array_reverse(explode('/', $variableDate)));
if ($variableDate < $fixedDate) // 20100428 < 20090501
{
// there you go
}
What is the best way in php to take the following string mm[some char]dd[some char]yyyy and translate it to yyyymmdd?
I will probably want in the future, according to local do the same with dd[some char]mm[some char]yyyy.
If there is a way that already uses the Zend Framework API, the better
<?php
$str = '08-24-1989'; // can be in any recognizable date format.
$new_str = date('Ymd', strtotime($str)); // produces "20090824".
?>
You can replace Ymd in the second statement above with any date format characters found here.
If you're looking to use Zend's Zend_Date framework, check out some examples and documentation here. Quite frankly though, the PHP functions are a lot simpler and easier to use in your case.
date('Ymd', strtotime($time));
Strtotime is absolutely the best tool to translate almost any time format into a standard one that you can then use Date to put into the format you want.
Because you question title says MySQL Dates, this is the string format that mysql uses.
date('Y-m-d h:i:s', strtotime($time));
Unless [some char] varies , use the mysql str_to_date function, e.g. STR_TO_DATE('12|23|2009','%m|%d|%Y');
I would absolutely use TIMESTAMP for any date storage. It's incredibly easy to handle time differences (like SELECT ... WHERE date BETWEEN 2138728753 AND 376251237) and can be translated to any locale pretty easily :)