I have an API call that returns the date in various formats. I've written a try...catch block to try Carbon::parse and Carbon::createFromDate with multiple formats which seems to work, but I feel like there's gotta be a better way of going about this.
Here are two of the possible date formats:
2020-09-24T00:00.000Z
24/09/20 00:00:00
And here is the code I have
// Test different date formats
$formats = ['d/m/y H:i:s', 'Y-m-d'];
$dateObj = null;
foreach ($formats as $format) {
try {
if ($dateObj = Carbon::createFromFormat($format, $date)) {
break;
}
} catch (\InvalidArgumentException $e) {
$error = 'invalid date';
}
try {
if ($dateObj = Carbon::parse($date)) {
break;
}
} catch (\InvalidArgumentException $e) {
$error = 'invalid date';
}
}
Carbon::parse() is exactly made to parse various formats (it uses the DateTime native constructor) and you may rely on it to understand the more common formats. createFromFormat() is actually needed only when you have precise expectation or to be get a precedence when there is an ambiguity. For instance 1/2 is parsed by default in the US way (January 2nd), to get February 1st, here it's relevant to try first createFromFormat() with specifically d/m formats, but else parse() may be just enough. In your example d/m/y H:i:s indeed needs to be specified else the order won't be correct (and you can use * instead of the space so T would also work) but Y-m-d is useless, parse() handle it properly.
Related
How to check string on date in laravel?
I want to handle the situation if string doesn't date for example like "it's some not date string".
I try it code, but it doesn't work I have next error:
InvalidArgumentException : A two digit month could not be found
Data missing
My code:
if (Carbon::createFromFormat('m-d-Y', $rowMatrix[4]) !== false) {
//
}
You can use DateTime for this purpose :
$dateTime = DateTime::createFromFormat('d/m/Y', $rowMatrix[4]);
$errors = DateTime::getLastErrors();
if (!empty($errors['warning_count'])) {
// Not a date
}
Or you can check it like this :
if (date('Y-m-d H:i:s', strtotime($rowMatrix[4])) == $rowMatrix[4]){
// it's a date
}
You can use try/catch block:
try {
$date = Carbon::createFromFormat('m-d-Y', $rowMatrix[4])
} catch(InvalidArgumentException $e) {
$date = 'Not a date';
}
But a much better way is to use Laravel validation date_format rule to make sure the string is a date:
'some_date_field' => 'date_format:"m-d-Y"',
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
}
}
I've a varible passed as String on a php method in a Symofny2 Application:
public function eventAllByScenarioAndDateAction($apiVersion, $scenario,$date, $options)
then the $date must be a DateTime type in format YYYY-MM-DD HH:MM:SS to passing it for populating a table by using a sql query.
I'd like to check if the format passed is correct so i put the control:
$dateControl1=strtotime($date);
and then the if sentence:
if ($dateControl1 === false)
but the "if" is setted to false just if I send something like 2013-33-01 and not for example if i cut the HH:MM:SS
so how can I check how the $date is passed to the method and for example having different behavior if I have only YYYY-MM-DD (but correct) or the whole YYYY-MM-DD HH:MM:SS
Again, how can I discard format different from the expected one (for example with / instead of - etc.)
There is no need to be that specific. The following works just fine:
$foo = new DateTime("2013-01-01");
$bar = new DateTime("2013-01-01 01:23:45");
echo $foo->format("Y-m-d H:i:s"); // 2013-01-01 00:00:00
echo $bar->format("Y-m-d H:i:s"); //2013-01-01 01:23:45
If an invalid date is your main concern, us a try/catch clause:
try {
$baz = new DateTime("foobar");
} catch (Exception $e) {
// do something else here
// like throwing an HTTP Exception
}
Actually the #nietonfir solution works fine for me:
try { $dateNew = new \DateTime('$date'); } catch (\Exception $e) { echo return $e; }
(note the "\" before some declaration for bypassing symofny exception)
Because if someone passing just YYYY-mm-dd the date is completed by 00:00:00 hour
But what I'd like to do is to checkin what is $date before validate it!
So for example
SOMETHING THAT CHECKIN DATE IF ITS yyyy-mm-dd `hh:mm:ss OR just yyyy-mm-dd
and THEN IF WE ARE IN THE SECOND CASE DOING SOMETHING BEFORE doing
try { $dateNew = new \DateTime('$date'); } catch (\Exception $e) { echo return $e; }
Approach like:
list($date1, $time) = explode(" ",$date);
doesn't works because the space " " isn't recognized if we are in yyyy-mm-dd case and it raise an exception like:
Notice: Undefined offset: 1 in...........
An easy follow up From an earlier question ( Date functions in PHP ) I have the following code:
$date_str = "Jan 14th 2011";
$date = new DateTime($date_str);
echo $date->format('d-m-y');
What I am wondering is if there is an easy way to check if $date_str will convert to a date so that I can stop prevent the error when it fails?
Basically I am looking to avoid using try catch statements but perhaps that is not possible.
As per the docs, the DateTime constructor will throw an exception if the date can't be parsed properly. So...
try {
$date = new DateTime($date_str);
} catch (Exception $e) {
die("It puked!");
}
If you're using the procedural interface, you'll get a boolean false instead, so...
$date = date_create_from_format(...);
if ($date === FALSE) {
die("It puked!");
}
Since DateTime class will throw an exception if incorrect values are passed. and the only way you should be dealing with exceptions is by using try catch statement.
try {
$date = new DateTime($date_str);
$date->format('d-m-y');
} catch(Exception $e) {
//$e will contain the caught exception if any.
}
i see no reason for skipping try catch method. if you want to validate the date input then you might want to have a look at php's checkdate function
date_create('sdfsdfdsfsd') //invalid
date_create('2010-07-30 08:03') //valid
As you can see from the documentation it is simply an alias of DateTime::__construct which:
Returns a new DateTime instance.
Procedural style returns FALSE on
failure.
Or you could validate first:
php check for a valid date, weird date conversions
If the date_create function doesn't return a valid date object, it'll return FALSE.
A much more complicated alternative is to validate its parameter with Regex according to http://www.php.net/manual/en/datetime.formats.php.
Isn't this covered right at the top of the manual page?
<?php
$date = date_create('2000-01-01');
if (!$date) {
$e = date_get_last_errors();
foreach ($e['errors'] as $error) {
echo "$error\n";
}
exit(1);
}
echo date_format($date, 'Y-m-d');
?>