Doctrine 2.2 Datetime string conversion in Symfony 3.4 - php

I am troubleshooting a search bar to return rows within a period chosen from 'To' and 'From' datepickers.
I initially got this error :
Error: Method Doctrine\ORM\Query\Expr\Comparison::__toString() must not throw an exception, caught Symfony\Component\Debug\Exception\ContextErrorException: Catchable Fatal Error: Object of class DateTime could not be converted to string
I converted the relevant query to a string using ->format() function:
if (is_array($value) && isset($value['to'])) {
$to = \DateTime::createFromFormat('d/m/Y H:i:s', $value['from'] . ' 23:59:59');
var_dump($value, $to);die;
if ($to <> false) {
$query->andWhere(
$query->expr()->lte($path, $to->format('Y-m-d H:i:s'))
);
}
}
Now doctrine throws the following error:
[Syntax Error] line 0, col 977: Error: Expected end of string, got '00'
Is there something else I need to do to format the date to make it acceptable to the querybuilder? I've tried using / instead of : but this causes an issue.

If I recall correctly, you should either use literal(), or query parameter. And since the lte argument is not constant, using literal() is highly discouraged (due to potential SQL injection).
Anyway, something like this should probably work:
if (is_array($value) && isset($value['to'])) {
if (is_array($value) && isset($value['to'])) {
$to = \DateTime::createFromFormat('d/m/Y H:i:s', $value['from'] . ' 23:59:59');
if ($to <> false) {
$query->andWhere($query->expr()->lte($path, ':to'));
$query->setParameter('to', $to->format('Y-m-d H:i:s'));
}
}
Does it work?
Hope it helps...

Related

Problem to convert unix time to human time

I have a online controller where i want to know the uptime and last seen of my access points. for this i use the epoch convert methode to convert unix time to human readable time.
this is the code i use
// getting controller ap info //
$name=$status=$uptime=$last_seen=[];
foreach ($ligowave->result as $index => $obj) {
$name[] = $obj->name;
$status[] = $obj->status;
$uptime[] = $obj->uptime;
$last_seen[] = $obj->last_seen;
}
// time settings //
$epoch = $uptime;
$uptimetime = (new DateTime("#$epoch"))->format(' H:i:s');
$epoch = $last_seen;
$lastseendate = (new DateTime("#$epoch"))->SetTimeZone(new DateTimeZone('Europe/Amsterdam'))->format(' d-m-Y H:i:s');
if ($status == "up") {
echo $name;
echo " is up, ";
echo "uptime is:" . $uptimetime;
} else {
echo $name;
echo " is down, ";
echo "device is last seen:" . $lastseendate;
}
return array($name, $status, $epoch, $uptimetime, $lastseendate);
}
the error i am getting is:
PHP Fatal error: Uncaught Exception: DateTime::__construct(): Failed
to parse time string (#Array) at position 0 (#): Unexpected character
Please Note:
This answer is only about resolving the specific PHP error as stated on the question. For a wider answer about how to effectively write code to iterate over arrays please see Fyrye's answer.
The error you are receiving is:
PHP Fatal error: Uncaught Exception: DateTime::__construct(): Failed to parse time string (#Array) at position 0 (#): Unexpected character
What is actually wrong, and why?
1)
You have an uncaught Exception, which throws a fatal error due to being, er, uncaught. Exceptions are central to object programming and should be researched and implemented in your PHP scripts.
2)
Why do you have an Exception in the first place? The error states the exception is caused by "Failed to parse time string (#Array)". So you are trying to give the DateTime object an array when it expects a string. It would help you to Read the PHP DateTime __construct Manual Page.
3)
Further, and more specifically the # character is unexpected; which means it should not be there. This character is only valid when followed by timestamp integer values in string format.
Because the array is output as a string (i.e in quotes) the end result is "#Array" and so the # is taken literally by DateTime; but of course this character is not expected by DateTime in any non-numeric incoming time string. This is the root cause of your fatal error here.
While PHP does employ loose typecasting to some extent, wrapping an array $var in quotes is far too loose and so the array simply outputs "Array" and issues a corresponding PHP Notice:
Notice: Array to string conversion in .....
For a valid list of correct DateTime string formats to give the object you can view this page from the PHP Manual.
4)
I do not see why you need those outer brackets?
So, how should this be done?
Reading the issues in reverse order from 4 to 1; the correct way of resolving this specific error is:
Wrap the attempt into a try/catch block to avoid these fatal errors.
Ensure that the value given to the DateTime object is a string
Remove unnecessary and invalid characters from that string.
So:
$epoch = $uptime;
try{
/***
* Uptime appears to be a numeric array of time string values
* Therefore go for the first one.
* You may want to wrap this code in a loop to catch each one.
***/
$uptimeTime = new DateTime("#".(string)$epoch[0]);
}
catch (Exception $ex){
/***
* If you wish to ignore these errors simply leave this block empty
***/
error_log("There was a problem on line ".__LINE__."! ".print_r($ex));
}
/***
* By default UTC timestamps are not zoned.
***/
// $uptimeTime->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
$uptimeTimeOutput = $uptimeTime->format('H:i:s');
/***
* $uptimeTimeOutput is the correctly formatted date from $epoch[0]
***/
print $uptimeTimeOutput;
I hope with the information given above your able to correct the second DateTime instantiation code (ie the new DateTime line) yourself. :-)
TL;DR
Please read the PHP Manual and allow it to inform your coding choices.
The main issue is caused by defining $uptime[] as an array of values, resulting in $epoch = $uptime containing an array of timestamp strings. When DateTime() expects a single string value.
To resolve the issue you need to move the DateTime calls inside of the foreach iteration.
The other issue, as mentioned in the answer provided by Martin, is that you are not handling exceptions within your code. If uptime or last_seen is not of an expected value that is being supplied to the DateTime constructor, an exception will be thrown.
To handle the exceptions you can use atry/catch block in order to handle an issue that arises in your code. Exceptions are meant to point you to fatal errors in your code so that you can resolve or verify them programmatically and typically should not be ignored by using try/catch. For more details please see https://www.php.net/manual/en/language.exceptions.php
Without knowing exactly what you're trying to accomplish with your code. It appears you are wanting to echo and return all of the values from $ligowave->result. I made the appropriate changes below to reflect what I surmise are your intentions. Along with some minor simplifications.
Please clarify what you are wanting to return and echo and I will adjust my answer.
Example: https://3v4l.org/O0nS6
//...
// getting controller ap info //
$values = [];
foreach ($ligowave->result as $index => $obj) {
//convert the unix timestamps to DateTime objects
$uptime = (new DateTime('#' . $obj->uptime));
$last_seen = (new DateTime('#' . $obj->last_seen))->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
//store the return values into an array
$values[] = $value = [
'name' => $obj->name,
'status' => $obj->status,
'uptimetime' => $uptime->format('H:i:s'),
'lastseendate' => $last_seen->format('d-m-Y H:i:s')
];
//output each of the statuses
printf('%s is %s, ', $obj->name, $obj->status);
if ('up' === $obj->status) {
echo 'uptime is: ' . $value['uptimetime'];
} else {
echo 'device is last seen: ' . $value['lastseendate'];
}
}
return $values;
}
Result:
foo is up, uptime is: 10:20:54
bar is down, device is last seen: 01-06-2019 08:22:30
Returns:
array (
0 =>
array (
'name' => 'foo',
'status' => 'up',
'uptimetime' => '10:20:54',
'lastseendate' => '05-06-2019 11:16:21',
),
1 =>
array (
'name' => 'bar',
'status' => 'down',
'uptimetime' => '10:20:54',
'lastseendate' => '01-06-2019 08:22:30',
),
)
It also appears that you are using a 24 hour time, to represent a duration.
If so you will need to use a DateInterval instead of DateTime, by using DateTime::diff from an appropriate timeframe. For more details please see https://php.net/manual/en/class.dateinterval.php
Assuming uptime is the started time and last_seen is the current run time, you can use $uptime->diff($last_seen), to retrieve the time that elapsed between uptime to last_seen (duration), instead of the 24 hour time value of uptime. Otherwise you can use $uptime->diff(new DateTime('now', new DateTimeZone('Europe/Amsterdam'))), to use the current date time.
One caveat, is that the hours of DateInterval are non cumulative, meaning you would need to add the days in some manner. I have used the most accurate of %a as opposed to adding on to the hours with days * 24
Example: https://3v4l.org/LHdqL
//...
$uptime = (new DateTime('#' . $obj->uptime))->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
$last_seen = (new DateTime('#' . $obj->last_seen))->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
$values[] = $value = [
'name' => $obj->name,
'status' => $obj->status,
'lastseendate' => $last_seen->format('d-m-Y H:i:s'),
'uptimetime' => $uptime->diff($last_seen)->format('%a.%H:%I:%S'), //DD.HH:MM:SS
];
//...
Result:
foo is up, uptime is: 12.22:48:26

