Используйте MySQL, чтобы определить, является ли сегодня днем рождения пользователя

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

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

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

12
задан Lightness Races with Monica 12 July 2011 в 10:36
поделиться

8 ответов

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

   SELECT * 
      FROM USERS
      WHERE 
         DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d')
20
ответ дан 2 December 2019 в 03:38
поделиться

Вот ответ, в котором свойство учитывает високосные годы и всегда будет выдавать вам пользователей, чей день рождения приходится на 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'
        )
8
ответ дан 2 December 2019 в 03:38
поделиться

Вы просто хотите писать, верно? Это сериализованный массив или синтаксический анализ?

Одним из способов чтения конфигурационного файла является parse _ ini _ file () . Я бы не стал называть это предпочтительным, но это метод. Тебе все еще нужно написать файл.

Другим способом было бы написать «config.inc.php» и просто включить его в, чтобы записать его вы просто вывести фактический PHP код (например, $ var = «myval»;).

Таким образом можно записать простую «выходную» функцию, которая взяла массив значений конфигурации и вывела их как имя = значение, предполагая, что $ config был ассоциативным массивом.

foreach ($config as $name => $value) {
   $output .= $name . '=' . $value . "\n";
}

if (!file_put_contents($filename, $output)) {
    die("Error writing config file.");
}

Есть много достойных способов сделать это. Это действительно основано на ваших требованиях. Нужно ли иметь в определенном формате или у вас есть свобода действий?

-121--4518411-

Допустим, файл config.inc выглядит следующим образом:

$config = array(
    'blah'  => 'mmm',
    'blah2' => 'www',
    //...
);

Вы хотите обновить его, чтобы создать простую форму, заполнить текстовые поля текущими значениями. Сценарий PHP, перезаписывающий текущую конфигурацию, может выглядеть следующим образом:

$newConfig = ...; // data from form - of course validate it first
$config = ...;    // data from config.inc

$config = array_merge($config, $newConfig);
file_put_contents('config.inc', '<?php $config = ' . var_export($config, true));

И вы закончили.

-121--4518418-

Я взял ответ Сагги Малахи и расширил его, включив день рождения 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
ответ дан 2 December 2019 в 03:38
поделиться

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

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())
      );

Объяснение: Первое предложение where проверяет, наступил ли чей-то день рождения сегодня. Второе гарантирует, что выбраны только те, чей день рождения 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'
4
ответ дан 2 December 2019 в 03:38
поделиться
set @now=now();
select * from user where (month(birthday) = month(@now) and day(birthday) = day(@now)) or
  (month(birthday) = 2 and day(birthday) = 29 and month(@now) = 2 and day(@now) = 28 and
  month(date_add(@now, interval 1 day)) = 3);
0
ответ дан 2 December 2019 в 03:38
поделиться

Не могли бы вы просто выбрать все строки, соответствующие дате текущего дня? Вы также можете использовать функцию FROM_UNIXTIME () для преобразования метки времени unix в дату:

mysql> SELECT FROM_UNIXTIME (1196440219); -> '2007-11-30 10:30:19'

Это описано в http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_from-unixtime

0
ответ дан 2 December 2019 в 03:38
поделиться

Более полный ответ:

class MyClass(object):

    def __init__(self):
        self.numbers = [1,2,3,4,54]

    def __contains__(self, key):
        return key in self.numbers

Здесь вы получите True, когда спросите, был ли 54 в m:

>>> m = MyClass()
>>> 54 in m
True  

См. документацию по перегрузке __ содержит __ .

-121--6575555-

Я обнаружил, что лучшим способом решения этой проблемы является использование < label > и размещение его над областью ввода. Это дает вам:

  1. Больше эстетической свободы
  2. Сохраняет вашу страницу семантической
  3. Позволяет вам изящно деградировать
  4. Не вызывает проблем, отправляя подсказку в качестве входного значения или должны беспокоиться об управлении этой проблемой

Вот версия ванили, так как вы не просили фреймворк. Разметка не должна изменяться, но может потребоваться настройка CSS для удовлетворения ваших потребностей.

HTML:

<html>
<head>
    <style>
    label.magiclabel {
        position: absolute;
        padding: 2px;
    }
    label.magiclabel,
    input.magiclabel {
        width: 250px;
    }
    .hidden { display: none; }
    </style>

    <noscript>
        <style>
            /* Example of graceful degredation */
            label.magiclabel {
                position: static;
            }
        </style>
    </noscript>
</head>
<body>
<label>This is not a magic label</label>

<form>
    <label class="magiclabel" for="input-1">Test input 1</label>
    <input class="magiclabel" type="text" id="input-1" name="input_1" value="">

    <label class="magiclabel" for="input-2">Test input 2 (with default value)</label>
    <input class="magiclabel" type="text" id="input-2" name="input_2" value="Default value">
</form>

<script src="magiclabel.js"></script> 
</body>
</html>

vanilla-magiclabel.js

(function() {
    var oldOnload = typeof window.onload == "function" ? window.onload : function() {};

    window.onload = function() {
        // Don't overwrite the old onload event, that's just rude
        oldOnload();
        var labels = document.getElementsByTagName("label");

        for ( var i in labels ) {
            if (
                // Not a real part of the container
                !labels.hasOwnProperty(i) ||
                // Not marked as a magic label
                !labels[i].className.match(/\bmagiclabel\b/i) ||
                // Doesn't have an associated element
                !labels[i].getAttribute("for")
            ) { continue; }

            var associated = document.getElementById( labels[i].getAttribute("for") );
            if ( associated ) {
                new MagicLabel(labels[i], associated);
            }
        }
    };
})();

var MagicLabel = function(label, input) {
    this.label = label;
    this.input = input;

    this.hide = function() {
        this.label.className += " hidden";
    };

    this.show = function() {
        this.label.className = this.label.className.replace(/\bhidden\b/ig, "");
    };

    // If the field has something in it already, hide the label
    if ( this.input.value ) {
        this.hide();
    }

    var self = this;

    // Hide label when input receives focuse
    this.input.onfocus = function() {
        self.hide();
    };

    // Show label when input loses focus and doesn't have a value
    this.input.onblur = function() {
        if ( self.input.value === "" ) {
            self.show();
        }
    };

    // Clicking on the label should cause input to be focused on since the `for` 
    // attribute is defined. This is just a safe guard for non-compliant browsers.
    this.label.onclick = function() {
        self.hide();
    };
};

Vanilla demo

Как вы видите, около половины кода завернуто в инициализации в window.onload . Это можно смягчить с помощью структуры. Вот версия с использованием jQuery:

$(function() {
    $("label.magiclabel[for]").each(function(index, label) {
        label = $(label);
        var associated = $("#" + label.attr("for"));

        if ( associated.length ) {
            new MagicLabel(label, associated);
        }
    });
});

var MagicLabel = function(label, input) {
    // If the field has something in it already, hide the label
    if ( input.val() !== "" ) {
        label.addClass("hidden");
    }

    label.click(function() { label.addClass("hidden"); });
    input.focus(function() { label.addClass("hidden"); });
    input.blur(function() {
        if ( input.val() === "" ) {
            label.removeClass("hidden");
        }
    });
};

демонстрация jQuery . Разметку не нужно изменять, но, конечно, необходимо включить библиотеку jQuery.

-121--4213438-

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

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

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

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

1
ответ дан 2 December 2019 в 03:38
поделиться

Вот мой вклад

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
ответ дан 2 December 2019 в 03:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: