【问题标题】:Very weird rruleset behavior非常奇怪的规则集行为
【发布时间】:2015-08-12 06:00:10
【问题描述】:

使用 pip 上可用的最新 dateutil,在使用重复出现的 DAILY rrule 调用 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

【问题讨论】:

    标签: python python-dateutil rrule


    【解决方案1】:

    答案很简单,因为您在创建规则集时没有包含 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 类中,它是ruleset 的基类。代码是(来源-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
    

    因此,即使在应用 exrule() 之后,如果您之前曾调用过 .count(),它仍会返回相同的计数。

    我不能 100% 确定它是否是一个错误,或者它是否打算这样做,很可能它是一个错误。

    我为此打开了issue

    【讨论】:

    • 太棒了。因此,exrule 不适用,因为它适用于我制定原始规则后的微秒时间。非常感谢!
    • 仅供参考,如果你想知道,我打开了问题 - github.com/dateutil/dateutil/issues/104 - 我说的第二个问题。
    猜你喜欢
    • 1970-01-01
    • 2016-03-13
    • 2011-03-01
    • 2017-09-05
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 2020-02-09
    相关资源
    最近更新 更多