Python 中的年度重复日期提醒

3 投票
5 回答
1890 浏览
提问于 2025-04-15 22:24

用户可以为生日设置一个提前提醒的日期。(我们不关心出生年份)

用户还可以选择在生日的前0、1、2或7天收到提醒(也就是“提前量”)。用户可以设置自己的时区。

我希望服务器在生日当天的早上8点发送提醒,具体时间要根据用户的时区和提前量来调整。

举个例子:

如果设置的是6月12日,并选择“提前3天提醒”,那么提醒的日期就是6月9日。

我的想法是,在“重复事件”对象中增加一个叫trigger_datetime的字段。这样的话,我的服务器上可以有一个定时任务,每小时运行一次,检查所有与当前时间的小时、日期和月份匹配的事件,并发送提醒。

但问题是,从一年到下一年,提醒的日期可能会变化!

比如,如果提醒设置在3月1日,提前一天的话,可能是2月28日或29日……

也许我不应该使用这个trigger_date的方式,而是应该考虑其他的方案。

欢迎大家提出各种想法。

5 个回答

0

试试这样做。

从警报中选择所有内容,条件是日期在以下几种情况中:今天的日期、今天加2天、今天加5天、今天加7天。

并且日期减去今天的日期等于警报的频率。

把这些查询结果中的警报发送出去。

2

假设你不能使用一个现有的库来实现你需要的功能,那么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也可以接受小时数,所以你需要的精确度是可以实现的。你可以像我上面展示的那样,定期运行这段代码来检查你的所有事件,看看是否有需要发送提醒的事件。在你的情况下,由于你希望这个事件能够重复发生,你只需在提醒触发时更新开始年份,这样就可以为明年做好准备。

3

虽然使用普通的 datetime 模块你可以实现所有需要的功能,但如果你需要处理重复事件的话,有一个更强大的扩展库叫做 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(生日)本身也可能会变,所以你需要重新计算。上面的方法基本上是实时计算提醒日期(和时间)。

还有一点我可以建议的是,记录上一次发送提醒的日期(包括年份),这样如果系统出现故障,你就不会错过提醒,而是可以发送所有未发送的提醒。你需要调整代码,增加这个检查和更新的功能。

撰写回答