I am working with arrays of values in PHP. Some of these values may include a date in various string formats.
I need to convert dates in multiple formats to their numerical equivalent (Unix timestamp). The problem is being able to determine if the string is a date.
Using
if (($timestamp = strtotime($str)) === false)
will check for a valid date from a string but how do I determine if the value should even be validated as a date?
Example:
$x = {1,2,3,"4","11/12/2009","22/12/2000",true,false};
foreach($x as $value)
{
if(is_bool($value))
if(is_string($value))
if(is_numeric($value))
if(is_date($value)) ?
...
}
In short, is there an easy way to check if a string value is a date?
In short, is there an easy way to check if a string value is a date?
Not really, seeing as it could be in an arbitrary format.
If at all possible, I would tend to leave parsing to the magic of strtotime(). If it manages to create a valid date, fine. If it doesn't, you'll receive false.
Be prepared for the possibility of false positives, though, because strtotime() parses even things like "Last Friday".
If strtotime() is too liberal for you, you could consider building a collection of date formats you want to accept, and run PHP 5.3's DateTime:createFromFormat using every one of the formats on every date.
Something like (untested)
$formats = array("d.m.Y", "d/m/Y", "Ymd"); // and so on.....
$dates = array(1,2,3,"4","11/12/2009","22/12/2000",true,false);
foreach ($dates as $input)
{
foreach ($formats as $format)
{
echo "Applying format $format on date $input...<br>";
$date = DateTime::createFromFormat($format, $input);
if ($date == false)
echo "Failed<br>";
else
echo "Success<br>";
}
}
The problem with Pekka's script is that the date '2011-30-30' is also considered valid. This is the modified version.
$formats = array("d.m.Y", "d/m/Y", "Ymd"); // and so on.....
$dates = array(1,2,3,"4","11/12/2009","22/12/2000",true,false);
foreach ($dates as $input)
{
foreach ($formats as $format)
{
echo "Applying format $format on date $input...<br>";
$date = DateTime::createFromFormat($format, $input);
if ($date == false || !(date_format($date,$format) == $input) )
echo "Failed<br>";
else
echo "Success<br>";
}
}
Extrapolating from http://au1.php.net/checkdate#113205 ;
just change the $formats array to all the formats you want to check.
public function convertDate($value) {
$formats = ['M d, Y', 'Y-m-d'];
foreach($formats as $f) {
$d = DateTime::createFromFormat($f, $value);
$is_date = $d && $d->format($f) === $value;
if ( true == $is_date ) break;
}
return $is_date;
}
Related
I'm trying to make a function that formats dates from nested arrays lying in the same array. I'm able to locate and echo the values in the array, however I'm struggling to format the date into the way I want to print it out. The way my code is set up I have one function that goes into the array, iterates over each of the nested arrays and prints out the value attached to the key that it is set to look for.
That works fine, but my other function is meant to take the date and format it into the way I wish it to print out with the date function and just no go. I've got a few ideas as to why this is the case, but I know I don't know which is why I'm hoping someone can help. Thanks in advance, I appreciate anyone trying to help me on this. I'm new to php so it's been an interesting foray.
I've used the php date, strtotime, and date_create_from_format functions to attempt to take the date and format it into a date the way I want to.
// Example clip from array
$Full_List_Of_Recover_Items = array (
0 =>
array (
'ActionTimeStamp' => '2018-07-23 15:17:23'
)
);
// End format would look like July 23, 2018 3:17pm
<?php
function valGet($arr, $value)
{
foreach($arr as $row)
{
foreach($row as $key => $val)
{
if ($key == $value)
{
if ($val == NULL)
echo "empty";
else
echo $val;
}
}
}
}
function timeFormat($timeStamp)
{
// split the array value to set up date
$first = explode(" ", $timestamp);
$second = explode("-", $first);
$third = explode(":", $second);
// format the date and convert it attempt
$stringTime = strtotime("D, F, d, Y, g, i", $timestamp);
$date = date_create_from_format("Y-m-d H:i:s");
echo date($date($stringTime));
}
?>
// invocation on html
<p>
<?php
echo timeFormat(valGet($Full_List_Of_Recover_Items, 'ActionTimeStamp'));
?>
</p>
You need to modify your timeFormat function. Just use strtotime:
$timeStamp = '2018-07-23 15:17:23';
echo date("F j, Y, g:i a", strtotime($timeStamp)); // prints July 23, 2018, 3:17 pm
And here you can see the documentation for all kind of format: PHP manual date
Reference: strtotime
I have function one of the arguments of which is $date variable.
Sometimes there is time in the date (like 2018-01-01 15:40:43),
sometimes - there is not (like 2018-01-01).
I want to know if time is set.
What is the easiest way to do it?
Here is what I tryied:
function checkDate ($date) {
$time = date("H:i:s", strtotime($date));
if ($time == '00:00:00') {
//time was not set!
}
}
Obviously, this works, but untill something like 2018-06-01 00:00:00 is passed.
I would not like using explode of string if there is some other solution.
Thank you/.
I think you can use date_parse
check this: http://php.net/manual/en/function.date-parse.php
you can check for the minutes, hours and seconds from the resulting array :D
also you can check for errors in date.
You can use the Datetime class to test. What the code below will do is attempt to create a Datetime object from a date as long as it is in the format that is specified.
So if you pass anything other than a date that is in the time format that you specify it will error. Then you use the getLastErrors() to check.
Like so:
function checkIsDate($date){
$date = DateTime::createFromFormat('Y-m-d', $date);
$date_errors = DateTime::getLastErrors();
if ($date_errors['warning_count'] + $date_errors['error_count'] == 0) {
return TRUE;
} else {
return FALSE;
}
}
echo checkIsDate('2018-05-29')?'True':'False'; //<-- Will return true;
echo checkIsDate('2018-05-29 11:30:00')?'True':'False'; //<-- Will return false;
echo checkIsDate('05/29/2018')?'True':'False'; //<-- Will return false;
For completeness, here's a plain string functions version:
$input = [
'2018-01-01',
'2018-01-01 15:40:43',
'2018-01-01 00:00:00',
];
foreach ($input as $string) {
list($year, $month, $day, $hour, $minutes, $seconds) = array_pad(preg_split('/[^\\d]+/i', $string, -1, PREG_SPLIT_NO_EMPTY), 6, null);
printf("%s has time? %s\n", $string, $hour!==null ? 'Yes' : 'No');
}
2018-01-01 has time? No
2018-01-01 15:40:43 has time? Yes
2018-01-01 00:00:00 has time? Yes
Tweak checks to your liking.
I would not recommend this though. Native date/time functions are way better coping with invalid input.
Let's say the user can submit their time as strings in one of multiple formats. Is there any way in DateTime::createFromFormat() to specify multiple formats to parse.
Right now I notice if you specify a format, any missing elements cause an error.
For example, lets say I'm accepting both 1h22m34s and a 21m22s as valid time strings (the second implies 00h, but doesn't require it).
The following will throw an error on the second string when seen:
$mytime = `21m22s`;
echo DateTime::createFromFormat('H\hi\ms\s',$mytime)->format('H:i:s');
How can I work to allow it to parse multiple formats?
Or is there another, non-hack way to work with multiple formats?
I know it's been some time but here is a solution based on #dave 's comment.
$date ='20200702';
$formats = ['Y-m-d', 'Y/m/d', 'Ymd'];
$dateObj = null;
foreach ($formats as $format) {
if ($dateObj = Carbon::createFromFormat($format, $date)){
break;
}
}
If you're using Carbon then here is another solution because the behaviour is slightly different.
$date = '20200727';
$formats = ['Y-m-d', 'Y/m/d', 'Ymd'];
$dateObj = null;
foreach ($formats as $format) {
try{
if ($dateObj = Carbon::createFromFormat($format, $date)){
break;
}
} catch (InvalidArgumentException $e) {
Log::debug('date', [$dateObj]); // It's null
}
}
Trying to validate a string to check if it has the format 07.05.2013, not sure how to approach it.
Thinking of checking if '.' are the 3rd and 6th characters, then checking if the rest of the characters are digits but I don't know how to achieve that.
If you simply need to parse the date, you can use the date time features of php.
<?php
$date = DateTime::createFromFormat('d.m.Y', '07.05.2013');
echo $date->format('Y-m-d');
?>
Use the DateTime::CreateFromFormat() method. This will validate your input and create a date object at the same time (which you can then use to work with the date).
$dateObj = DateTime::CreateFromFormat('d.m.Y', $inputString);
If the date is invalid or is in the wrong format, $dateObj will be false.
If it is a valid date in the required format, $dateObj will be a DateTime object.
Hope that helps.
if (preg_match('/^\d{2}\.\d{2}\.\d\{4}$/', $yourstring)) {
...
}
This will be true if your string matches expression like dd.dd.dddd where d is a digit.
You can also use the checkdate function:
$date= '07.05.2013';
$date_arr= explode('.', $date);
if (checkdate($date_arr[0], $date_arr[1], $date_arr[2])) {
// validate your date here
}
Something like:
$date = DateTime::createFromFormat('d.m.Y', $yourStringWhichMightBeADate);
if ($date)
{
// it's a date, so use it
}
Or:
$date = DateTime::createFromFormat('m.d.Y', $yourStringWhichMightBeADate);
if ($date)
{
// it's a date, so use it
}
if the month is first rather than the day of month.
SOLUTION 1:
Here's the way I did it, it works with every input you decide to enter (e.g: "12.02.1996", "12.30.1996", "dasdsadas", and so on..)
public function valid_date($inputdate){
$date = $inputdate;
if (strtotime($date)){
if (strpos($date,'.') !== false) {
list($day, $month, $year) = explode('/', $date);
return checkdate($month, $day, $year);
}else{
return false;
}
}else{
return false;
}
}
If input date is 10/10/1996 which is also a valid format, or 10/02/1996, it won't accept them because I'm asking the user to use the format with ".". Just remove the "if" if you don't want to do this validation and that is it.
SOLUTION 2:
Found this at php.net, very clean and interesting!
public function valid_date($date, $format = 'd.m.Y'){
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm trying to use preg_match to validate that a time input is in this format - "HH:MM"
You can use regular expressions to check that.
for 12-hour:
preg_match("/^(?:1[012]|0[0-9]):[0-5][0-9]$/", $foo)
for 24-hour:
preg_match("/^(?:2[0-3]|[01][0-9]):[0-5][0-9]$/", $foo)
If you use a 24-hour clock going from 01:00 to 24:59, use
preg_match("/^(?:2[0-4]|[01][1-9]|10):([0-5][0-9])$/", $foo)
Simple function that validates a date (and/or time) without throwing exceptions. It takes the expected date format as a parameter:
function isValidDate(string $date, string $format = 'Y-m-d'): bool
{
$dateObj = DateTime::createFromFormat($format, $date);
return $dateObj && $dateObj->format($format) == $date;
}
How it works: it converts the input date into a PHP DateTime object according to the passed $format, then compares this object with the original input date.
If they match, the date is valid and has the expected format.
Some usage examples:
/* Valid Examples: */
isValidDate("2017-05-31");
isValidDate("23:15:00", 'H:i:s');
isValidDate("2017-05-31 11:15:00", 'Y-m-d h:i:s');
/* Invalid: */
isValidDate("2012-00-21");
isValidDate("25:15:00", 'H:i:s');
isValidDate("Any string that's not a valid date/time");
Let's imagine the time you want to check is $timeStr and has to be the format H:i according to the date specs.
Using a regex for this is IMHO silly. This is so much easier to read:
UPDATED
$timeStr = " 02:00"; //example of valid time, note whitespace
test($timeStr);
$timeStr = "23:59"; //valid
test($timeStr);
$timeStr = "24:00"; //invalid
test($timeStr);
$timeStr = "25:00"; //invalid
test($timeStr);
$timeStr = "16:61"; // invalid
test($timeStr);
//tests 23:59 hour format
function test($timeStr){
$dateObj = DateTime::createFromFormat('d.m.Y H:i', "10.10.2010 " . $timeStr);
if ($dateObj !== false && $dateObj && $dateObj->format('G') ==
intval($timeStr)){
//return true;
echo 'valid <br/>';
}
else{
//return false;
echo 'invalid <br/>';
}
}
Function that validates hours, minutes and seconds, according to the desired format:
function validTime($time, $format='H:i:s') {
$d = DateTime::createFromFormat("Y-m-d $format", "2017-12-01 $time");
return $d && $d->format($format) == $time;
}
How to use:
$valid = validTime("23","H");
$valid = validTime("23:59","H:i");
$valid = validTime("23:59:59","H:i:s");
$valid = validTime("23:59:59");
valid = true
$valid = validTime("25","H");
$valid = validTime("01:60","H:i");
$valid = validTime("01:20:61","H:i:s");
$valid = validTime("01:20:61");
valid = false
here is a code that check if the string is an hour between 00:00 and 23:59
$checked = false;
if (preg_match('/^\d{2}:\d{2}$/', $str)) {
if (preg_match("/(2[0-3]|[0][0-9]|1[0-9]):([0-5][0-9])/", $str)) {
$checked = true;
}
}
var_dump($checked );die;
You can do:
if(preg_match('/^(?:[01][0-9]|2[0-3]):[0-5][0-9]$/',$input)) {
// $input is valid HH:MM format.
}
For a 12-hour match that can do am and pm, use this
/^(1[0-2]|0?[1-9]):[0-5][0-9] (AM|PM)$/i
It will handle 01:20 am or 1:20 AM.
The examples above for 12 hour were incorrect because you could potentially do:
00:20
which is not a valid 12 hour format.
Expanding on what #Toskan wrote, you could do this to validate in 00:00 format. Returns true if valid and between 00:00 and 23:59.
This also allows different time formats to be used...
function isTimeValid($time_str, $format = 'H:i')
{
$DateTime = \DateTime::createFromFormat( "d/m/Y {$format}", "10/10/2010 {$time_str}" );
return $DateTime && $DateTime->format( "d/m/Y {$format}" ) == "10/10/2010 {$time_str}";
}
If you aren't requiring preg_match, here is another novel method:
$thetime = "20:15" // set the time
$timecheck = explode(":", filter_var($thetime, FILTER_SANITIZE_URL));
$hourvalid = $minvalid = false;
if (count($timecheck) > 1 && count($timecheck) < 4) {
$hourvalid = ((abs(filter_var($timecheck[0], FILTER_SANITIZE_NUMBER_INT)) < 24)
&& (abs(filter_var($timecheck[0], FILTER_SANITIZE_NUMBER_INT)) === (INT) $timecheck[0]))
? true : false;
$minvalid = ((abs(filter_var($timecheck[1], FILTER_SANITIZE_NUMBER_INT)) < 60)
&& (abs(filter_var($timecheck[1], FILTER_SANITIZE_NUMBER_INT)) === (INT) $timecheck[1]))
? true : false;
}
if ($hourvalid && $minvalid) {//valid time
echo $thetime . " is a valid time<br />";
} else {//invalid time
echo $thetime . " is NOT a valid time<br />";
}
Probably not the most efficient method in the world, but it gets it done. Valid only for times from 00:00 to 23:59. Also, 8:0 validates as a time (assuming you would mean 08:00).
Corrected answer for #Toskan if you only want to validate HH:MM string
protected function isValidTime($timeStr){
$dateObj = DateTime::createFromFormat('d.m.Y H:i', "10.10.2010 " . $timeStr);
$dateObjOffset = DateTime::createFromFormat('d.m.Y H:i', "10.10.2010 " . '24:00');
if($dateObjOffset <= $dateObj){
return false;
}
if ($dateObj !== false) {
return true;
}
else{
return false;
}
}
Based on the Charles's elegant answer with regular expression. If you need a one line validation of both "HH:MM" and "H:MM" (i.e. "9:45"/"09:45") use the following regexp to match 24-hour format:
preg_match("/^(?(?=\d{2})(?:2[0-3]|[01][0-9])|[0-9]):[0-5][0-9]$/", $time)
Explanation
(? stands for conditional subpattern, the syntax is:
(?(condition)yes-pattern|no-pattern)
?= in condition is the regexp assertion
?: in yes-pattern is optional for better performance and you may drop it. This means we don't need any capturing within parentheses (), we need just alternatives feature.
So, we merely describe the following:
If $time string begins with two digits (?=\d{2}), use (2[0-3]|[01][0-9]) pattern to match HH-hour notation ("09:45" case)
otherwise use [0-9] pattern to match H-hour notation ("9:45" case)
UPDATE
As they say, simplicity is the sister of a talent. We don't necessarily need the condition pattern described above. The simpler validation of "HH:MM/H:MM" for 24-hour format:
preg_match("/^(?:2[0-3]|[01][0-9]|[0-9]):[0-5][0-9]$/", $time)
Again, ?: in grouping parentheses () is optional to disable capturing, you can drop it.
So, in this regexp the alternative subpatterns withing () is trying to match two digits hour at the first (20..23) and second (01..19) pattern, then one digit at the last third one (0..9).
In addition, the validation of "HH:MM/H:MM" for 12-hour format:
preg_match("/^(?:0?[1-9]|1[012]):[0-5][0-9]$/", $time);
Here, we're trying to match at first one digit (1..9) with possible preceding zero (0?), and then two digits (10..12).
If you're looking for seconds (24hour). This worked like a charm for me.
$time = "23:59:60";
preg_match("/^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $time)
Another approch without using regex.
if(is_string($foo) && (strlen($foo) == 4 || strlen($foo) == 5) && intval(str_replace(':','',$foo)) > -1 && intval(str_replace(':','',$foo)) < 2360){
stuff to do if valid time
}
else{
stuff to do if invalid time
}
First of all I check if the datatype is string. If not it obvious that it is not a valid time. Then I check if the string has the right lenght of 4 / 5 letters.
With str_replace I remove the ':' and then cast the result to an integer which I could easily compare to the desired time range (in my example 00:00 - 23:59).