Symfony - Select object where date = today - mysql

I have a entity repository containing code
$qb = $this->createQueryBuilder('tdd');
$qb->select('tdd')
->where($qb->expr()->eq('tdd.disable_date', ':dat'))
->setParameter('dat', new \DateTime());
return $qb->getQuery()->getOneOrNullResult();
And Entity containing only one member (disable_date)
/**
* #ORM\Column(type="date", unique=true, nullable=false)
* #ORM\Id()
*/
private $disable_date;
When I try to check if today's date is in database, code above returns NULL.
Date in DB exists.
What the heck?

Because new DateTime() creates object similar to this:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-04-12 07:24:34.697668"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
And you trying to match exact date with time (including seconds and ms). And thats why results is null
Check date without h:i:s

I solved this using midnight modificator.
When you declare in doctrine a Date field, in database it will be stored as date time, but Entity uses a DateTime interface.
So if you try to compare a new \DateTime (current date and time) with the date stored en database, parsed by doctrine as date stored + current time, comparasion never will be equal.
Using the midnight modificator you are really comparing equals.
$dateInDatabase = '2020-04-22';
$parsedByDoctrine = new \DateTime($dateInDatabase); // 2020-04-22 00:00:00
$now = new \DateTime(); // 2020-04-22 17:20:00
$todayMidnight = new \DateTime('midnight'); // 2020-04-22 00:00:00
$now === $parsedInDatabase // FALSE
$todayMidnight === $parsedInDatabase // TRUE
This can be applied in the createQueryBuilder or in the findBy methods
php.net/manual/en/datetime.formats.relative.php

Related

Laravel Scope query an eloquent relationship and then subQuery a set of conditions on whether or not to return the model

I have a Model Charter that hasMany BlackoutRanges. I am trying to setup a scope to return charters that do not have a blackoutRange created for 3 dates. In our system a blackoutRange is a single day.
Pseudocode would look something like this:
// query where doesnt have blackoutDates on all three of the following dates:
// start date === date passed in
// start date === date passed in plus 1 days
// start date === date passed in plus 2 days
I tried to do some logical grouping and came up with this and I also logged my raw sql query to see what it looks like:
$dayTwo = $date->copy()->addDays(1);
$dayThree = $date->copy()->addDays(2);
return $query->whereDoesntHave("blackoutRanges", function(Builder $subQuery) use($date, $dayTwo, $dayThree){
$temp = $subQuery->where(function($queryOne) use($date) {
return $queryOne->whereDate('start', $date)->where('trip_id', NULL);
})->where(function($queryTwo) use($dayTwo) {
return $queryTwo->whereDate('start', $dayTwo)->where('trip_id', NULL);
})->where(function($queryThree) use($dayThree) {
return $queryThree->whereDate('start', $dayThree)->where('trip_id', NULL);
});
logger($temp->toSql());
return $temp;
});
select * from `blackout_ranges` where `charters`.`id` = `blackout_ranges`.`charter_id` and (date(`start`) = ? and `trip_id` is null) and (date(`start`) = ? and `trip_id` is null) and (date(`start`) = ? and `trip_id` is null)
I've also logged the dates passed in and they are:
[2022-06-07 19:00:58] local.DEBUG: 2022-06-09 00:00:00
[2022-06-07 19:00:58] local.DEBUG: 2022-06-10 00:00:00
[2022-06-07 19:00:58] local.DEBUG: 2022-06-11 00:00:00
An example of the start column of a BlackoutRange would be: 2022-07-21 04:00:00
Would the fact that they are not matching timestamps be a reason for this scope not working?
And how do I know it's not working? I added blackoutRanges for a specific charter for the entire month of June and it's still being returned.
I am looking for any advice on this one as I've been plugging away now for a day and a half and have gotten no where.

DHMS to concatenate date and time to datetime causes the first date to be 1/1/1960

