【发布时间】:2015-12-26 00:48:06
【问题描述】:
给定“开始”日期和频率(每月、每季度、每半年、每年),我如何计算今天是否是执行所需操作的日期?
例如,开始日期为 2010-01-01,频率为每月。一个 cron 作业每天都会运行一个 Django 管理命令,所以在 2010 年 2 月 1 日,应该执行所需的操作(不管是什么,对这个问题并不重要)。
【问题讨论】:
给定“开始”日期和频率(每月、每季度、每半年、每年),我如何计算今天是否是执行所需操作的日期?
例如,开始日期为 2010-01-01,频率为每月。一个 cron 作业每天都会运行一个 Django 管理命令,所以在 2010 年 2 月 1 日,应该执行所需的操作(不管是什么,对这个问题并不重要)。
【问题讨论】:
这实际上比我最初想象的要简单。因为所有这些间隔都发生在一个月内,所以计算起来非常简单。它利用了dateutil 中的relativedelta 对象。
from datetime import date
from dateutil.relativedelta import relativedelta
starts_at = date(2010, 1, 1)
today = date(2010, 2, 1) # as an example
diff = relativedelta(today, starts_at)
if diff.days == 0: # there must be no days difference between two dates
if diff.months % 12 == 0: # this is a year interval
do_something('annual')
elif diff.months % 6 == 0: # this is a six month interval
do_something('bi_annual')
elif diff.months % 3 == 0: # this is a three month interval
do_something('quarter')
else: # this is a month interval
do_something('month')
【讨论】:
do_something() 都不一样?
diff.months % 1 也不总是为 0 吗?
12 % 3 == 0 或者即使一年过去了,您也永远无法达到 elif,间隔 6 或 12 个月,最后一个 elif 也可以是 else永远是真的
要查看今天是否是重复日期,您可以使用today in recurring_rule:
from datetime import datetime
from dateutil.rrule import rrule, MONTHLY # $ pip install python-dateutil
starts_at = datetime(2010, 1, 1)
today = datetime(2010, 2, 1)
interval = {'monthly': 1, 'quarterly': 3,
'bi-annually': 6, 'annually': 12}[frequency]
if today in rrule(MONTHLY, dtstart=starts_at, interval=interval):
print('today is a recurring date')
dateutil.rrule 允许您根据RFC 2445 创建循环规则。
如果您只需要支持每月、每季度、每半年、每年频率的简单规则,这可能有点过头了,但它在更复杂的情况下很有用。
【讨论】:
有一个很棒的Delorean library 有相关的stops() function。这个想法是找出今天的日期是否是一个范围的“停止”之一。示例实现:
from datetime import datetime
import delorean
from delorean import stops
def is_it_time(start_date, frequency):
today = datetime.now()
today_date = today.date()
try:
next(stop for stop in stops(frequency, start=start_date, stop=today)
if stop.date == today_date)
return "It's time."
except StopIteration:
return "It's not the time."
print is_it_time(datetime(2010, 1, 21), delorean.MONTHLY)
print is_it_time(datetime(2010, 1, 22), delorean.MONTHLY)
打印:
It's time.
It's not the time.
请注意,此处的 frequency 必须是 Delorean 频率常数之一,但是,如果您需要自定义频率值 - 只需将它们适当地映射到 Delorean 常数即可。
【讨论】: