python - 没有 dtend 作为 rrule 参数?
问题描述
我试图dateutil.rrule
在给定的datetime
.
尝试 1:
我的第一次尝试是:
dtstart = datetime(2010, 1, 1, 0, 00)
myRule = rrule(freq=WEEKLY, dtstart=dtstart)
result = myRule.before(dtstart)
它不起作用,变量结果将等于None
.
如果我是对的,当您执行before
an 的方法时rrule
,您将不幸地在datetime
传递给参数之后搜索dtstart
。所以基本上,我之前的代码可以表示为那种时间线:
[A区] [TARGET]
[B区] [dtstart]
[C区]
在那个时间线中,只有 [zone C] 被解析,所以我的目标永远找不到。
尝试 2:
我的第二次尝试很有效,但真的很难看......目的是改变[dtstart]
之前的[TARGET]
时间线以获得看起来像这样的时间线:
[A区] [dtstart]
[B区] [TARGET]
[C区]
为此,我必须确定一个dtstart
肯定是在目标之前而不是那么远以避免性能问题的目标。所以 [zone B] 必须存在,但必须尽可能短。
seekdt = datetime(2010, 1, 1, 0, 00)
startdt = seekdt - timedelta(days=7) # While my rrule.freq is WEEKLY and the interval is 1 (default), I'm sure that my startdt will be before my target if I shift it by 7 days
myRule = rrule(freq=WEEKLY, dtstart=startdt)
result = muRule.before(seekdt)
正如我所说,那个解决方案真的很难看......如果我有一个更复杂的规则或规则集,也很难定义最佳转变。
最好的解决方案,但实际上并不存在...... :'( :
如果 rrule 可以采用 dtend 而不是 dtstart,那将是完美的。我可以做这样的事情:
dtstart = datetime(2010, 1, 1, 0, 00)
myRule = rrule(freq=WEEKLY, dtend=dt)
result = muRule.before(dt)
问题:
如果没有任何简单的功能可以做到这一点,这对我来说很奇怪。有什么优雅的方式可以达到我的目标吗?我的尝试 2 是最好的解决方案吗?
换句话说(同样的问题,但作为一个练习):
您将如何找到 2 月 13 日的最后一个星期五(基于今天)?
解决方案
假设 dateutils.rrule 不提供开箱即用的功能,我认为您自己的解决方案已经接近但还没有完全实现。您需要以正确的时间间隔倒退并计算目标日期之前的最后一个结果。如果您的规则没有完全指定并且结果继承了原始日期的某些属性,那么“正确的间隔”很重要。
例如,如果您的规则是MONTHLY
您必须确保您在上个月或上个月的同一天结束。这很棘手,因为上个月甚至可能没有那一天,例如,从 7 月 31 日向后退 1 个月会给你一个不正确的结果——在这种情况下,你必须一直回到 5 月 31 日。另一个例子:从 2 月 29 日开始倒退YEARLY
——你必须倒退 4 年(有时甚至 8 年)。
此外,您必须确保跳过规则中指定的间隔数。对于双周规则(例如FREQ=WEEKLY;INTERVAL=2
),您必须及时返回 2 周,否则您的结果将出现在错误的一周内。
另一个需要注意的陷阱是间隔可能是空的。要学习您的示例,您可能需要倒退几个星期才能找到匹配的日期FREQ=WEEKLY;BYDAY=FR;BYMONTHDAY=13
。您必须为此做好准备并继续倒退,直到找到一个非空的。
我不熟悉 dateutil.rrule,所以这里有一些伪代码可以引导你:
rule = … // your rule
target = … // the pivot date
dtstart = target
DO
DO
SWITCH(rule.freq)
CASE YEARLY ->
dtstart = same month, same day of month rule.interval years before old dtstart
BREAK
CASE MONTHLY:
dtstart = same day of month rule.interval months before old dtstart
BREAK
CASE WEEKLY:
dtstart = 7 * rule.interval days before old dtstart
BREAK
CASE DAILY:
dtstart = rule.interval days before old dtstart
BREAK
UNTIL dtstart is a valid date
rule.dtstart = dtstart
candidate = rule.before(target)
UNTIL candidate is a date
// candidate is your result
请注意,很可能以一种不会产生单一结果的方式指定规则。因此,如果您的代码接受用户输入,您应该为此做好准备并避免无限循环。
另一种处理继承属性的方法是在某些字段不存在时调整规则。例如,对于MONTHLY
没有您的规则,BYMONTHDAY
您可以将rule.bymonthday
其设置为目标日期的月份。但是您必须设置的字段会有所不同,FREQ
因此有其自身的缺陷。
推荐阅读
- ios - 自定尺寸单元 UICollectionViewCompositionalLayout 不适用于图像
- if-statement - if 语句:条件为真,但代码块未执行
- python - 属性错误:“str”对象没有属性“str”
- apache-spark - 如何计算组中事件之间的时间
- monitoring - 除了 Azure databricks sparkUI,我如何访问实时驱动程序日志(不延迟 5 分钟)
- python - 选择 pandas groupby 中的前 n 个项目并计算平均值
- javascript - 从窗口中删除所有侦听器
- django - 仅允许电子邮件访问徽标所在的站点(Django)
- c++ - 派生类方法中的基类参数
- android - Android ADB - 无法连接到“192.168.1.4:5037”:连接被拒绝