I am creating a time series of intraday (1 minute interval) time series. I have the variables date YYYYMMDD and time HH:MM:SS and would like to create the datetime YYYYMMDDTHH:MM:SS (or whatever format is not too important).
When looking at the output (just sample dates):
Date Time Datetime
20000101 9:30:00 1960-01-01T09:30:00
20000101 9:31:00 2000-01-01T09:31:00
.
.
.
20000102 9:30:00 1960-01-01T09:30:00
20000102 9:31:00 2000-01-02T09:31:00
SO whenever time is 9:30:00 the concatenation via dhms(date, 0, 0, time) gives me the wrong value.
My code actually picks stock prices in certain interval from higher frequency data:
data xtemp2;
set _v_&tables;
by symbol date time;
format datetime e8601dt. itime rtime time12.;
if first.symbol = 1 or first.date = 1 then do;
/* Initialize time and price when new symbol or date starts; */
rtime = time;
iprice = bid;
oprice = ofr;
itime = &start_time;
datetime = time;
end;
if time >= itime then do;
output;
itime = itime + &interval_seconds;
do while(time >= itime);
output;
itime = itime + &interval_seconds;
end;
end;
rtime = time;
iprice = bid;
oprice = ofr;
datetime = dhms(date, 0,0,itime);
retain itime datetime iprice oprice;
run;
Is it something in my code? because looking at the distinct date and time variable shows the correct date.
I wanted to combine these because I have a time series for each stock and would like to match merge them which - if I understand correctly - requires one unique id that could be my datetime variable.
The issue seems to be with this piece of conditional logic:
if first.symbol = 1 or first.date = 1 then do;
This means that the first instance of those by groups will execute datetime = time; instead of datetime = dhms(date, 0,0,itime); (presuming time >= itime is true).
I suggest replacing datetime = time; with datetime = dhms(date, 0,0,itime); in the first instance.

I want to calculate time which is taken by SQL query in MySQL for execution [duplicate]

