I have some events stored in a database using doctrine and Symfony2, and those events have a two datetime parameters, start and end of the event. I need to know if those events are active during a certain month, but i cant find a way. I tried with :
$now = new \Datetime('now');
$qb = $this->createQueryBuilder('e');
$qb->where('e.start <= :now AND e.end >= :now')
->setParameter('now', $now);
return $qb->getQuery()
->getArrayResult();
but it limits to the day, and not to the month. Is there a way to check it ? Thanks a lot !
You can use the following code
$monthStart = new DateTime(date('Y-m-01') . " 00:00:00");
$monthEnd = new DateTime(date('Y-m-t'). " 23:59:59");
$qb = $this->createQueryBuilder('e');
$qb
->where('e.start <= :end AND e.end >= :start')
->setParameter('start', $monthStart)
->setParameter('end', $monthEnd);
return $qb->getQuery()
->getArrayResult();
Related
I want to get some data from database table, where date field is in range between two dates.
Here is my code below:
$date = new \DateTime('today');
$newDate = new \DateTime('today');
$newDate->add(new \DateInterval('P2D'));
$query = $repository->createQueryBuilder('s')
->select('s.day')
->where('s.day > :data')
->andWhere('s.day < :newDate')
->setParameter('data', $date)
->setParameter('newDate', $newDate)
->getQuery();
$dates = $query->getResult();
But unfortunately it doesn't work.
The second method gives empty array, too.
$date = new \DateTime('today');
$newDate = new \DateTime('today');
$newDate->add(new \DateInterval('P2D'));
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT s.day
FROM AppBundle:Seance s
WHERE s.day BETWEEN :date AND :newDate')
->setParameter('date', $date)
->setParameter('newDate', $newDate);
$seances= $query->getResult();
If I remove andWhere clause or between, doctrine returns data correctyly but all recordse
Does anyone have idea why it doesn't work?
In my application I do what you are asking, using the following:
/* #var $date1 \DateTime */
$date1 = \DateTime::createFromFormat('d/m/Y', $this->request()->get("from_date"));
$date1->format('Y-m-d h:i:s');
$date1->setTime(0, 0, 0); // You'll likely not need this bit if times don't matter to you
/* #var $date2 \DateTime */
$date2 = \DateTime::createFromFormat('d/m/Y', $this->request()->get("to_date"));
$date2->format('Y-m-d h:i:s');
$date2->setTime(23, 59, 59); // You'll likely not need this bit if times don't matter to you
Then in it's repository we do this:
->andWhere("s.date >= :date1 AND s.date < :date2)
You simply needed to pass correct criteria.
$dateFrom = (new \DateTime())->setTime(0, 0, 0);
$dateTo = (new \DateTime())->add(new \DateInterval('P2D'))->setTime(23, 59, 59);
$query = $repository->createQueryBuilder('s')
->where('s.day >= :dateFrom', 's.day <= :dateTo')
->setParameter('dateFrom', $dateFrom)
->setParameter('dateTo', $dateTo)
->getQuery();
$dates = $query->getResult();
I currently am facing a little problem : I have a table of events, and would like to get which events are upcoming or ongoing.
So for instance we are on a Monday at 12:00, we have 3 events planned for today :
Event A starting at 10:00 and lasting 1h
Event B starting at 11:00 and lasting 2h
Event C starting at 13:00 and lasting 2h
In the end I would like to get Event B (ongoing) and Event C (upcoming).
I tried doing this (didn't work) :
public function findAllPast(\Datetime $datetime)
{
$query = $this->createQueryBuilder('event')
->where('event.startTime + event.duration >= :time')
->setParameter('time', $datetime)
->getQuery();
return $query->getResult();
}
Searching around, I came onto the SQL ADDTIME() function. I'd pretty much like to do a where('ADDTIME(event.startTime, event.duration) >= :time'), but this isn't recognized by Doctrine.
Is there any proper way of doing this without brutal native SQL ?
You could use Doctrine's DATE_ADD() function :
public function findAllPast(\Datetime $datetime)
{
$query = $this->createQueryBuilder('event')
->where('DATE_ADD(event.startTime, event.duration, "days") >= :time')
->setParameter('time', $datetime)
->getQuery();
return $query->getResult();
}
This supposes that event.duration is in days, of course.
EDIT : Alternative in PHP working with DateTime objects
If $duration is in seconds, you can simply :
$datetime->sub(new DateInterval('PT' . $durationInSeconds . 'S')); // or ->add(), depending on what you wnat
and then just use :
public function findAllPast(\Datetime $datetime)
{
$datetime->sub(new DateInterval('PT' . $durationInSeconds . 'S'));
$query = $this->createQueryBuilder('event')
->where('event.startTime >= :time')
->setParameter('time', $datetime)
->getQuery();
return $query->getResult();
}
Alright, here's a working solution with $duration as a time field (much simpler for the form part of the problem) : a custom query
$entityManager = $this->getEntityManager();
$rsm = new ResultSetMappingBuilder($entityManager);
$rsm->addRootEntityFromClassMetadata('Ormindo\EventBundle\Entity\Event', 'event');
$sql = "
SELECT *
FROM events
WHERE ADDTIME(startTime, duration) > '" . $datetime->format("Y-m-d H:i:s") ."'"
;
$query = $entityManager->createNativeQuery($sql, $rsm);
return $query->getResult();
don't forget to use
use Doctrine\ORM\Query\ResultSetMappingBuilder;
Thank you tchap for your time and quick replies :)
Why is today excluded from the returned values?
SELECT DATE(created) AS reg_date,
COUNT(*) AS user_reg_per_day
FROM users
WHERE created > (NOW() - INTERVAL 30 DAY)
GROUP BY reg_date
My query seems to be fine, but I use following PHP to fill in the gaps:
function generate_calendar_days() {
$end = date("Y-m-d");
$today = strtotime($end);
$start = strtotime("-30 day", $today);
$start = date('Y-m-d', $start);
$range = new DatePeriod(
DateTime::createFromFormat('Y-m-d', $start),
new DateInterval('P1D'),
DateTime::createFromFormat('Y-m-d', $end));
$filler = array();
foreach($range as $date) {
$d = $date->format('Y-m-d');
$filler[$d] = 0;
}
return $filler;
}
My guess is $today is not correct.
There is no reason your query should exclude data from the current day unless there is something odd with the way you are writing data to this table. Are you maybe not seeing it because you are not ordering your results (i.e. it is at bottom of result set)?
It would be giving partial day results for the day 30 days ago. As such, you might consider modifying the WHERE condition a bit:
SELECT DATE(created) AS reg_date,
COUNT(*) AS user_reg_per_day
FROM users
WHERE created >= DATE(DATE_SUB(NOW(),INTERVAL 30 DAY))
GROUP BY reg_date
ORDER BY reg_date DESC
The following is comments on update question, since it seems problem is in PHP code.
I do not fully understand why you would mix strtotime functionality with DateTime, DateInterval, DatePeriod. It is good to see that you are using those though as those are drastically underused by many developers.
That being said I might rewrite that function as:
function generate_calendar_days($start = 'today', $days = 30, $days_in_past = true) {
$dates = array();
try {
$current_day = new DateTime($start); // time set to 00:00:00
} catch (Exception $e) {
echo ('Failed with: ' . $e->getMessage());
return false;
}
$interval = new DateInterval('P1D');
if (true === $days_in_past) {
$interval->invert = 1; // make days step back in time
}
$range = new DatePeriod($current_day, $interval, $days);
foreach($range as $date) {
$dates[] = $date->format('Y-m-d');
}
return $dates;
}
Note that here I have added parameters to make your function more flexible. I also only return an array of date strings so as to make the the function more general purpose. You can leave how to work with the array of dates as an implementation detail outside the scope of this function.
Your zero-filled array can easily be constructed outside the function call like this:
$calendar = array_fill_keys(generate_calendar_days(), 0);
Your sentence is perfect, in fact SELECT (NOW() - INTERVAL 30 DAY) returns 2013-12-18 22:33:30. I experimented similar odd problems, and it was because our DDBB server had a different time configuration than our Apache Server, and it gaves us weird results.
Check your servers time configuration, (http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html)
You can see from the comments in the PHP manual that people have had the trouble including the end date when iterating a DatePeriod. There are various modifications suggested there that can help with that, but for what you're doing you don't really need the end date, since you're always just going back a set number of days from the current date.
You can include the end date by using the "recurrences" form of the DatePeriod constructor.
function generate_calendar_days(int $n): array
{
$range = new DatePeriod(new DateTime("-$n day"), new DateInterval('P1D'), $n);
foreach($range as $date) {
$filler[$date->format('Y-m-d')] = 0;
}
return $filler;
}
$days = generate_calendar_days(30);
$datetime = new DateTime('today');
$datetime->modify('+2 day');
$expired_tags = DB::table('tags')
->where('active', '=', 1)
->where('expiry_date', '=', $datetime)
->get();
I'm trying to understand how I can ask:
Give me all tags that are two days away from being expired. But the above seems to be taking the Hour, Minute and Second into account ... I simply need to ask for the Year, Month, Day and compare that aspect of the two dates.
Okay, so I figured out a great way of doing what I want ...
$starting_time = new DateTime('today');
$starting_time->modify('+1 day');
$ending_time = new DateTime('today');
$ending_time->modify('+1 day +23 hours +59 minutes +59 seconds');
$expired_tags = DB::table('tags')
->where('active', '=', 1)
->whereBetween('expiry_date', array($starting_time, $ending_time))
->get();
This grabs all records that have a datetime anytime during the next calendar day! :)
$today = new DateTime('today');
$expired_tags = DB::table('tags')
->where('active', '=', 1)
->where('expiry_date', '>=', $today->modify('+1 day')->format('Y-m-d'))
->where('expiry_date', '<', $today->modify('+1 day')->format('Y-m-d'))
->get();
I have fields in my table for date, but they contain everything - day, year and month. Can I write a query to get only the records, which has month equal to the current month? I can do this:
$today = new \DateTime();
$month = $today->format('m');
$cat = $em->getRepository('EMBudgetTrackerBundle:Expense')->find(1);
$ex_date = $cat->getDate();
and compare $month and $ex_date, but can I write some kind of query? Something like this:
public function getExpensesByMonth($month)
{
$q = $this->createQueryBuilder('e');
$q->select('e')
->where('e.date = :date')
->setParameter('date', $month);
return $q->getQuery()->getResult();
}
Thank you in advance! :)
If you database column is in DateTime format you can use the DateTime object in your query. As far as I know you can only query for time ranges though.
public function getExpensesByMonth($beginning, $end)
{
$q = $this->createQueryBuilder('e');
$q->select('e')
->where('e.date > :beginning')
->andWhere('e.date < :end')
->setParameter('beginning', $beginning)
->setParameter('end', $end);
return $q->getQuery()->getResult();
}