Используйте MySQL, чтобы определить, является ли сегодня день рождения пользователя - PullRequest
10 голосов
/ 08 февраля 2010

У меня все дни рождения пользователей хранятся в виде метки времени UNIX, и я хочу каждый день отправлять электронные письма пользователям, у которых в этот день день рождения.

Мне нужно сделать запрос MySQL, который получит все строки, содержащие день рождения на сегодняшнюю дату.

Кажется, это должно быть довольно просто, но, возможно, я просто слишком усложняю.

Ответы [ 13 ]

19 голосов
/ 08 февраля 2010

Это должно работать:

   SELECT * 
      FROM USERS
      WHERE 
         DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d')
7 голосов
/ 08 февраля 2010

Вот ответ, что свойство учитывает високосные годы и всегда даст вам пользователей, чей день рождения 29 февраля, в то же время, что и 1 марта.

SELECT * 
  FROM USERS
  WHERE 
     DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d')
     OR (
            (
                DATE_FORMAT(NOW(),'%Y') % 4 <> 0
                OR (
                        DATE_FORMAT(NOW(),'%Y') % 100 = 0
                        AND DATE_FORMAT(NOW(),'%Y') % 400 <> 0
                    )
            )
            AND DATE_FORMAT(NOW(),'%m-%d') = '03-01'
            AND DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = '02-29'
        )
4 голосов
/ 08 февраля 2010

Поскольку это все больше и больше становится вопросом игры в гольф, вот мой подход к решению этой проблемы, включая заботу о високосных годах:

select * 
from user
where (date_format(from_unixtime(birthday),"%m-%d") = date_format(now(),"%m-%d"))
   or (date_format(from_unixtime(birthday),"%m-%d") = '02-29'
       and date_format('%m') = '02' 
       and last_day(now()) = date(now())
      );

Объяснение: Первый пункт, где проверяется, сегодня ли у кого-то день рождения. Второй обеспечивает выбор только тех, чей день рождения 29 февраля, только если текущий день равен последнему дню февраля.

Примеры:

SELECT last_day('2009-02-01'); -- gives '2009-02-28'
SELECT last_day('2000-02-01'); -- gives '2009-02-29'
SELECT last_day('2100-02-01'); -- gives '2100-02-28'
2 голосов
/ 01 октября 2015

Это должно охватывать случаи високосного года и использовать внутреннюю механику даты.

В основном это работает путем добавления лет между двумя датами к дате рождения и проверки на равенство с текущей датой:

WHERE dob + INTERVAL (YEAR(CURDATE()) - YEAR(dob)) YEAR = CURDATE();

Тестирование:

SELECT '2012-02-29' 
       + INTERVAL (YEAR('2015-02-28') - YEAR('2012-02-29')) YEAR 
       = '2015-02-28'; /* 1, is birthday */

SELECT '2012-02-28' 
       + INTERVAL (YEAR('2015-02-28') - YEAR('2012-02-28')) YEAR  
       = '2015-02-28'; /* 1, is birthday */

SELECT '2012-02-28'
       + INTERVAL (YEAR('2016-02-29') - YEAR('2012-02-28')) YEAR 
       = '2016-02-29'; /* 0, is NOT birthday  */

SELECT '2012-02-29'
       + INTERVAL (YEAR('2016-02-29') - YEAR('2012-02-29')) YEAR 
       = '2016-02-29'; /* 1, is birthday */  
2 голосов
/ 28 октября 2011

Я столкнулся с этой проблемой, и я просто использовал этот простой код, используя NOW();

$myquery = "SELECT username FROM $tblusers WHERE NOW() = bd";

Результаты - сегодняшние дни рождения, так что после этого я работаю, отправляя электронные письма своим пользователям в день их рождения.

Я храню своих пользователей по дням, используя только ДАТУ, поэтому у меня всегда есть yy:mm:dd, так что, по крайней мере, для меня, при таком подходе это работает.