So I just found the most frustrating bug ever in MySQL.
Apparently the TIMESTAMP field, and supporting functions do not support any greater precision than seconds!?
So I am using PHP and Doctrine, and I really need those microseconds (I am using the actAs: [Timestampable] property).
I found a that I can use a BIGINT field to store the values. But will doctrine add the milliseconds? I think it just assigns NOW() to the field. I am also worried the date manipulation functions (in SQL) sprinkled through the code will break.
I also saw something about compiling a UDF extension. This is not an acceptable because I or a future maintainer will upgrade and poof, change gone.
Has anyone found a suitable workaround?
For information for the next readers, this bug has finally be corrected in version 5.6.4:
"MySQL now supports fractional seconds for TIME, DATETIME, and TIMESTAMP values, with up to microsecond precision."
From the SQL92-Standard:
TIMESTAMP - contains the datetime field's YEAR, MONTH, DAY,
HOUR, MINUTE, and SECOND.
A SQL92 compliant database does not need to support milli- or microseconds from my point of view. Therefore the Bug #8523 is correctly marked as "feature request".
How does Doctrine will handle microseconds et al? I just found the following:
Doctrine#Timestamp:
The timestamp data type is a mere
combination of the date and the time
of the day data types. The
representation of values of the time
stamp type is accomplished by joining
the date and time string values in a
single string joined by a space.
Therefore, the format template is
YYYY-MM-DD HH:MI:SS.
So there are no microseconds mentioned either as in the SQL92-docs.
But I am not to deep into doctrine, but it seems to be an ORM like hibernate in java for example. Therefore it could/should be possible to define your own models, where you can store the timeinformation in a BIGINT or STRING and your model is responsible to read/write it accordingly into your PHP-classes.
BTW: I don't expect MySQL to support TIMESTAMP with milli/microseconds in the near future eg the next 5 years.
I found a workaround! It is very clean and doesn't require any application code changes. This works for Doctrine, and can be applied to other ORM's as well.
Basically, store the timestamp as a string.
Comparisons and sorting works if the date string is formatted correctly. MySQL time functions will truncate the microsecond portion when passed a date string. This is okay if microsecond precision isn't needed for date_diff etc.
SELECT DATEDIFF('2010-04-04 17:24:42.000000','2010-04-04 17:24:42.999999');
> 0
SELECT microsecond('2010-04-04 17:24:42.021343');
> 21343
I ended up writing a MicroTimestampable class that will implement this. I just annotate my fields as actAs:MicroTimestampable and voila, microtime precision with MySQL and Doctrine.
Doctrine_Template_MicroTimestampable
class Doctrine_Template_MicroTimestampable extends Doctrine_Template_Timestampable
{
/**
* Array of Timestampable options
*
* #var string
*/
protected $_options = array('created' => array('name' => 'created_at',
'alias' => null,
'type' => 'string(30)',
'format' => 'Y-m-d H:i:s',
'disabled' => false,
'expression' => false,
'options' => array('notnull' => true)),
'updated' => array('name' => 'updated_at',
'alias' => null,
'type' => 'string(30)',
'format' => 'Y-m-d H:i:s',
'disabled' => false,
'expression' => false,
'onInsert' => true,
'options' => array('notnull' => true)));
/**
* Set table definition for Timestampable behavior
*
* #return void
*/
public function setTableDefinition()
{
if ( ! $this->_options['created']['disabled']) {
$name = $this->_options['created']['name'];
if ($this->_options['created']['alias']) {
$name .= ' as ' . $this->_options['created']['alias'];
}
$this->hasColumn($name, $this->_options['created']['type'], null, $this->_options['created']['options']);
}
if ( ! $this->_options['updated']['disabled']) {
$name = $this->_options['updated']['name'];
if ($this->_options['updated']['alias']) {
$name .= ' as ' . $this->_options['updated']['alias'];
}
$this->hasColumn($name, $this->_options['updated']['type'], null, $this->_options['updated']['options']);
}
$this->addListener(new Doctrine_Template_Listener_MicroTimestampable($this->_options));
}
}
Doctrine_Template_Listener_MicroTimestampable
class Doctrine_Template_Listener_MicroTimestampable extends Doctrine_Template_Listener_Timestampable
{
protected $_options = array();
/**
* __construct
*
* #param string $options
* #return void
*/
public function __construct(array $options)
{
$this->_options = $options;
}
/**
* Gets the timestamp in the correct format based on the way the behavior is configured
*
* #param string $type
* #return void
*/
public function getTimestamp($type, $conn = null)
{
$options = $this->_options[$type];
if ($options['expression'] !== false && is_string($options['expression'])) {
return new Doctrine_Expression($options['expression'], $conn);
} else {
if ($options['type'] == 'date') {
return date($options['format'], time().".".microtime());
} else if ($options['type'] == 'timestamp') {
return date($options['format'], time().".".microtime());
} else {
return time().".".microtime();
}
}
}
}
As you're using Doctrine to store data, and Doctrine does not support fractional seconds either, then the bottleneck is not MySQL.
I suggest you define additional fields in your objects where you need the extra precision, and store in them the output of microtime(). You probably want to store it in two different fields - one for the epoch seconds timestamp and the other for the microseconds part. That way you can store standard 32bit integers and easily sort and filter on them using SQL.
I often recommend storing epoch seconds instead of native timestamp types as they are usually easier to manipulate and avoid the whole time zone issue you keep getting into with native time types and providing service internationally.
From Mysql version 5.6.4 onward ,It stores microsecond in a column.
"MySQL now supports fractional seconds for TIME, DATETIME, and TIMESTAMP values, with up to microsecond precision."
For example:
CREATE TABLE `test_table` (
`name` VARCHAR(1000) ,
`orderdate` DATETIME(6)
);
INSERT INTO test_table VALUES('A','2010-12-10 14:12:09.019473');
SELECT * FROM test_table;
Only needs to change datatype to datetime to datetime(6);
For more information refer following:
http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
Another workaround for Time in milliseconds. Created function "time_in_msec"
USAGE :
Difference between two dates in milliseconds.
mysql> SELECT time_in_msec('2010-07-12 23:14:36.233','2010-07-11 23:04:00.000') AS miliseconds;
+-------------+
| miliseconds |
+-------------+
| 87036233 |
+-------------+
1 row in set, 2 warnings (0.00 sec)
DELIMITER $$
DROP FUNCTION IF EXISTS `time_in_msec`$$
CREATE FUNCTION `time_in_msec`(ftime VARCHAR(23),stime VARCHAR(23)) RETURNS VARCHAR(30) CHARSET latin1
BEGIN
DECLARE msec INT DEFAULT 0;
DECLARE sftime,sstime VARCHAR(27);
SET ftime=CONCAT(ftime,'000');
SET stime=CONCAT(stime,'000');
SET msec=TIME_TO_SEC(TIMEDIFF(ftime,stime))*1000+TRUNCATE(MICROSECOND(TIMEDIFF(ftime,stime))/1000,0);
RETURN msec;
END$$
DELIMITER ;
Now you can use micro seconds
mysql> select ##version;
+-----------+
| ##version |
+-----------+
| 5.6.26 |
+-----------+
1 row in set (0.00 sec)
mysql> select now(6);
+----------------------------+
| now(6) |
+----------------------------+
| 2016-01-16 21:18:35.496021 |
+----------------------------+
1 row in set (0.00 sec)
As mentioned microsecond support was added in version 5.6.4
Perhaps the following is of use for fractional seconds:
drop procedure if exists doSomething123;
delimiter $$
create procedure doSomething123()
begin
DECLARE dtBEGIN,dtEnd DATETIME(6);
DECLARE theCount,slp INT;
set dtBegin=now(6); -- see http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
-- now do something to profile
select count(*) into theCount from questions_java where closeDate is null;
select sleep(2) into slp;
-- not the above but "something"
set dtEnd=now(6); -- see http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
select timediff(dtEnd,dtBegin) as timeDiff,timediff(dtEnd,dtBegin)+MICROSECOND(timediff(dtEnd,dtBegin))/1000000 seconds;
-- select dtEnd,dtBegin;
end$$
delimiter ;
Test:
call doSomething123();
+-----------------+----------+
| timeDiff | seconds |
+-----------------+----------+
| 00:00:02.008378 | 2.016756 |
+-----------------+----------+
Another view of it:
set #dt1=cast('2016-01-01 01:00:00.1111' as datetime(6));
set #dt2=cast('2016-01-01 01:00:00.8888' as datetime(6));
select #dt1,#dt2,MICROSECOND(timediff(#dt2,#dt1))/1000000 micros;
+----------------------------+----------------------------+--------+
| #dt1 | #dt2 | micros |
+----------------------------+----------------------------+--------+
| 2016-01-01 01:00:00.111100 | 2016-01-01 01:00:00.888800 | 0.7777 |
+----------------------------+----------------------------+--------+
See the MySQL Manual Page entitled Fractional Seconds in Time Values

