Choosing birthdays in MySQL + little things
They gave the task: to select from the database users whose birthday is one of these days - to be displayed on the main page of the site.
We use PHP (ZF) & MySQL.
The field in our database is of type “date”, which is already good. The task is simple , I began to write ...
Faster, I think, google, why reinvent the wheel, obviously already been decided hundreds of times.
I looked at the first request - it works incorrectly, the second - too ...
I found the right one, but it turned out to be so monstrous.
There was no limit to surprise - some of these “bicycles” were invented this year!
I wrote in the end myself. For starters, it’s simpler (Birthdays from September 01 to October 29 are selected here):
But you need to set the period for the next N days. And what about the New Year transition?
Wrote something like this:
I decided it was too early for me to write SQL procedures. In addition, the request generated on the Zend Framework will be easier. Happened:
Constants are passed from PHP, not calculated inside the request.
Now I’ll list the pitfalls of previously found bicycles:
1. The transition to the new year was
not taken into account 2. The leap year was not taken into account when sampling according to DAYOFYEAR () - 1 day error
3. Unfortunately, my birthday, only once ... every 4 years
3. Too complex calculations
3. Extreme dates fell out
I think those who do not use ZF will also come in handy.
The SQL query itself turned out to be quite simple, but for very large databases you need to create a separate field and index it. Time zones are not taken into account by the current task.
At the same time, I’ll give age calculation in PHP (in MySQL - even easier). Because I met implementations from calculation in seconds (with a leap error) to "integral" two pages of code.
P.S. If there is a more correct bike, write. Then we will definitely end the invention of this type of bike. :)
If you are minus, then put plus to the best option from the comments, or offer your own.
We use PHP (ZF) & MySQL.
The field in our database is of type “date”, which is already good. The task is simple , I began to write ...
Faster, I think, google, why reinvent the wheel, obviously already been decided hundreds of times.
I looked at the first request - it works incorrectly, the second - too ...
I found the right one, but it turned out to be so monstrous.
There was no limit to surprise - some of these “bicycles” were invented this year!
I wrote in the end myself. For starters, it’s simpler (Birthdays from September 01 to October 29 are selected here):
SELECT * FROM users__accounts WHERE DATE_FORMAT(birthday,'%m%d') >= '0901' AND DATE_FORMAT(birthday,'%m%d') <= '1029'
* This source code was highlighted with Source Code Highlighter.
But you need to set the period for the next N days. And what about the New Year transition?
Wrote something like this:
SET @dayplus:=15;
SET @andor:=CASE WHEN YEAR(CURDATE() + INTERVAL @dayplus DAY) - YEAR(CURDATE()) THEN 'OR' ELSE 'AND' END;
SET @fromdate:=DATE_FORMAT(CURDATE(),'%m%d');
SET @todate:=DATE_FORMAT(CURDATE() + INTERVAL @dayplus DAY,'%m%d');
SET @birthday_query:=CONCAT("SELECT * FROM users__accounts WHERE DATE_FORMAT(birthday,'%m%d') >= @fromdate ",
@andor, " DATE_FORMAT(birthday,'%m%d') <= @todate");
PREPARE birthday_query FROM @birthday_query;
EXECUTE birthday_query;
DEALLOCATE PREPARE archive_query;
* This source code was highlighted with Source Code Highlighter.
I decided it was too early for me to write SQL procedures. In addition, the request generated on the Zend Framework will be easier. Happened:
class Users extends Zend_Db_Table_Abstract
{
protected $_name = 'users__accounts';
/**
...
*/
public function getBirthdayUsers($count, $days = 7)
{
$date = new Zend_Date();
/* сегодня */
$dateFrom = $date->toString('MMdd');
/* мы заботимся о каждом ;) */
if ($dateFrom == '0301' && !$date->isLeapYear()) {
$dateFrom = '0229';
}
$yearFrom = $date->toString('YY');
$date->addDay($days);
/* сегодня + $days дней */
$dateTo = $date->toString('MMdd');
$nextYear = $yearFrom - $date->toString('YY');
$select = $this->getAdapter()->select()
->from(array('u' => $this->_name))
->where("date_format(u.birthday,'%m%d') >= ?", $dateFrom)
->order('DAYOFYEAR(u.birthday)')
->limit($count);
/* переход на следующий год - OR / AND */
if ($nextYear == 0) {
$select->where("date_format(u.birthday,'%m%d') < ?", $dateTo);
} else {
$select->orWhere("date_format(u.birthday,'%m%d') < ?", $dateTo);
}
$users = $select->query()->fetchAll();
return $users;
}
}
* This source code was highlighted with Source Code Highlighter.
Constants are passed from PHP, not calculated inside the request.
Now I’ll list the pitfalls of previously found bicycles:
1. The transition to the new year was
not taken into account 2. The leap year was not taken into account when sampling according to DAYOFYEAR () - 1 day error
3. Unfortunately, my birthday, only once ... every 4 years
3. Too complex calculations
3. Extreme dates fell out
I think those who do not use ZF will also come in handy.
The SQL query itself turned out to be quite simple, but for very large databases you need to create a separate field and index it. Time zones are not taken into account by the current task.
At the same time, I’ll give age calculation in PHP (in MySQL - even easier). Because I met implementations from calculation in seconds (with a leap error) to "integral" two pages of code.
/**
* @param timestamp() $birth
* @return INT
*/
function getAge($birth)
{
$now = time();
$age = date('Y', $now) - date('Y', $birth);
if (date('md', $now) < date('md', $birth)) {
$age--;
}
return $age;
}
* This source code was highlighted with Source Code Highlighter.
P.S. If there is a more correct bike, write. Then we will definitely end the invention of this type of bike. :)
If you are minus, then put plus to the best option from the comments, or offer your own.