在12个月内每月开始结束日期

时间:2014-01-17 18:54:14

标签: python

这是我目前的代码

class TimeSeries():
    def year(year):
        today = datetime.now()
        start_date = today+relativedelta(years=-1)
        mint, maxt = datetime.min.time(), datetime.max.time()
        for st in rrule(MONTHLY, count=24, bymonthday=(1,-1,), dtstart=start_date):
            yield st.combine(st, mint)

这是从这个输出:

for y in TimeSeries().year():
    print(y)

2013-01-31 00:00:00
2013-02-01 00:00:00
2013-02-28 00:00:00
2013-03-01 00:00:00
2013-03-31 00:00:00
2013-04-01 00:00:00
2013-04-30 00:00:00
2013-05-01 00:00:00
2013-05-31 00:00:00
2013-06-01 00:00:00
2013-06-30 00:00:00
2013-07-01 00:00:00
2013-07-31 00:00:00
2013-08-01 00:00:00
2013-08-31 00:00:00
2013-09-01 00:00:00
2013-09-30 00:00:00
2013-10-01 00:00:00
2013-10-31 00:00:00
2013-11-01 00:00:00
2013-11-30 00:00:00
2013-12-01 00:00:00
2013-12-31 00:00:00
2014-01-01 00:00:00

问题是如何强制计数从2013-01-01 00:00:00和月末开始,如2013-01-31 23:59:59等等。 循环结束于2014-01-31 23:59:59而不是2014-01-01 00:00:00

结束

另外,我喜欢在一行上创建开始日期和结束日期:

2013-03-01 00:00:00 2013-03-31 23:59:59
2013-04-01 00:00:00 2013-03-30 23:59:59
...
...
2014-01-01 00:00:00 2014-01-31 23:59:59

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

首先,您确定要2013-03-31 23:59:59吗?传统上,日期间隔被指定为半开间隔 - 就像Python中的范围一样。原因是23:59:59实际上不是一天的结束。

最明显的是,23:59:59.001晚于此,但在同一天。 Python datetime对象包括微秒,所以这不仅仅是一个“meh,无论如何”的问题 - 如果你,例如,调用now(),你可以得到一个错误的时间晚于你的“结束“在同一天。

不太明显,在leap second的某一天,23:59:60也会在同一天发布。


但如果你真的想要这个,那么有两种明显的方法可以实现它:


您已经在迭代日期而不是日期时间并手动组合时间。当你处理第1天与第-1天时,这是显而易见的,因为约会的day成员将是1或者不是。{1}}成员。所以:

class TimeSeries():
    def year(year):
        today = datetime.now()
        start_date = today+relativedelta(years=-1)
        mint, maxt = datetime.min.time(), datetime.max.time()
        for st in rrule(MONTHLY, count=24, bymonthday=(1, -1,), dtstart=start_date):
            yield st.combine(st, mint if st.day=1 else maxt)

或者,不是迭代第一天和最后几天,只是迭代第一天,然后减去第二天以获得上个月的最后一秒:

class TimeSeries():
    def year(year):
        today = datetime.now()
        start_date = today+relativedelta(years=-1)
        mint, maxt = datetime.min.time(), datetime.max.time()
        for st in rrule(MONTHLY, count=24, bymonthday=(1,), dtstart=start_date):                
            dt = st.combine(st, mint)
            yield dt - timedelta(seconds=1)
            yield dt

至于成对打印这些......好吧,正如所写的那样,这是一个不明确的问题。列表中的第一个值是一对中的第二个值 - 除非您在一个月的第一天运行它。同样,最后一个日期是一对中的第一个值,除非你在31日运行它。那么,你想用它们做什么?

如果这不明显,请查看您的示例。您的第一个值为2013-01-31 00:00:00,但您的第一对价格不是从2013-01-31开始的。

  • 从一年前的第一个月开始,而不是去年发生的第一个月或者最后一个月。同样为了结束。因此,您的列表中会有2013-01-01,并且总会有对。
  • 从去年开始的第一个月开始,同样结束。所以你不会在你的列表中得到2013-01-31,并且总会有对。
  • 使用您当前的规则,并且没有一对,请使用None作为缺失值。

无论你真正想要什么规则都可以轻松编码。然后你可能想要{开始,结束)元组yield,所以print循环可以这样做:

for start, end in TimeSeries().year():
    print(start, end)