【发布时间】:2013-03-20 07:33:39
【问题描述】:
请考虑这个问题:
我有一个过去的日期,我从该日期开始添加句点。当添加这些期间导致日期大于今天时,我想停下来检查最后一个日期是什么。
这是一种计算会员借记日期的功能。一个成员加入,比如说,2007-01-31。他每个月都会被扣款。假设今天是 2013-03-29(实际上是 atm)。所以我需要从 2007 年 1 月 31 日开始计算月份,当我超过今天的日期时,我需要停止。然后我可以看到下一个借记日期是 2013-03-31。
我正在使用 dateutil 库来实现这一点,在 while 循环中添加 relativedelta,直到我超过当前日期。 (我知道这可能不是最好的方法,但我对 Python 还是很陌生,这是一个概念验证)。问题是当我在 2007-01-31 中添加一个月时,下一个日期是 2007-02-28,这是正确的。但是下一次迭代的日期是 2007-03-28,因为 dateutil 不将 28 日识别为该月的最后一天,以保持其完整并迭代到 3 月的最后一天。当然,这是一个完全有效的实现。然后我尝试了 dateutils rrule 对象,但它具有相同的原理。它输出日期列表,但它只是跳过没有足够天数的月份。
period = rrule(MONTHLY, interval=1, dtstart=datetime.date(2012, 5, 31), until=datetime.date(2013, 3, 29))
print(list(period))
然后我想到了另一种方法:
如果我可以计算 2007 年 1 月 31 日到 2013 年 3 月 29 日期间的期间数,我可以将这些期间数添加到开始日期,并且 dateutil 将返回正确的日期。
问题是这个时期并不总是一个月。例如,也可以是四个星期、一个季度或一年。
我找不到一种方法来获取一个 relativedelta 并将它与另一个 relativedelta 相除,以获得后者进入第一个的次数。
如果有人能指出我正确的方向,我将不胜感激。例如,是否有一个库可以做到这一点(相互划分时间跨度,并在给定的时间块内输出结果,如几个月或几周)?是否有一个 datediff 函数接受一个句点作为输入(我知道例如in vbscript you can get the difference between two dates in whatever period you want,无论是几周、几个月、几天,等等)。可能有完全不同的解决方案吗?
为了完整起见,我将包含代码,但我认为文本已经说明了一切:
def calculate(self, testdate=datetime.date.today()):
self._testdate = testdate
while self.next < self._testdate:
self.next += self._ddinterval
self.previous = self.next - self._ddinterval
return self.next
谢谢,
埃里克
编辑:我现在有一个解决方案,可以做它应该做的,但它几乎不是 Pythonic、优雅或快速的。所以问题仍然是一样的,如果有人能提出更好的解决方案,请这样做。这是我想出的:
def calculate(self, testdate=datetime.date.today()):
self._testdate = testdate
start = self.next
count = 0
while self.next < self._testdate:
count += 1
self.next = start + (count * self._ddinterval)
self.previous = self.next - self._ddinterval
return self.next
【问题讨论】:
-
我在使用另一个日期处理模块时遇到了类似的问题。对于以月为单位的时间段,我的解决方案只是在将间隔添加到开始日期的间隔后比较结果的月份日期,并在必要时进行调整。
-
感谢 Martineau,这会起作用,但只能持续几个月,例如,不能增加 4 周的时间。我发现了很多只添加几个月的例子。
-
IMO 添加 4 周(或固定跨度天数的任何时间)很容易。在 4 周内,您的时间总是会增加 28 天。所以即使像
old_datetime + timedelta(days=28)这样的东西也可以。对于月份和季度来说,这并不容易,因为不同的月份有不同的天数。 -
感谢您的意见,RedBaron。我考虑过做出这种区分。但是, _ddinterval 属性是一个 relativedelta 对象,我找不到在该期间检查这样一个对象的方法。 (无法确定它是否包含周、天、年或组合)。如果我可以将 relativedelta 对象转换为,说“周”,这会使事情变得容易得多。
-
我对@987654326@ 没有太多经验,因此无法对此发表评论。你怎么设置
_ddintervalBTW?