PHP error: Call to a member function setTimeZone() on boolean

Faced the following error in a function that returns the current time with microseconds:
Fatal error: Call to a member function setTimeZone() on boolean
The code this function is:
public static function getCurrentTime() {
$microtime = microtime(true);
$time = DateTime::createFromFormat('U.u', (int) $microtime != $microtime ? $microtime : $microtime + 0.001);
$time->setTimeZone(new DateTimeZone(date_default_timezone_get()));
return $time->format('Y-m-d H:i:s.u');
}
This error occurs with a small proportion of users (<1%). I know that setTimeZone() can return false if a problem occurs, but how can I avoid this problem in my code? Why does setTimeZone() return false?
I am using PHP Version 7.0.9.
The problem turned out to be that the microtime(true) function sometimes returns a number without a dot and the U.u format does not apply to it. As a result, two solutions were found to solve the problem:
Solution 1: Replace (int) $microtime != $microtime with stripos($microtime, '.')
Solution 2: Wrap the code in a try-catch construct, like this:
try {
getCurrentTime();
} catch (Exception $e) {
// Retry a maximum of 3 times
}
Posted on behalf of OP
The casting to (int) on your ternary statement might be the culprit.
What you are effectively doing is:
$microtime_int != $microtime_float
Which will almost always give you a false. But when it returns TRUE, when you hit the magic sweet spot of $microtime having zeroes after the decimal point, your format U.u will not work.
Since you must have microseconds, then I will suggest catching an error and retrying until you are fine.
This pseudocode should fix your issue:
try{
getCurrentTime();
}catch(e Exception){
retry max 3 times
}
Please see the proof:
Ouput:
1544603355.9997
1544603355.9998
1544603355.9998
1544603355.9999
1544603355.9999
1544603355.9999
1544603356
PHP Fatal error: Uncaught Error: Call to a member function setTimeZone() on boolean in a.php:6
Stack trace:
#0 {main}
thrown in a.php on line 6
script:
<?php
for ($i = 0; $i <= 999999; $i++){
$microtime = microtime(true);
echo $microtime . "\n";
$time = DateTime::createFromFormat('U.u', (int) $microtime != $microtime ? $microtime : $microtime + 0.001);
$time->setTimeZone(new DateTimeZone(date_default_timezone_get()));
}
Above fixes, still in very small amount of cases, give me an error. So I fixed it, in rather very creapy way, but if it works, it works:
$microtime = number_format(microtime(true),4,'.','');

