I\'m trying to write a query to select users of a database whose birthdays are in the next 7 days.
I\'ve done a lot of research but I can\'t come up with a working s
To get all birthdays in next 7 days, add the year difference between the date of birth and today to the date of birth and then find if it falls within next seven days.
SELECT *
FROM persons
WHERE DATE_ADD(birthday,
INTERVAL YEAR(CURDATE())-YEAR(birthday)
+ IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(birthday),1,0)
YEAR)
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY);
If you want to exclude today's birthdays just change > to >=
SELECT *
FROM persons
WHERE DATE_ADD(birthday,
INTERVAL YEAR(CURDATE())-YEAR(birthday)
+ IF(DAYOFYEAR(CURDATE()) >= DAYOFYEAR(birthday),1,0)
YEAR)
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY);
-- Same as above query with another way to exclude today's birthdays
SELECT *
FROM persons
WHERE DATE_ADD(birthday,
INTERVAL YEAR(CURDATE())-YEAR(birthday)
+ IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(birthday),1,0)
YEAR)
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
AND DATE_ADD(birthday, INTERVAL YEAR(CURDATE())-YEAR(birthday) YEAR) <> CURDATE();
-- Same as above query with another way to exclude today's birthdays
SELECT *
FROM persons
WHERE DATE_ADD(birthday,
INTERVAL YEAR(CURDATE())-YEAR(birthday)
+ IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(birthday),1,0)
YEAR)
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
AND (MONTH(birthday) <> MONTH(CURDATE()) OR DAY(birthday) <> DAY(CURDATE()));
Here is a DEMO of all queries
Building on Lobo's answer to tackle leap years
SELECT * FROM users
WHERE DATE_ADD(dob,INTERVAL YEAR(CURDATE())-YEAR(dob)
+ IF(MONTH(CURDATE()) > MONTH(dob), 1,
IF(MONTH(CURDATE()) = MONTH(dob) AND DAY(CURDATE()) > DAY(dob), 1, 0))
YEAR)
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
This is my solution. It also works if date of birth is January 1st and today's date is December 31.
SELECT `id`, `name`, `dateofbirth`,
DATE_ADD(
dateofbirth,
INTERVAL IF(DAYOFYEAR(dateofbirth) >= DAYOFYEAR(CURDATE()),
YEAR(CURDATE())-YEAR(dateofbirth),
YEAR(CURDATE())-YEAR(dateofbirth)+1
) YEAR
) AS `next_birthday`
FROM `user`
WHERE
`dateofbirth` IS NOT NULL
HAVING
`next_birthday` BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
ORDER BY `next_birthday`
LIMIT 1000;
I found this code to work really well:
DATE_ADD(user_birthdate, INTERVAL YEAR(FROM_DAYS(DATEDIFF(CURDATE(), user_birthdate)-1)) + 1 YEAR) AS next_birthday
it actually really simple, it calculate the person age, then the current's year birthday and then add 1 year.
it based on the answer of Robert Eisele which you may find here: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
p.s.
with this solution you might fetch people who had a birthday yesterday (that's because the -1 in the FROM_DAYS calculation, but it is needed because of the leap years). this shouldn't consider you too much since you only want 7 days a head so you should just add the following condition:
HAVING next_birthday BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
While trying to get the list who have their b'days upcoming in a range of time, we can run in to couple of issues.
When there is a leap year, then there is a chance that the condition you have fails to handle the case of leap years. Next problem could be like today is 2016-12-30 and you need b'days for next 7 days. So the end of the period is in year 2017. Some condition fail in this case. These are very important test cases.
Most of the fixed in this thread are using the DAYOFYEAR() which fails when you are on a leap year.
eg.
DAYOFYEAR('2016-03-01 00:00:00') is 61.
DAYOFYEAR('2015-03-01 00:00:00') is 60
Simplest and most easy to understand way is this.
This works on leap years and also the range of dates span in two years.
SELECT *
FROM `PERSONS`
WHERE
/*
Here we calculate the next coming b'day for user
and check if it is between our span
*/
CONCAT(IF(
CONCAT( YEAR(CURDATE()), substring(`BIRTHDAY`, 5, length(`BIRTHDAY`))) < CURDATE(),
YEAR(CURDATE()) + 1, /* Adds an year if already past */
YEAR(CURDATE()) /* Use this year if it is upcoming */
), substring(`BIRTHDAY`, 5, length(`BIRTHDAY`)))
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL @tot DAY)
PS: Also it is the best solution if you want to order these on the basis of the b'days. You just need to add this as a field.
This is optimized solution for leap year problem
SELECT *
FROM persons
WHERE DATE_FORMAT( CONCAT(YEAR(CURDATE()),'-',DATE_FORMAT(birth_date, '%m-%d') ), '%Y-%m-%d')
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)