没有 dtend 作为规则参数?
No dtend as rrule parameters?
我试图用 dateutil.rrule
找到给定 datetime
之前的第一个匹配项。
尝试 1:
我的第一次尝试是:
dtstart = datetime(2010, 1, 1, 0, 00)
myRule = rrule(freq=WEEKLY, dtstart=dtstart)
result = myRule.before(dtstart)
它不起作用,变量结果将等于 None
。
如果我是对的,当您执行 rrule
的方法 before
时,您将不幸地搜索传递给参数 dtstart
的 datetime
之后。
所以基本上,我以前的代码可以表示为那种时间线:
[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
请注意,规则的指定方式很可能不会产生单一结果。因此,如果您的代码接受用户输入,您应该为此做好准备并避免无限循环。
另一种处理继承属性的方法是在某些字段不存在时调整规则。例如,对于没有 BYMONTHDAY
的 MONTHLY
规则,您可以将 rule.bymonthday
设置为目标日期的月日。但是您必须设置的字段因 FREQ
而异,因此有其自身的缺陷。
我试图用 dateutil.rrule
找到给定 datetime
之前的第一个匹配项。
尝试 1:
我的第一次尝试是:
dtstart = datetime(2010, 1, 1, 0, 00)
myRule = rrule(freq=WEEKLY, dtstart=dtstart)
result = myRule.before(dtstart)
它不起作用,变量结果将等于 None
。
如果我是对的,当您执行 rrule
的方法 before
时,您将不幸地搜索传递给参数 dtstart
的 datetime
之后。
所以基本上,我以前的代码可以表示为那种时间线:
[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
请注意,规则的指定方式很可能不会产生单一结果。因此,如果您的代码接受用户输入,您应该为此做好准备并避免无限循环。
另一种处理继承属性的方法是在某些字段不存在时调整规则。例如,对于没有 BYMONTHDAY
的 MONTHLY
规则,您可以将 rule.bymonthday
设置为目标日期的月日。但是您必须设置的字段因 FREQ
而异,因此有其自身的缺陷。