Doctirne query builder, filtering by birthday (working with DateTime)?

I've a builder for selecting people with a phone number not null, a permission flag true (in the first builder call), and with a birthday template not null in this function. There is also a birthday field:
public function getAllForBirthdaySmsSend()
{
$qb = $this->getAllSuitableForSmsQueryBuilder();
$alias = $qb->getRootAlias();
$today = new \DateTime();
return $qb->andWhere(
$qb->expr()->andX(
$qb->expr()->isNotNull("$alias.sms_birthday_template"),
/* Filter if today is his birthday */
))
;
}
Now i should filter people by birthday, that is if birthday column formatted as 'm-d-' . date('Y') equals $today.
Anyone knows how to to this with query builder? I don't want to write pure SQL query but i prefer reusing the other query builder to be DRY.
You can use native sql and then map it in order to deal with real entities makeing use og ResultSetMapping. Of curse, the YEAR is ignored:
Mapping the query fields:
$rsm = new Doctrine\ORM\Query\ResultSetMapping;
$rsm->addEntityResult('models\User', 'u');
$rsm->addFieldResult('u', 'id', 'id');
$rsm->addFieldResult('u', 'username', 'username');
$rsm->addFieldResult('u', 'birthday', 'birthday');
Create a query using native date functions (each selected column now is mapped ):
$query = $this->doctrine->em->createNativeQuery('
SELECT id, username, birthday
FROM user
WHERE TIMESTAMPDIFF(YEAR, birthday, CURRENT_DATE)
> TIMESTAMPDIFF(YEAR, birthday, CURRENT_DATE - INTERVAL 1 DAY)', $rsm);
Get the users:
$users = $query->getResult();
Tip: Try to avoid casting column values when you want to do a query. It forces MySQL(if it is your case) to convert the column into a CHAR before performing the comparison and alter the performance.
Edit birthday column is datetime type. And the user model has the birtdate attibute mapped as \DateTime object

calculate the time passed after an entry of date with the current time of the day

PreparedStatement pStmt = con.prepareStatement("insert into mydate values(?,?)");
java.util.Date now = new java.util.Date();
pStmt.setDate( 1, new java.sql.Date( now.getTime()) );
pStmt.setTimestamp( 2, new java.sql.Timestamp( now.getTime() ) );
pStmt.executeUpdate();
QUERY1:
I am creating post a comment module .I want to display the time when user posted their comments.also i want to show the time passed after they have posted a comment.
like 2 days ago ,5 min before etc.
QUERY2:
i also want to change the format of the date to dd/mm/yyyy.
For displaying the date formatted you can use java.text.SimpleDateFormat or
org.apache.commons.lang.time.FastDateFormat
For the time intervals you can use org.apache.commons.lang.time.DurationFormatUtils
Here is a sample:
//this will get the date in format dd/mm/yyyy
FastDateFormat fmt = FastDateFormat.getInstance("dd/MM/yyyy");
String txt = fmt.format(date);
//this will get the interval
long ival = System.currentTimeMilis()-date.getTime();
String interval = DurationFormatUtils.formatDurationWords(ival, true, true);