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
}
}
Related
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.
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"',
Now I sq use the DateTime class to convert to different time formats and I find it very useful except one feature. Before when the user try to add date but for some reason skip the time I got 00:00:00 for the time which was good enough for me. Now, with the DateTime class if the time is not included it return error.
Here is my code:
$dt = DateTime::createFromFormat("d.m.Y H:i:s", $data['event_time']);
if($dt === false)
{
throw new Exception("Invalid date");
}
$formattedDate = $dt->format('Y-m-d H:i:s');
Every time I try to insert date without time I get Invalid date error. Is there a way to insert zeros on the place of the time, except getting error for this?
Thanks
Leron
Some simple pre-validation:
$date['event_time'] = trim($date['event_time']);
if (preg_match('/^\d{2}\.\d{2}\.\d{4}$/', $date['event_time'])) {
$date['event_time'] .= ' 00:00:00';
} else if (!preg_match('/^\d{2}\.\d{2}\.\d{4} \d{2}:\d{2}:\d{2}$/', $date['event_time'])) {
die('Invalid format');
}
If you don't want to use regex I guess this should work too. If i was you I would use #deceze solution instead of this :P but for the sake of completeness, here it is:
$dt = DateTime::createFromFormat("d.m.Y H:i:s", $data['event_time']);
if($dt === false)
{
$data['event_time'] = trim($data['event_time']);
$data['event_time'] .= " 00:00:00";
$dt = DateTime::createFromFormat("d.m.Y H:i:s", $data['event_time')
if ($dt === false) {
throw new Exception("Invalid date");
}
}
$formattedDate = $dt->format('Y-m-d H:i:s');
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
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;
}