Периодическое оповещение о дате в Python - PullRequest
3 голосов
/ 05 мая 2010

Пользователь может установить оповещение на день рождения. (Нас не волнует год рождения) Он также выбирает, хочет ли он получить уведомление за 0, 1, 2 или 7 дней (Дельта) до дня D. У пользователей есть настройка часового пояса.

Я хочу, чтобы сервер отправлял оповещения в 8 часов утра в день D - delete + - часовой пояс пользователя

Пример:

12 июня, с «предупредить меня за 3 дня до» даст 9 июня.

Моя идея заключалась в том, чтобы сохранить дополнительное поле trigger_datetime в объекте 'recurrent event'. Таким образом, cron Задание, выполняемое каждый час на моем сервере, будет просто проверять все события, соответствующие текущему времени часам, дням и месяцам, и отправлять оповещение.

Проблема от года к следующему, триггер_дата может измениться! Если оповещение установлено 1 марта с однодневной задержкой, которая может быть 28 или 29 февраля.

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

Все планы приветствуются.

Ответы [ 5 ]

3 голосов
/ 06 мая 2010

Хотя с помощью простого datetime модуля Python вы сможете реализовать все, что вам нужно, доступно гораздо более мощное расширение python-dateutil , особенно если вам нужно работать с повторяющимися событиями. Код ниже должен дать вам представление о том, как достичь вашей цели:

from datetime import *
from dateutil.rrule import rrule, YEARLY

# GLOBAL CONFIG
td_8am = timedelta(seconds=3600*8)
td_jobfrequency = timedelta(seconds=3600) # hourly job


# USER DATA::
# birthday: assumed to be retrieved from some data source
bday = date(1960, 5, 12)
# reminder delta: number of days before the b-day
td_delta = timedelta(days=6)
# difference between the user TZ and the server TZ
tz_diff = timedelta(seconds=3600*5) # example: +5h


# from current time minus the job periodicity and the delta
sday = date.today()
# occr will return the first birthday from today on
occr = rrule(YEARLY, bymonth=bday.month, bymonthday=bday.day, dtstart=sday, count=1)[0]

# adjust: subtract the reminder delta, fixed 8h (8am) and tz difference
occr -= (td_delta + td_8am + tz_diff)

# send the reminder when the adjusted occurance is within this job time period
if datetime.now() - td_jobfrequency < occr < datetime.now():
    print occr, '@todo: send the reminder'
else:
    print occr, 'no reminder'

И я предлагаю вам не сохранять дату напоминания о следующем году, потому что delta может измениться, или timezone может измениться, и даже birthday само по себе, так что вам придется пересчитать его. Приведенный выше метод в основном вычисляет дату и время напоминания на лету.

Еще одна вещь, которую я могу предложить - сохранить дату (день рождения, включая год) последнего напоминания. Таким образом, в случае простоя системы вы не пропустите напоминания, а отправите все, что не было отправлено. Вам нужно будет адаптировать код, чтобы выполнить дополнительную проверку и обновление.

2 голосов
/ 06 мая 2010

Предполагая, что вы не можете использовать существующую библиотеку , чтобы обеспечить функциональность, которая вам требуется, в частности, стандартный модуль библиотеки Python datetime объект timedelta должен предоставить вам примитивы для реализации нужного вам поведения:

from datetime import timedelta, date
start_date = date(2010, 6, 12)
notification_date = start_date + timedelta(days=365) - timedelta(days=3)
print notification_date

Этот фрагмент кода печатает: 2011-06-09, timedelta также принимает часы, поэтому требуемая точность возможна. Вы можете запускать код, как я показал выше, регулярно для всех ваших событий, чтобы посмотреть, должно ли какое-либо из них отправлять оповещение. В вашем случае, так как вы хотите, чтобы это повторялось, вы можете просто обновить начальный год при срабатывании оповещения, настроив его на следующий год.

0 голосов
/ 06 мая 2010

Попробуйте что-нибудь подобное.

Выберите * из оповещений, где дата в (GetDate (), GetDate () + 2, GetDATE () + 5, GETDATE () + 7) и date-GetDate () = alertFrequency

Отправить оповещения на все результаты вышеуказанного запроса

0 голосов
/ 06 мая 2010

Как насчет выполнения запроса типа

SELECT `user` FROM `mytable` WHERE now() >= (`birthday` - INTERVAL `delta` DAY);

ежедневно?

0 голосов
/ 06 мая 2010

Вы можете сделать это в двух частях.

  1. Cron Job, который запускает приложение ежечасно, полчаса или на другой подходящей частоте.

  2. Приложение проверяет, настало ли время для срабатывания каких-либо предупреждений. Добавляет эти оповещения в список рассылки. Отправляет оповещения по электронной почте этим клиентам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...