Failed to parse time string: it is working good on my local but on server

I have a code which is working on my localhost but in server it throws error.
the error is: Fatal error: Uncaught exception 'Exception' with message 'DateTime::__construct(): Failed to parse time string (#1645.0000000006) at position 14 (0): Unexpected character
my code is:
function secondsToTime($seconds)
{
$arr = array();
$dtF = new DateTime('#0');
$dtT = new DateTime("#$seconds");
$arr[0] = $dtF->diff($dtT)->format('%h');
$arr[1] = $dtF->diff($dtT)->format('%i');
$arr[2] = $dtF->diff($dtT)->format('%s');
return $arr;
}
print_r(secondsToTime("1645.0000000006"));
what is the problem? thanks everyone
Apparently handling of microseconds changed around PHP 7.1 and PHP accepts decimal values as valid timestamps starting with that version, but not before. If you have to make it compatible with previous versions, you need to cast your float to an int:
$dtT = new DateTime('#' . (int)$seconds);

phpspreadsheet setFormatCode not working

Sometimes I'm unable to format an Excel cell data as date using $date wiht format 'yyyy-mm-dd' (eg. 2017-07-12)
if ($date != '') {
$t_date = PhpOffice\PhpSpreadsheet\Shared\Date::stringToExcel($date);
$sheet->setCellValueByColumnAndRow($column,$row, $t_date);
$sheet->getStyleByColumnAndRow($column,$row)->getNumberFormat()->setFormatCode(PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DDMMYYYY);
}
The previous code fails when a $date is not valid (eg. 0000-00-00), and keeps failing in all sequent applies.
My solution is
if ($date != '') {
$t_date = PhpOffice\PhpSpreadsheet\Shared\Date::stringToExcel($date);
if ($t_date !== false) {
$sheet->setCellValueByColumnAndRow($column,$row, $t_date);
$sheet->getStyleByColumnAndRow($column,$row)->getNumberFormat()->setFormatCode(PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DDMMYYYY);
$sheet->getStyleByColumnAndRow($column,$row)->getFont()->setBold(true);
$sheet->getStyleByColumnAndRow($column,$row)->getFont()->setBold(false);
}
}
Settting and unsetting the bold stile kwwpd working the setFormatCode in moste fo the cases ... I do not know why.

