非常奇怪的规则集行为
Very weird rruleset behavior
使用 pip 上可用的最新 dateutil,在使用循环 DAILY
规则调用 count
方法时,我遇到了奇怪的时间和依赖于顺序的行为。
>>> import dateutil
>>> dateutil.__version__
'2.4.2'
>>> from dateutil import rrule
>>> import datetime
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # ??? Expected 0
>>> rules = rrule.rruleset()
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # ??? Expected 0
>>> rules = rrule.rruleset()
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
0
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
0 # Now its working???
>>> rules = rrule.rruleset()
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # ??? Expected 0
>>> rules = rrule.rruleset()
>>> rules.count()
0
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
0 # WHAT???
>>> rules.count()
0
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # IM DONE... WTF
答案很简单,因为您在创建规则集时没有包含 dtstart
参数,如果不包含它,则默认为 datetime.datetime.now()
,即当前时间,并且它包含直到当前微秒的组件。
因此,当您第一次使用 -
创建规则集时
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179
您从当前时间开始获取条目,最多微秒。
一段时间后,当您再次尝试时 -
rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
您再次创建一个 rrule.rrule
对象,从当前时间开始,因此它与您在 rules
.
中创建的上一个对象不同
要解决此问题,您可以指定 dtstart
属性以确保它同时启动。
例子-
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0), dtstart=datetime.datetime(now.year,now.month,now.day,0,0,0)))
>>> rules.count()
8179
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0), dtstart=datetime.datetime(now.year,now.month,now.day,0,0,0)))
>>> l3 = list(rules)
>>> len(l3)
0
>>> rules.count()
0
类似的问题出现在你的其他例子中。
鉴于以上情况,我认为 dateutil 代码中存在一个问题,当您第一次调用 count()
时,它们实际上缓存了规则集的计数(长度),然后它的正确长度仅为当你遍历它时重新计算等等
问题出现在 rrulebase
class 中,这是 ruleset
的基础 class。其中的代码是 (source - https://github.com/dateutil/dateutil/blob/master/dateutil/rrule.py) -
def count(self):
""" Returns the number of recurrences in this set. It will have go
trough the whole recurrence, if this hasn't been done before. """
if self._len is None:
for x in self:
pass
return self._len
因此,如果您之前调用过 .count()
,即使在应用 exrule()
之后,它也会继续返回相同的计数。
我不是 100% 确定它是否是一个错误,或者它是否打算表现得像那样,很可能它是一个错误。
我为此打开了 issue。
使用 pip 上可用的最新 dateutil,在使用循环 DAILY
规则调用 count
方法时,我遇到了奇怪的时间和依赖于顺序的行为。
>>> import dateutil
>>> dateutil.__version__
'2.4.2'
>>> from dateutil import rrule
>>> import datetime
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # ??? Expected 0
>>> rules = rrule.rruleset()
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # ??? Expected 0
>>> rules = rrule.rruleset()
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
0
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
0 # Now its working???
>>> rules = rrule.rruleset()
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # ??? Expected 0
>>> rules = rrule.rruleset()
>>> rules.count()
0
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
0 # WHAT???
>>> rules.count()
0
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179 # IM DONE... WTF
答案很简单,因为您在创建规则集时没有包含 dtstart
参数,如果不包含它,则默认为 datetime.datetime.now()
,即当前时间,并且它包含直到当前微秒的组件。
因此,当您第一次使用 -
创建规则集时>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
>>> rules.count()
8179
您从当前时间开始获取条目,最多微秒。
一段时间后,当您再次尝试时 -
rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0)))
您再次创建一个 rrule.rrule
对象,从当前时间开始,因此它与您在 rules
.
要解决此问题,您可以指定 dtstart
属性以确保它同时启动。
例子-
>>> rules = rrule.rruleset()
>>> rules.rrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0), dtstart=datetime.datetime(now.year,now.month,now.day,0,0,0)))
>>> rules.count()
8179
>>> rules.exrule(rrule.rrule(rrule.DAILY, until=datetime.datetime(2038,1,1,0,0,0), dtstart=datetime.datetime(now.year,now.month,now.day,0,0,0)))
>>> l3 = list(rules)
>>> len(l3)
0
>>> rules.count()
0
类似的问题出现在你的其他例子中。
鉴于以上情况,我认为 dateutil 代码中存在一个问题,当您第一次调用 count()
时,它们实际上缓存了规则集的计数(长度),然后它的正确长度仅为当你遍历它时重新计算等等
问题出现在 rrulebase
class 中,这是 ruleset
的基础 class。其中的代码是 (source - https://github.com/dateutil/dateutil/blob/master/dateutil/rrule.py) -
def count(self):
""" Returns the number of recurrences in this set. It will have go
trough the whole recurrence, if this hasn't been done before. """
if self._len is None:
for x in self:
pass
return self._len
因此,如果您之前调用过 .count()
,即使在应用 exrule()
之后,它也会继续返回相同的计数。
我不是 100% 确定它是否是一个错误,或者它是否打算表现得像那样,很可能它是一个错误。
我为此打开了 issue。