没有数据终端作为rrule参数?

2024-05-29 06:03:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用dateutil.rrule找到给定datetime之前的第一个匹配项

尝试1:

我的第一次尝试是:

dtstart = datetime(2010, 1, 1, 0, 00)
myRule = rrule(freq=WEEKLY, dtstart=dt)
result = myRule.before(dt)

它不起作用,变量结果将等于None

如果我是对的,当您执行rrule的方法before时,您将不幸地在传递给参数dtstartdatetime之后进行搜索。 基本上,我之前的代码可以表示为这样的时间线:

[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或rruleset,那么很难定义最佳移位

最好的解决方案,但实际上并不存在……:'(:

如果rrule可以使用dtend而不是dtstart,那就太完美了。我可以这样做:

dtstart = datetime(2010, 1, 1, 0, 00)
myRule = rrule(freq=WEEKLY, dtend=dt)
result = muRule.before(dt)

问题:

如果没有任何简单的功能,我会感到奇怪。有什么优雅的方法可以达到我的目标吗?我的尝试2是最好的解决方案吗

换句话说(同样有问题,但作为练习):

你如何找到2月13日的最后一个星期五(基于今天)


Tags: target目标datetimemydtresult解决方案freq
1条回答
网友
1楼 · 发布于 2024-05-29 06:03:41

假设dateutils.rrule不提供开箱即用的功能,我认为您自己的解决方案很接近,但还没有完全实现。您需要在正确的时间间隔内倒退,并计算目标日期之前的最后结果。如果没有完全指定规则,并且结果继承了原始日期的某些属性,则“正确间隔”很重要

例如,如果您的规则是MONTHLY,那么您必须确保您在本月的同一天或上一个月结束。这很棘手,因为前一个月甚至可能没有这一天,例如,从7月31日开始倒退1个月会给你一个错误的结果——在这种情况下,你必须一直追溯到5月31日。另一个例子:从2月29日开始,按照YEARLY规则向后走——你必须向后走4年(有时甚至8年)

此外,您必须确保跳过规则中指定的间隔数。对于每两周一次的规则(例如FREQ=WEEKLY;INTERVAL=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

请注意,规则的指定方式很可能不会产生单一结果。所以,如果您的代码接受用户输入,您应该为此做好准备,并避免无限循环

处理继承属性的另一种方法是,如果某些字段不存在,则调整规则。例如,对于不带BYMONTHDAYMONTHLY规则,可以将rule.bymonthday设置为目标日期的monthday。但是您必须设置的字段因FREQ而异,因此这有其自身的缺陷

相关问题 更多 >

    热门问题