PHP Input Error- String to Time Input [duplicate]

This question already has answers here:
Convert one date format into another in PHP
(17 answers)
Closed 3 years ago.
I'm trying to receive data from input that I changed from "text" to the "time" selector. Now when the data goes in, it's generating the following error listed below. I understand why this is happening, but don't know where and how to change the code so that the code can process the PHP "time" input.
Error:
Fatal error: Uncaught exception 'Exception' with message 'DateTime::__construct(): Failed to parse time string (013:59) at position 0 (0): Unexpected character' in C:\xampp\htdocs\index.php:240 Stack trace: #0 C:\xampp\htdocs\index.php(240): DateTime->__construct('013:59') #1 C:\xampp\htdocs\index.php(84): format_time('13:59') #2 {main} thrown in C:\xampp\htdocs\index.php on line 240
Relevant Code:
if($to){
$s = (int)format_time($start);
$e = (int)format_time($end);
function ct($time){
$timezone_offset = 14400000; //EST vs UTC in ms
return new MongoDB\BSON\UTCDateTime(strtotime($time)*1000 + $timezone_offset);
}
function now_in_mongo($offset = 0){
return new MongoDB\BSON\UTCDateTime(time()*1000 + $offset*1000);
}
function format_time($time){
if(strlen($time) != 6){
$time = "0$time";
}
$date = new DateTime($time);
$date->add(new DateInterval('PT4H'));
return $date->format('His');
}
I am not sure why you are checking the input for length under 6. A correct time input would have length of 5 (e.g 12:34), so at least you should use
if(strlen($time) != 5)
However this also may not always be correct - yet I'm not sure how you are constructing your $time string.
I think your time format should be like this xx:xx, i didnt tried your code but you can check the string to parse using a regex '/^\d{2}:\d{2}$/'
And use DateTime::CreateFromFormat to create ur date object.

Categories