1 голос
/ 08 июля 2015

Вы можете использовать запрос ниже, если дата рождения сохранена в таблице.

Сегодня День Рождения:

select * from TABLENAME
 where DAY(FIELDNAME) = DAY(CURDATE())
   and MONTH(FIELDNAME) = MONTH(CURDATE());

Вчера День Рождения:

select * from TABLENAME
 where DAY(FIELDNAME) = DAY(DATE_ADD(CURDATE(), INTERVAL -1 DAY))
   and MONTH(FIELDNAME) = MONTH(CURDATE());

Завтра День Рождения:

select * from TABLENAME
 where DAY(FIELDNAME) = DAY(DATE_ADD(CURDATE(), INTERVAL 1 DAY))
   and MONTH(FIELDNAME) = MONTH(CURDATE());
1 голос
/ 02 ноября 2014

Наслаждайтесь:)

select p.birthday, 
CASE YEAR(p.birthday)%4 + MONTH(p.birthday)-2 + dayofmonth(p.birthday)-29 WHEN 0 THEN 1 ELSE 0 END as isBirthday29Feb,
CASE YEAR(now())%4  WHEN 0 THEN 1 ELSE 0 END as isThisYearLeap,
IF(YEAR(p.birthday)%4 + MONTH(p.birthday)-2 + dayofmonth(p.birthday)-29=0 AND YEAR(now())%4 != 0,
            DATE_ADD(DATE_ADD(p.birthday, INTERVAL 1  DAY), INTERVAL YEAR(NOW())-YEAR(p.birthday)  YEAR) ,
            DATE_ADD(p.birthday, INTERVAL YEAR(NOW())-YEAR(p.birthday)  YEAR)  
)as thisYearBirthDay
from person p;

Это дает вам день рождения человека, рассчитанный по текущему году. Тогда вы можете использовать его для других расчетов! Столбцы isBirthday28Feb и isThisYearLeap приведены только для иллюстрации решения.

1 голос
/ 03 июня 2010

Вот мой вклад

SELECT
  DAYOFYEAR(CURRENT_DATE)-(dayofyear(date_format(CURRENT_DATE,'%Y-03-01'))-60)=
  DAYOFYEAR(the_birthday)-(dayofyear(date_format(the_birthday,'%Y-03-01'))-60)
FROM
   the_table

Биты '(dayofyear (date_format (current_date,'% Y-03-01 ')) - 60)' возвращают 1 в високосные годы, поскольку 1 марта будет днём номер 61, и 0 в обычные годы.

Отсюда просто нужно вычесть этот дополнительный день для расчета "is-it-my-birthday".

1 голос
/ 08 февраля 2010

Я взял ответ Сагги Малачи и расширил его, включив день рождения 29 февраля в дату 28 февраля, если в этом году такого дня нет.

SELECT * 
      FROM USERS
      WHERE 
         DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d')
UNION
SELECT * 
      FROM USERS
      WHERE 
         DATE_FORMAT(NOW(),'%Y')%4 != 0 AND DATE_FORMAT(NOW(),'%m-%d')='02-28' and DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = '02-29'
1 голос
/ 08 февраля 2010

Ответ ниже фактически не работает. При этом не учитывается тот факт, что год длится 365,24 (високосных дней) дней, поэтому фактическое сравнение с датой рождения пользователей, по меньшей мере, сложно. Я оставляю это по историческим причинам.

Остальные ответы должны работать, но если вам нужна небольшая оптимизация, скажем, если есть много много строк, вам, вероятно, лучше выразить запрос непосредственно в секундах с отметкой времени. Вы можете использовать отношения (слегка вовлеченные из-за учета часового пояса):

today_starts = UNIX_TIMESTAMP(NOW()) - TIMESTAMPDIFF(SECOND, DATE(NOW()), NOW())
today_ends = today_starts + 86400

и затем выберите записи, где отметка времени находится между этими значениями.

...